diff options
-rw-r--r-- | Documentation/config.txt | 6 | ||||
-rw-r--r-- | Documentation/technical/http-protocol.txt | 3 | ||||
-rw-r--r-- | Documentation/technical/protocol-capabilities.txt | 7 | ||||
-rw-r--r-- | fetch-pack.c | 10 | ||||
-rwxr-xr-x | t/t5516-fetch-push.sh | 55 | ||||
-rw-r--r-- | upload-pack.c | 22 |
6 files changed, 97 insertions, 6 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt index 2b86fe6aa5..980520b655 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -2538,6 +2538,12 @@ uploadpack.allowTipSHA1InWant:: of a hidden ref (by default, such a request is rejected). see also `uploadpack.hideRefs`. +uploadpack.allowReachableSHA1InWant:: + Allow `upload-pack` to accept a fetch request that asks for an + object that is reachable from any ref tip. However, note that + calculating object reachability is computationally expensive. + Defaults to `false`. + uploadpack.keepAlive:: When `upload-pack` has started `pack-objects`, there may be a quiet period while `pack-objects` prepares the pack. Normally diff --git a/Documentation/technical/http-protocol.txt b/Documentation/technical/http-protocol.txt index 229f845dfa..1c561bdd92 100644 --- a/Documentation/technical/http-protocol.txt +++ b/Documentation/technical/http-protocol.txt @@ -319,7 +319,8 @@ Servers SHOULD support all capabilities defined here. Clients MUST send at least one "want" command in the request body. Clients MUST NOT reference an id in a "want" command which did not appear in the response obtained through ref discovery unless the -server advertises capability `allow-tip-sha1-in-want`. +server advertises capability `allow-tip-sha1-in-want` or +`allow-reachable-sha1-in-want`. compute_request = want_list have_list diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt index 4f8a7bfb4c..eaab6b4ac7 100644 --- a/Documentation/technical/protocol-capabilities.txt +++ b/Documentation/technical/protocol-capabilities.txt @@ -260,6 +260,13 @@ If the upload-pack server advertises this capability, fetch-pack may send "want" lines with SHA-1s that exist at the server but are not advertised by upload-pack. +allow-reachable-sha1-in-want +---------------------------- + +If the upload-pack server advertises this capability, fetch-pack may +send "want" lines with SHA-1s that exist at the server but are not +advertised by upload-pack. + push-cert=<nonce> ----------------- diff --git a/fetch-pack.c b/fetch-pack.c index ff5bd5c48b..ff8a13b8c4 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -46,6 +46,8 @@ static struct prio_queue rev_list = { compare_commits_by_commit_date }; static int non_common_revs, multi_ack, use_sideband; /* Allow specifying sha1 if it is a ref tip. */ #define ALLOW_TIP_SHA1 01 +/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */ +#define ALLOW_REACHABLE_SHA1 02 static unsigned int allow_unadvertised_object_request; static void rev_list_push(struct commit *commit, int mark) @@ -545,7 +547,8 @@ static void filter_refs(struct fetch_pack_args *args, } /* Append unmatched requests to the list */ - if ((allow_unadvertised_object_request & ALLOW_TIP_SHA1)) { + if ((allow_unadvertised_object_request & + (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) { for (i = 0; i < nr_sought; i++) { unsigned char sha1[20]; @@ -826,6 +829,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, fprintf(stderr, "Server supports allow-tip-sha1-in-want\n"); allow_unadvertised_object_request |= ALLOW_TIP_SHA1; } + if (server_supports("allow-reachable-sha1-in-want")) { + if (args->verbose) + fprintf(stderr, "Server supports allow-reachable-sha1-in-want\n"); + allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1; + } if (!server_supports("thin-pack")) args->use_thin_pack = 0; if (!server_supports("no-progress")) diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 8a5f2363a9..ec22c98445 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -1120,6 +1120,61 @@ test_expect_success 'fetch exact SHA1' ' ) ' +for configallowtipsha1inwant in true false +do + test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" ' + mk_empty testrepo && + ( + cd testrepo && + git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant && + git commit --allow-empty -m foo && + git commit --allow-empty -m bar + ) && + SHA1=$(git --git-dir=testrepo/.git rev-parse HEAD^) && + mk_empty shallow && + ( + cd shallow && + test_must_fail git fetch --depth=1 ../testrepo/.git $SHA1 && + git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && + git fetch --depth=1 ../testrepo/.git $SHA1 && + git cat-file commit $SHA1 + ) + ' + + test_expect_success "deny fetch unreachable SHA1, allowtipsha1inwant=$configallowtipsha1inwant" ' + mk_empty testrepo && + ( + cd testrepo && + git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant && + git commit --allow-empty -m foo && + git commit --allow-empty -m bar && + git commit --allow-empty -m xyz + ) && + SHA1_1=$(git --git-dir=testrepo/.git rev-parse HEAD^^) && + SHA1_2=$(git --git-dir=testrepo/.git rev-parse HEAD^) && + SHA1_3=$(git --git-dir=testrepo/.git rev-parse HEAD) && + ( + cd testrepo && + git reset --hard $SHA1_2 && + git cat-file commit $SHA1_1 && + git cat-file commit $SHA1_3 + ) && + mk_empty shallow && + ( + cd shallow && + test_must_fail git fetch ../testrepo/.git $SHA1_3 && + test_must_fail git fetch ../testrepo/.git $SHA1_1 && + git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true && + git fetch ../testrepo/.git $SHA1_1 && + git cat-file commit $SHA1_1 && + test_must_fail git cat-file commit $SHA1_2 && + git fetch ../testrepo/.git $SHA1_2 && + git cat-file commit $SHA1_2 && + test_must_fail git fetch ../testrepo/.git $SHA1_3 + ) + ' +done + test_expect_success 'fetch follows tags by default' ' mk_test testrepo heads/master && rm -fr src dst && diff --git a/upload-pack.c b/upload-pack.c index be8c724a45..5cb4ac4ccc 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -37,6 +37,8 @@ static int use_thin_pack, use_ofs_delta, use_include_tag; static int no_progress, daemon_mode; /* Allow specifying sha1 if it is a ref tip. */ #define ALLOW_TIP_SHA1 01 +/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */ +#define ALLOW_REACHABLE_SHA1 02 static unsigned int allow_unadvertised_object_request; static int shallow_nr; static struct object_array have_obj; @@ -444,7 +446,8 @@ static int get_common_commits(void) static int is_our_ref(struct object *o) { - int allow_hidden_ref = (allow_unadvertised_object_request & ALLOW_TIP_SHA1); + int allow_hidden_ref = (allow_unadvertised_object_request & + (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)); return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF); } @@ -458,8 +461,12 @@ static void check_non_tip(void) char namebuf[42]; /* ^ + SHA-1 + LF */ int i; - /* In the normal in-process case non-tip request can never happen */ - if (!stateless_rpc) + /* + * In the normal in-process case without + * uploadpack.allowReachableSHA1InWant, + * non-tip requests can never happen. + */ + if (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1)) goto error; cmd.argv = argv; @@ -726,11 +733,13 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo struct strbuf symref_info = STRBUF_INIT; format_symref_info(&symref_info, cb_data); - packet_write(1, "%s %s%c%s%s%s%s agent=%s\n", + packet_write(1, "%s %s%c%s%s%s%s%s agent=%s\n", sha1_to_hex(sha1), refname_nons, 0, capabilities, (allow_unadvertised_object_request & ALLOW_TIP_SHA1) ? " allow-tip-sha1-in-want" : "", + (allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1) ? + " allow-reachable-sha1-in-want" : "", stateless_rpc ? " no-done" : "", symref_info.buf, git_user_agent_sanitized()); @@ -795,6 +804,11 @@ static int upload_pack_config(const char *var, const char *value, void *unused) allow_unadvertised_object_request |= ALLOW_TIP_SHA1; else allow_unadvertised_object_request &= ~ALLOW_TIP_SHA1; + } else if (!strcmp("uploadpack.allowreachablesha1inwant", var)) { + if (git_config_bool(var, value)) + allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1; + else + allow_unadvertised_object_request &= ~ALLOW_REACHABLE_SHA1; } else if (!strcmp("uploadpack.keepalive", var)) { keepalive = git_config_int(var, value); if (!keepalive) |