diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 1724b76052..85aff029b2 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -15,6 +15,7 @@ static int transfer_unpack_limit = -1; static int fetch_unpack_limit = -1; static int unpack_limit = 100; static int prefer_ofs_delta = 1; +static int no_done = 0; static struct fetch_pack_args args = { /* .uploadpack = */ "git-upload-pack", }; @@ -229,16 +230,17 @@ static void insert_alternate_refs(void) } #define INITIAL_FLUSH 16 +#define PIPESAFE_FLUSH 32 #define LARGE_FLUSH 1024 static int next_flush(int count) { - if (count < INITIAL_FLUSH * 2) - count += INITIAL_FLUSH; - else if (count < LARGE_FLUSH) + int flush_limit = args.stateless_rpc ? LARGE_FLUSH : PIPESAFE_FLUSH; + + if (count < flush_limit) count <<= 1; else - count += LARGE_FLUSH; + count += flush_limit; return count; } @@ -250,6 +252,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, const unsigned char *sha1; unsigned in_vain = 0; int got_continue = 0; + int got_ready = 0; struct strbuf req_buf = STRBUF_INIT; size_t state_len = 0; @@ -288,6 +291,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, struct strbuf c = STRBUF_INIT; if (multi_ack == 2) strbuf_addstr(&c, " multi_ack_detailed"); if (multi_ack == 1) strbuf_addstr(&c, " multi_ack"); + if (no_done) strbuf_addstr(&c, " no-done"); if (use_sideband == 2) strbuf_addstr(&c, " side-band-64k"); if (use_sideband == 1) strbuf_addstr(&c, " side-band"); if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack"); @@ -406,8 +410,10 @@ static int find_common(int fd[2], unsigned char *result_sha1, retval = 0; in_vain = 0; got_continue = 1; - if (ack == ACK_ready) + if (ack == ACK_ready) { rev_list = NULL; + got_ready = 1; + } break; } } @@ -421,8 +427,10 @@ static int find_common(int fd[2], unsigned char *result_sha1, } } done: - packet_buf_write(&req_buf, "done\n"); - send_request(fd[1], &req_buf); + if (!got_ready || !no_done) { + packet_buf_write(&req_buf, "done\n"); + send_request(fd[1], &req_buf); + } if (args.verbose) fprintf(stderr, "done\n"); if (retval != 0) { @@ -725,6 +733,12 @@ static struct ref *do_fetch_pack(int fd[2], if (args.verbose) fprintf(stderr, "Server supports multi_ack_detailed\n"); multi_ack = 2; + if (server_supports("no-done")) { + if (args.verbose) + fprintf(stderr, "Server supports no-done\n"); + if (args.stateless_rpc) + no_done = 1; + } } else if (server_supports("multi_ack")) { if (args.verbose) diff --git a/t/test-lib.sh b/t/test-lib.sh index 7a56f11101..abc47f3abc 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -993,14 +993,14 @@ rm -fr "$test" || { exit 1 } +HOME="$TRASH_DIRECTORY" +export HOME + test_create_repo "$test" # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || exit 1 -HOME=$(pwd) -export HOME - this_test=${0##*/} this_test=${this_test%%-*} for skp in $GIT_SKIP_TESTS diff --git a/upload-pack.c b/upload-pack.c index eb80dd9aad..bba053f0aa 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=< static unsigned long oldest_have; static int multi_ack, nr_our_refs; +static int no_done; static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; static int shallow_nr; @@ -431,6 +432,7 @@ static int get_common_commits(void) char last_hex[41]; int got_common = 0; int got_other = 0; + int sent_ready = 0; save_commit_buffer = 0; @@ -440,10 +442,17 @@ static int get_common_commits(void) if (!len) { if (multi_ack == 2 && got_common - && !got_other && ok_to_give_up()) + && !got_other && ok_to_give_up()) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", last_hex); + } if (have_obj.nr == 0 || multi_ack) packet_write(1, "NAK\n"); + + if (no_done && sent_ready) { + packet_write(1, "ACK %s\n", last_hex); + return 0; + } if (stateless_rpc) exit(0); got_common = 0; @@ -457,9 +466,10 @@ static int get_common_commits(void) got_other = 1; if (multi_ack && ok_to_give_up()) { const char *hex = sha1_to_hex(sha1); - if (multi_ack == 2) + if (multi_ack == 2) { + sent_ready = 1; packet_write(1, "ACK %s ready\n", hex); - else + } else packet_write(1, "ACK %s continue\n", hex); } break; @@ -535,6 +545,8 @@ static void receive_needs(void) multi_ack = 2; else if (strstr(line+45, "multi_ack")) multi_ack = 1; + if (strstr(line+45, "no-done")) + no_done = 1; if (strstr(line+45, "thin-pack")) use_thin_pack = 1; if (strstr(line+45, "ofs-delta")) @@ -635,8 +647,9 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); if (capabilities) - packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, - 0, capabilities); + packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname, + 0, capabilities, + stateless_rpc ? " no-done" : ""); else packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname); capabilities = NULL;