Merge branch 'fm/fetch-raw-sha1'

"git upload-pack" that serves "git fetch" can be told to serve
commits that are not at the tip of any ref, as long as they are
reachable from a ref, with uploadpack.allowReachableSHA1InWant
configuration variable.

* fm/fetch-raw-sha1:
  upload-pack: optionally allow fetching reachable sha1
  upload-pack: prepare to extend allow-tip-sha1-in-want
  config.txt: clarify allowTipSHA1InWant with camelCase
This commit is contained in:
Junio C Hamano 2015-06-01 12:45:19 -07:00
commit a9d3493380
6 changed files with 116 additions and 16 deletions

View File

@ -2558,14 +2558,20 @@ uploadpack.hideRefs::
are under the hierarchies listed on the value of this are under the hierarchies listed on the value of this
variable is excluded, and is hidden from `git ls-remote`, variable is excluded, and is hidden from `git ls-remote`,
`git fetch`, etc. An attempt to fetch a hidden ref by `git `git fetch`, etc. An attempt to fetch a hidden ref by `git
fetch` will fail. See also `uploadpack.allowtipsha1inwant`. fetch` will fail. See also `uploadpack.allowTipSHA1InWant`.
uploadpack.allowtipsha1inwant:: uploadpack.allowTipSHA1InWant::
When `uploadpack.hideRefs` is in effect, allow `upload-pack` When `uploadpack.hideRefs` is in effect, allow `upload-pack`
to accept a fetch request that asks for an object at the tip to accept a fetch request that asks for an object at the tip
of a hidden ref (by default, such a request is rejected). of a hidden ref (by default, such a request is rejected).
see also `uploadpack.hideRefs`. 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:: uploadpack.keepAlive::
When `upload-pack` has started `pack-objects`, there may be a When `upload-pack` has started `pack-objects`, there may be a
quiet period while `pack-objects` prepares the pack. Normally quiet period while `pack-objects` prepares the pack. Normally

View File

@ -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 send at least one "want" command in the request body.
Clients MUST NOT reference an id in a "want" command which did not Clients MUST NOT reference an id in a "want" command which did not
appear in the response obtained through ref discovery unless the 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 compute_request = want_list
have_list have_list

View File

@ -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 send "want" lines with SHA-1s that exist at the server but are not
advertised by upload-pack. 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> push-cert=<nonce>
----------------- -----------------

View File

@ -43,7 +43,12 @@ static int marked;
#define MAX_IN_VAIN 256 #define MAX_IN_VAIN 256
static struct prio_queue rev_list = { compare_commits_by_commit_date }; static struct prio_queue rev_list = { compare_commits_by_commit_date };
static int non_common_revs, multi_ack, use_sideband, allow_tip_sha1_in_want; 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) static void rev_list_push(struct commit *commit, int mark)
{ {
@ -542,7 +547,8 @@ static void filter_refs(struct fetch_pack_args *args,
} }
/* Append unmatched requests to the list */ /* Append unmatched requests to the list */
if (allow_tip_sha1_in_want) { if ((allow_unadvertised_object_request &
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
for (i = 0; i < nr_sought; i++) { for (i = 0; i < nr_sought; i++) {
unsigned char sha1[20]; unsigned char sha1[20];
@ -821,7 +827,12 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (server_supports("allow-tip-sha1-in-want")) { if (server_supports("allow-tip-sha1-in-want")) {
if (args->verbose) if (args->verbose)
fprintf(stderr, "Server supports allow-tip-sha1-in-want\n"); fprintf(stderr, "Server supports allow-tip-sha1-in-want\n");
allow_tip_sha1_in_want = 1; 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")) if (!server_supports("thin-pack"))
args->use_thin_pack = 0; args->use_thin_pack = 0;

View File

@ -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' ' test_expect_success 'fetch follows tags by default' '
mk_test testrepo heads/master && mk_test testrepo heads/master &&
rm -fr src dst && rm -fr src dst &&

View File

@ -35,7 +35,11 @@ static int multi_ack;
static int no_done; static int no_done;
static int use_thin_pack, use_ofs_delta, use_include_tag; static int use_thin_pack, use_ofs_delta, use_include_tag;
static int no_progress, daemon_mode; static int no_progress, daemon_mode;
static int allow_tip_sha1_in_want; /* 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 int shallow_nr;
static struct object_array have_obj; static struct object_array have_obj;
static struct object_array want_obj; static struct object_array want_obj;
@ -442,8 +446,9 @@ static int get_common_commits(void)
static int is_our_ref(struct object *o) static int is_our_ref(struct object *o)
{ {
return o->flags & int allow_hidden_ref = (allow_unadvertised_object_request &
((allow_tip_sha1_in_want ? HIDDEN_REF : 0) | OUR_REF); (ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);
} }
static void check_non_tip(void) static void check_non_tip(void)
@ -456,8 +461,12 @@ static void check_non_tip(void)
char namebuf[42]; /* ^ + SHA-1 + LF */ char namebuf[42]; /* ^ + SHA-1 + LF */
int i; 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; goto error;
cmd.argv = argv; cmd.argv = argv;
@ -724,10 +733,13 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
struct strbuf symref_info = STRBUF_INIT; struct strbuf symref_info = STRBUF_INIT;
format_symref_info(&symref_info, cb_data); 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, sha1_to_hex(sha1), refname_nons,
0, capabilities, 0, capabilities,
allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "", (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" : "", stateless_rpc ? " no-done" : "",
symref_info.buf, symref_info.buf,
git_user_agent_sanitized()); git_user_agent_sanitized());
@ -787,9 +799,17 @@ static void upload_pack(void)
static int upload_pack_config(const char *var, const char *value, void *unused) static int upload_pack_config(const char *var, const char *value, void *unused)
{ {
if (!strcmp("uploadpack.allowtipsha1inwant", var)) if (!strcmp("uploadpack.allowtipsha1inwant", var)) {
allow_tip_sha1_in_want = git_config_bool(var, value); if (git_config_bool(var, value))
else if (!strcmp("uploadpack.keepalive", var)) { 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); keepalive = git_config_int(var, value);
if (!keepalive) if (!keepalive)
keepalive = -1; keepalive = -1;