diff options
Diffstat (limited to 'builtin-send-pack.c')
-rw-r--r-- | builtin-send-pack.c | 257 |
1 files changed, 56 insertions, 201 deletions
diff --git a/builtin-send-pack.c b/builtin-send-pack.c index 76c72065de..6019eac918 100644 --- a/builtin-send-pack.c +++ b/builtin-send-pack.c @@ -7,6 +7,7 @@ #include "remote.h" #include "send-pack.h" #include "quote.h" +#include "transport.h" static const char send_pack_usage[] = "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n" @@ -169,156 +170,6 @@ static int receive_status(int in, struct ref *refs) return ret; } -static void update_tracking_ref(struct remote *remote, struct ref *ref) -{ - struct refspec rs; - - if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) - return; - - rs.src = ref->name; - rs.dst = NULL; - - if (!remote_find_tracking(remote, &rs)) { - if (args.verbose) - fprintf(stderr, "updating local tracking ref '%s'\n", rs.dst); - if (ref->deletion) { - delete_ref(rs.dst, NULL, 0); - } else - update_ref("update by push", rs.dst, - ref->new_sha1, NULL, 0, 0); - free(rs.dst); - } -} - -#define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) - -static void print_ref_status(char flag, const char *summary, struct ref *to, struct ref *from, const char *msg) -{ - fprintf(stderr, " %c %-*s ", flag, SUMMARY_WIDTH, summary); - if (from) - fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name)); - else - fputs(prettify_refname(to->name), stderr); - if (msg) { - fputs(" (", stderr); - fputs(msg, stderr); - fputc(')', stderr); - } - fputc('\n', stderr); -} - -static const char *status_abbrev(unsigned char sha1[20]) -{ - return find_unique_abbrev(sha1, DEFAULT_ABBREV); -} - -static void print_ok_ref_status(struct ref *ref) -{ - if (ref->deletion) - print_ref_status('-', "[deleted]", ref, NULL, NULL); - else if (is_null_sha1(ref->old_sha1)) - print_ref_status('*', - (!prefixcmp(ref->name, "refs/tags/") ? "[new tag]" : - "[new branch]"), - ref, ref->peer_ref, NULL); - else { - char quickref[84]; - char type; - const char *msg; - - strcpy(quickref, status_abbrev(ref->old_sha1)); - if (ref->nonfastforward) { - strcat(quickref, "..."); - type = '+'; - msg = "forced update"; - } else { - strcat(quickref, ".."); - type = ' '; - msg = NULL; - } - strcat(quickref, status_abbrev(ref->new_sha1)); - - print_ref_status(type, quickref, ref, ref->peer_ref, msg); - } -} - -static int print_one_push_status(struct ref *ref, const char *dest, int count) -{ - if (!count) - fprintf(stderr, "To %s\n", dest); - - switch(ref->status) { - case REF_STATUS_NONE: - print_ref_status('X', "[no match]", ref, NULL, NULL); - break; - case REF_STATUS_REJECT_NODELETE: - print_ref_status('!', "[rejected]", ref, NULL, - "remote does not support deleting refs"); - break; - case REF_STATUS_UPTODATE: - print_ref_status('=', "[up to date]", ref, - ref->peer_ref, NULL); - break; - case REF_STATUS_REJECT_NONFASTFORWARD: - print_ref_status('!', "[rejected]", ref, ref->peer_ref, - "non-fast-forward"); - break; - case REF_STATUS_REMOTE_REJECT: - 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); - break; - } - - return 1; -} - -static void print_push_status(const char *dest, struct ref *refs) -{ - struct ref *ref; - int n = 0; - - if (args.verbose) { - for (ref = refs; ref; ref = ref->next) - if (ref->status == REF_STATUS_UPTODATE) - n += print_one_push_status(ref, dest, n); - } - - for (ref = refs; ref; ref = ref->next) - if (ref->status == REF_STATUS_OK) - n += print_one_push_status(ref, dest, n); - - for (ref = refs; ref; ref = ref->next) { - if (ref->status != REF_STATUS_NONE && - ref->status != REF_STATUS_UPTODATE && - ref->status != REF_STATUS_OK) - n += print_one_push_status(ref, dest, n); - } -} - -static int refs_pushed(struct ref *ref) -{ - for (; ref; ref = ref->next) { - switch(ref->status) { - case REF_STATUS_NONE: - case REF_STATUS_UPTODATE: - break; - default: - return 1; - } - } - return 0; -} - static void print_helper_status(struct ref *ref) { struct strbuf buf = STRBUF_INIT; @@ -372,6 +223,14 @@ static void print_helper_status(struct ref *ref) strbuf_release(&buf); } +static int sideband_demux(int in, int out, void *data) +{ + int *fd = data; + int ret = recv_sideband("send-pack", fd[0], out); + close(out); + return ret; +} + int send_pack(struct send_pack_args *args, int fd[], struct child_process *conn, struct ref *remote_refs, @@ -382,18 +241,22 @@ int send_pack(struct send_pack_args *args, struct strbuf req_buf = STRBUF_INIT; struct ref *ref; int new_refs; - int ask_for_status_report = 0; int allow_deleting_refs = 0; - int expect_status_report = 0; + int status_report = 0; + int use_sideband = 0; + unsigned cmds_sent = 0; int ret; + struct async demux; /* Does the other end support the reporting? */ if (server_supports("report-status")) - ask_for_status_report = 1; + status_report = 1; if (server_supports("delete-refs")) allow_deleting_refs = 1; if (server_supports("ofs-delta")) args->use_ofs_delta = 1; + if (server_supports("side-band-64k")) + use_sideband = 1; if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" @@ -426,28 +289,30 @@ int send_pack(struct send_pack_args *args, if (!ref->deletion) new_refs++; - if (!args->dry_run) { + if (args->dry_run) { + ref->status = REF_STATUS_OK; + } else { char *old_hex = sha1_to_hex(ref->old_sha1); char *new_hex = sha1_to_hex(ref->new_sha1); - if (ask_for_status_report) { - packet_buf_write(&req_buf, "%s %s %s%c%s", + if (!cmds_sent && (status_report || use_sideband)) { + packet_buf_write(&req_buf, "%s %s %s%c%s%s", old_hex, new_hex, ref->name, 0, - "report-status"); - ask_for_status_report = 0; - expect_status_report = 1; + status_report ? " report-status" : "", + use_sideband ? " side-band-64k" : ""); } else packet_buf_write(&req_buf, "%s %s %s", old_hex, new_hex, ref->name); + ref->status = status_report ? + REF_STATUS_EXPECTING_REPORT : + REF_STATUS_OK; + cmds_sent++; } - ref->status = expect_status_report ? - REF_STATUS_EXPECTING_REPORT : - REF_STATUS_OK; } if (args->stateless_rpc) { - if (!args->dry_run) { + if (!args->dry_run && cmds_sent) { packet_buf_flush(&req_buf); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); } @@ -457,23 +322,43 @@ int send_pack(struct send_pack_args *args, } strbuf_release(&req_buf); - if (new_refs && !args->dry_run) { + if (use_sideband && cmds_sent) { + memset(&demux, 0, sizeof(demux)); + demux.proc = sideband_demux; + demux.data = fd; + demux.out = -1; + if (start_async(&demux)) + die("receive-pack: unable to fork off sideband demultiplexer"); + in = demux.out; + } + + if (new_refs && cmds_sent) { if (pack_objects(out, remote_refs, extra_have, args) < 0) { for (ref = remote_refs; ref; ref = ref->next) ref->status = REF_STATUS_NONE; + if (use_sideband) + finish_async(&demux); return -1; } } - if (args->stateless_rpc && !args->dry_run) + if (args->stateless_rpc && cmds_sent) packet_flush(out); - if (expect_status_report) + if (status_report && cmds_sent) ret = receive_status(in, remote_refs); else ret = 0; if (args->stateless_rpc) packet_flush(out); + if (use_sideband && cmds_sent) { + if (finish_async(&demux)) { + error("error in sideband demultiplexer"); + ret = -1; + } + close(demux.out); + } + if (ret < 0) return ret; for (ref = remote_refs; ref; ref = ref->next) { @@ -489,37 +374,6 @@ int send_pack(struct send_pack_args *args, return 0; } -static void verify_remote_names(int nr_heads, const char **heads) -{ - int i; - - for (i = 0; i < nr_heads; i++) { - const char *local = heads[i]; - const char *remote = strrchr(heads[i], ':'); - - if (*local == '+') - local++; - - /* A matching refspec is okay. */ - if (remote == local && remote[1] == '\0') - continue; - - remote = remote ? (remote + 1) : local; - switch (check_ref_format(remote)) { - case 0: /* ok */ - case CHECK_REF_FORMAT_ONELEVEL: - /* ok but a single level -- that is fine for - * a match pattern. - */ - case CHECK_REF_FORMAT_WILDCARD: - /* ok but ends with a pattern-match character */ - continue; - } - die("remote part of refspec is not a valid name in %s", - heads[i]); - } -} - int cmd_send_pack(int argc, const char **argv, const char *prefix) { int i, nr_refspecs = 0; @@ -536,6 +390,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) int send_all = 0; const char *receivepack = "git-receive-pack"; int flags; + int nonfastforward = 0; argv++; for (i = 1; i < argc; i++, argv++) { @@ -628,7 +483,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) get_remote_heads(fd[0], &remote_refs, 0, NULL, REF_NORMAL, &extra_have); - verify_remote_names(nr_refspecs, refspecs); + transport_verify_remote_names(nr_refspecs, refspecs); local_refs = get_local_heads(); @@ -657,15 +512,15 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix) ret |= finish_connect(conn); if (!helper_status) - print_push_status(dest, remote_refs); + transport_print_push_status(dest, remote_refs, args.verbose, 0, &nonfastforward); if (!args.dry_run && remote) { struct ref *ref; for (ref = remote_refs; ref; ref = ref->next) - update_tracking_ref(remote, ref); + transport_update_tracking_ref(remote, ref, args.verbose); } - if (!ret && !refs_pushed(remote_refs)) + if (!ret && !transport_refs_pushed(remote_refs)) fprintf(stderr, "Everything up-to-date\n"); return ret; |