summaryrefslogtreecommitdiff
path: root/send-pack.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-12-25 23:18:37 -0800
committerJunio C Hamano <junkio@cox.net>2005-12-27 18:04:14 -0800
commitcfee10a773be0f8d0024f2567164c910d4213244 (patch)
tree7f8562e817c43a9b614d3cc1628e8321a2e63b09 /send-pack.c
parent9b88fcef7dd6327cc3aba3927e56fef6f6c4d628 (diff)
downloadgit-cfee10a773be0f8d0024f2567164c910d4213244.tar.gz
send-pack/receive-pack: allow errors to be reported back to pusher.
This updates the protocol between git-send-pack/git-receive-pack in a backward compatible way to allow failures at the receiving end to be propagated back to the sender. Most notably, versions of git-push before this could not notice if the update hook on the receiving end refused to update the ref for its own policy reasons. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'send-pack.c')
-rw-r--r--send-pack.c59
1 files changed, 56 insertions, 3 deletions
diff --git a/send-pack.c b/send-pack.c
index 0d41f9a178..cd36193444 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -176,16 +176,53 @@ static void get_local_heads(void)
for_each_ref(one_local_ref);
}
+static int receive_status(int in)
+{
+ 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 -1;
+ }
+ if (memcmp(line, "unpack ok\n", 10)) {
+ fputs(line, stderr);
+ ret = -1;
+ }
+ while (1) {
+ len = packet_read_line(in, line, sizeof(line));
+ if (!len)
+ break;
+ if (len < 3 ||
+ (memcmp(line, "ok", 2) && memcmp(line, "ng", 2))) {
+ fprintf(stderr, "protocol error: %s\n", line);
+ ret = -1;
+ break;
+ }
+ if (!memcmp(line, "ok", 2))
+ continue;
+ fputs(line, stderr);
+ ret = -1;
+ }
+ return ret;
+}
+
static int send_pack(int in, int out, int nr_refspec, char **refspec)
{
struct ref *ref;
int new_refs;
int ret = 0;
+ int ask_for_status_report = 0;
+ int expect_status_report = 0;
/* No funny business with the matcher */
remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1);
get_local_heads();
+ /* Does the other end support the reporting? */
+ if (server_supports("report-status"))
+ ask_for_status_report = 1;
+
/* match them up */
if (!remote_tail)
remote_tail = &remote_refs;
@@ -260,7 +297,17 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
new_refs++;
strcpy(old_hex, sha1_to_hex(ref->old_sha1));
new_hex = sha1_to_hex(ref->new_sha1);
- packet_write(out, "%s %s %s", old_hex, new_hex, ref->name);
+
+ if (ask_for_status_report) {
+ packet_write(out, "%s %s %s%c%s",
+ old_hex, new_hex, ref->name, 0,
+ "report-status");
+ ask_for_status_report = 0;
+ expect_status_report = 1;
+ }
+ else
+ packet_write(out, "%s %s %s",
+ old_hex, new_hex, ref->name);
fprintf(stderr, "updating '%s'", ref->name);
if (strcmp(ref->name, ref->peer_ref->name))
fprintf(stderr, " using '%s'", ref->peer_ref->name);
@@ -270,9 +317,15 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
packet_flush(out);
if (new_refs)
pack_objects(out, remote_refs);
- else if (ret == 0)
- fprintf(stderr, "Everything up-to-date\n");
close(out);
+
+ if (expect_status_report) {
+ if (receive_status(in))
+ ret = -4;
+ }
+
+ if (!new_refs && ret == 0)
+ fprintf(stderr, "Everything up-to-date\n");
return ret;
}