aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin-send-pack.c94
-rw-r--r--cache.h3
2 files changed, 54 insertions, 43 deletions
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 5fadd0bc9..14447bb7c 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -146,60 +146,67 @@ static void get_local_heads(void)
for_each_ref(one_local_ref, NULL);
}
-static struct ref *set_ref_error(struct ref *refs, const char *line)
-{
- struct ref *ref;
-
- for (ref = refs; ref; ref = ref->next) {
- const char *msg;
- if (prefixcmp(line, ref->name))
- continue;
- msg = line + strlen(ref->name);
- if (*msg++ != ' ')
- continue;
- ref->status = REF_STATUS_REMOTE_REJECT;
- ref->error = xstrdup(msg);
- ref->error[strlen(ref->error)-1] = '\0';
- return ref;
- }
- return NULL;
-}
-
-/* a return value of -1 indicates that an error occurred,
- * but we were able to set individual ref errors. A return
- * value of -2 means we couldn't even get that far. */
static int receive_status(int in, struct ref *refs)
{
struct ref *hint;
char line[1000];
int ret = 0;
int len = packet_read_line(in, line, sizeof(line));
- if (len < 10 || memcmp(line, "unpack ", 7)) {
- fprintf(stderr, "did not receive status back\n");
- return -2;
- }
+ if (len < 10 || memcmp(line, "unpack ", 7))
+ return error("did not receive remote status");
if (memcmp(line, "unpack ok\n", 10)) {
- fputs(line, stderr);
+ char *p = line + strlen(line) - 1;
+ if (*p == '\n')
+ *p = '\0';
+ error("unpack failed: %s", line + 7);
ret = -1;
}
hint = NULL;
while (1) {
+ char *refname;
+ char *msg;
len = packet_read_line(in, line, sizeof(line));
if (!len)
break;
if (len < 3 ||
- (memcmp(line, "ok", 2) && memcmp(line, "ng", 2))) {
+ (memcmp(line, "ok ", 3) && memcmp(line, "ng ", 3))) {
fprintf(stderr, "protocol error: %s\n", line);
ret = -1;
break;
}
- if (!memcmp(line, "ok", 2))
- continue;
+
+ line[strlen(line)-1] = '\0';
+ refname = line + 3;
+ msg = strchr(refname, ' ');
+ if (msg)
+ *msg++ = '\0';
+
+ /* first try searching at our hint, falling back to all refs */
if (hint)
- hint = set_ref_error(hint, line + 3);
+ hint = find_ref_by_name(hint, refname);
if (!hint)
- hint = set_ref_error(refs, line + 3);
- ret = -1;
+ hint = find_ref_by_name(refs, refname);
+ if (!hint) {
+ warning("remote reported status on unknown ref: %s",
+ refname);
+ continue;
+ }
+ if (hint->status != REF_STATUS_EXPECTING_REPORT) {
+ warning("remote reported status on unexpected ref: %s",
+ refname);
+ continue;
+ }
+
+ if (line[0] == 'o' && line[1] == 'k')
+ hint->status = REF_STATUS_OK;
+ else {
+ hint->status = REF_STATUS_REMOTE_REJECT;
+ ret = -1;
+ }
+ if (msg)
+ hint->remote_status = xstrdup(msg);
+ /* start our next search from the next ref */
+ hint = hint->next;
}
return ret;
}
@@ -324,10 +331,14 @@ static void print_push_status(const char *dest, struct ref *refs)
"non-fast forward");
break;
case REF_STATUS_REMOTE_REJECT:
- if (ref->deletion)
- print_ref_status('!', "[remote rejected]", ref, NULL, ref->error);
- else
- print_ref_status('!', "[remote rejected]", ref, ref->peer_ref, ref->error);
+ print_ref_status('!', "[remote rejected]", ref,
+ ref->deletion ? NULL : ref->peer_ref,
+ ref->remote_status);
+ break;
+ case REF_STATUS_EXPECTING_REPORT:
+ print_ref_status('!', "[remote failure]", ref,
+ ref->deletion ? NULL : ref->peer_ref,
+ "remote failed to report status");
break;
case REF_STATUS_OK:
print_ok_ref_status(ref);
@@ -434,7 +445,6 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
hashcpy(ref->new_sha1, new_sha1);
if (!ref->deletion)
new_refs++;
- ref->status = REF_STATUS_OK;
if (!args.dry_run) {
char *old_hex = sha1_to_hex(ref->old_sha1);
@@ -451,6 +461,9 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
packet_write(out, "%s %s %s",
old_hex, new_hex, ref->name);
}
+ ref->status = expect_status_report ?
+ REF_STATUS_EXPECTING_REPORT :
+ REF_STATUS_OK;
}
packet_flush(out);
@@ -462,11 +475,8 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest
}
close(out);
- if (expect_status_report) {
+ if (expect_status_report)
ret = receive_status(in, remote_refs);
- if (ret == -2)
- return -1;
- }
else
ret = 0;
diff --git a/cache.h b/cache.h
index 8d601dd6f..e0c1cc3fe 100644
--- a/cache.h
+++ b/cache.h
@@ -504,8 +504,9 @@ struct ref {
REF_STATUS_REJECT_NODELETE,
REF_STATUS_UPTODATE,
REF_STATUS_REMOTE_REJECT,
+ REF_STATUS_EXPECTING_REPORT,
} status;
- char *error;
+ char *remote_status;
struct ref *peer_ref; /* when renaming */
char name[FLEX_ARRAY]; /* more */
};