Skip to content

Commit a9d3493

Browse files
committed
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
2 parents 6dec263 + 68ee628 commit a9d3493

File tree

6 files changed

+116
-16
lines changed

6 files changed

+116
-16
lines changed

Documentation/config.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,14 +2558,20 @@ uploadpack.hideRefs::
25582558
are under the hierarchies listed on the value of this
25592559
variable is excluded, and is hidden from `git ls-remote`,
25602560
`git fetch`, etc. An attempt to fetch a hidden ref by `git
2561-
fetch` will fail. See also `uploadpack.allowtipsha1inwant`.
2561+
fetch` will fail. See also `uploadpack.allowTipSHA1InWant`.
25622562

2563-
uploadpack.allowtipsha1inwant::
2563+
uploadpack.allowTipSHA1InWant::
25642564
When `uploadpack.hideRefs` is in effect, allow `upload-pack`
25652565
to accept a fetch request that asks for an object at the tip
25662566
of a hidden ref (by default, such a request is rejected).
25672567
see also `uploadpack.hideRefs`.
25682568

2569+
uploadpack.allowReachableSHA1InWant::
2570+
Allow `upload-pack` to accept a fetch request that asks for an
2571+
object that is reachable from any ref tip. However, note that
2572+
calculating object reachability is computationally expensive.
2573+
Defaults to `false`.
2574+
25692575
uploadpack.keepAlive::
25702576
When `upload-pack` has started `pack-objects`, there may be a
25712577
quiet period while `pack-objects` prepares the pack. Normally

Documentation/technical/http-protocol.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,8 @@ Servers SHOULD support all capabilities defined here.
319319
Clients MUST send at least one "want" command in the request body.
320320
Clients MUST NOT reference an id in a "want" command which did not
321321
appear in the response obtained through ref discovery unless the
322-
server advertises capability `allow-tip-sha1-in-want`.
322+
server advertises capability `allow-tip-sha1-in-want` or
323+
`allow-reachable-sha1-in-want`.
323324

324325
compute_request = want_list
325326
have_list

Documentation/technical/protocol-capabilities.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,13 @@ If the upload-pack server advertises this capability, fetch-pack may
260260
send "want" lines with SHA-1s that exist at the server but are not
261261
advertised by upload-pack.
262262

263+
allow-reachable-sha1-in-want
264+
----------------------------
265+
266+
If the upload-pack server advertises this capability, fetch-pack may
267+
send "want" lines with SHA-1s that exist at the server but are not
268+
advertised by upload-pack.
269+
263270
push-cert=<nonce>
264271
-----------------
265272

fetch-pack.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ static int marked;
4343
#define MAX_IN_VAIN 256
4444

4545
static struct prio_queue rev_list = { compare_commits_by_commit_date };
46-
static int non_common_revs, multi_ack, use_sideband, allow_tip_sha1_in_want;
46+
static int non_common_revs, multi_ack, use_sideband;
47+
/* Allow specifying sha1 if it is a ref tip. */
48+
#define ALLOW_TIP_SHA1 01
49+
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
50+
#define ALLOW_REACHABLE_SHA1 02
51+
static unsigned int allow_unadvertised_object_request;
4752

4853
static void rev_list_push(struct commit *commit, int mark)
4954
{
@@ -542,7 +547,8 @@ static void filter_refs(struct fetch_pack_args *args,
542547
}
543548

544549
/* Append unmatched requests to the list */
545-
if (allow_tip_sha1_in_want) {
550+
if ((allow_unadvertised_object_request &
551+
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
546552
for (i = 0; i < nr_sought; i++) {
547553
unsigned char sha1[20];
548554

@@ -821,7 +827,12 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
821827
if (server_supports("allow-tip-sha1-in-want")) {
822828
if (args->verbose)
823829
fprintf(stderr, "Server supports allow-tip-sha1-in-want\n");
824-
allow_tip_sha1_in_want = 1;
830+
allow_unadvertised_object_request |= ALLOW_TIP_SHA1;
831+
}
832+
if (server_supports("allow-reachable-sha1-in-want")) {
833+
if (args->verbose)
834+
fprintf(stderr, "Server supports allow-reachable-sha1-in-want\n");
835+
allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
825836
}
826837
if (!server_supports("thin-pack"))
827838
args->use_thin_pack = 0;

t/t5516-fetch-push.sh

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,61 @@ test_expect_success 'fetch exact SHA1' '
11201120
)
11211121
'
11221122

1123+
for configallowtipsha1inwant in true false
1124+
do
1125+
test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" '
1126+
mk_empty testrepo &&
1127+
(
1128+
cd testrepo &&
1129+
git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant &&
1130+
git commit --allow-empty -m foo &&
1131+
git commit --allow-empty -m bar
1132+
) &&
1133+
SHA1=$(git --git-dir=testrepo/.git rev-parse HEAD^) &&
1134+
mk_empty shallow &&
1135+
(
1136+
cd shallow &&
1137+
test_must_fail git fetch --depth=1 ../testrepo/.git $SHA1 &&
1138+
git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true &&
1139+
git fetch --depth=1 ../testrepo/.git $SHA1 &&
1140+
git cat-file commit $SHA1
1141+
)
1142+
'
1143+
1144+
test_expect_success "deny fetch unreachable SHA1, allowtipsha1inwant=$configallowtipsha1inwant" '
1145+
mk_empty testrepo &&
1146+
(
1147+
cd testrepo &&
1148+
git config uploadpack.allowtipsha1inwant $configallowtipsha1inwant &&
1149+
git commit --allow-empty -m foo &&
1150+
git commit --allow-empty -m bar &&
1151+
git commit --allow-empty -m xyz
1152+
) &&
1153+
SHA1_1=$(git --git-dir=testrepo/.git rev-parse HEAD^^) &&
1154+
SHA1_2=$(git --git-dir=testrepo/.git rev-parse HEAD^) &&
1155+
SHA1_3=$(git --git-dir=testrepo/.git rev-parse HEAD) &&
1156+
(
1157+
cd testrepo &&
1158+
git reset --hard $SHA1_2 &&
1159+
git cat-file commit $SHA1_1 &&
1160+
git cat-file commit $SHA1_3
1161+
) &&
1162+
mk_empty shallow &&
1163+
(
1164+
cd shallow &&
1165+
test_must_fail git fetch ../testrepo/.git $SHA1_3 &&
1166+
test_must_fail git fetch ../testrepo/.git $SHA1_1 &&
1167+
git --git-dir=../testrepo/.git config uploadpack.allowreachablesha1inwant true &&
1168+
git fetch ../testrepo/.git $SHA1_1 &&
1169+
git cat-file commit $SHA1_1 &&
1170+
test_must_fail git cat-file commit $SHA1_2 &&
1171+
git fetch ../testrepo/.git $SHA1_2 &&
1172+
git cat-file commit $SHA1_2 &&
1173+
test_must_fail git fetch ../testrepo/.git $SHA1_3
1174+
)
1175+
'
1176+
done
1177+
11231178
test_expect_success 'fetch follows tags by default' '
11241179
mk_test testrepo heads/master &&
11251180
rm -fr src dst &&

upload-pack.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ static int multi_ack;
3535
static int no_done;
3636
static int use_thin_pack, use_ofs_delta, use_include_tag;
3737
static int no_progress, daemon_mode;
38-
static int allow_tip_sha1_in_want;
38+
/* Allow specifying sha1 if it is a ref tip. */
39+
#define ALLOW_TIP_SHA1 01
40+
/* Allow request of a sha1 if it is reachable from a ref (possibly hidden ref). */
41+
#define ALLOW_REACHABLE_SHA1 02
42+
static unsigned int allow_unadvertised_object_request;
3943
static int shallow_nr;
4044
static struct object_array have_obj;
4145
static struct object_array want_obj;
@@ -442,8 +446,9 @@ static int get_common_commits(void)
442446

443447
static int is_our_ref(struct object *o)
444448
{
445-
return o->flags &
446-
((allow_tip_sha1_in_want ? HIDDEN_REF : 0) | OUR_REF);
449+
int allow_hidden_ref = (allow_unadvertised_object_request &
450+
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1));
451+
return o->flags & ((allow_hidden_ref ? HIDDEN_REF : 0) | OUR_REF);
447452
}
448453

449454
static void check_non_tip(void)
@@ -456,8 +461,12 @@ static void check_non_tip(void)
456461
char namebuf[42]; /* ^ + SHA-1 + LF */
457462
int i;
458463

459-
/* In the normal in-process case non-tip request can never happen */
460-
if (!stateless_rpc)
464+
/*
465+
* In the normal in-process case without
466+
* uploadpack.allowReachableSHA1InWant,
467+
* non-tip requests can never happen.
468+
*/
469+
if (!stateless_rpc && !(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1))
461470
goto error;
462471

463472
cmd.argv = argv;
@@ -724,10 +733,13 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
724733
struct strbuf symref_info = STRBUF_INIT;
725734

726735
format_symref_info(&symref_info, cb_data);
727-
packet_write(1, "%s %s%c%s%s%s%s agent=%s\n",
736+
packet_write(1, "%s %s%c%s%s%s%s%s agent=%s\n",
728737
sha1_to_hex(sha1), refname_nons,
729738
0, capabilities,
730-
allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "",
739+
(allow_unadvertised_object_request & ALLOW_TIP_SHA1) ?
740+
" allow-tip-sha1-in-want" : "",
741+
(allow_unadvertised_object_request & ALLOW_REACHABLE_SHA1) ?
742+
" allow-reachable-sha1-in-want" : "",
731743
stateless_rpc ? " no-done" : "",
732744
symref_info.buf,
733745
git_user_agent_sanitized());
@@ -787,9 +799,17 @@ static void upload_pack(void)
787799

788800
static int upload_pack_config(const char *var, const char *value, void *unused)
789801
{
790-
if (!strcmp("uploadpack.allowtipsha1inwant", var))
791-
allow_tip_sha1_in_want = git_config_bool(var, value);
792-
else if (!strcmp("uploadpack.keepalive", var)) {
802+
if (!strcmp("uploadpack.allowtipsha1inwant", var)) {
803+
if (git_config_bool(var, value))
804+
allow_unadvertised_object_request |= ALLOW_TIP_SHA1;
805+
else
806+
allow_unadvertised_object_request &= ~ALLOW_TIP_SHA1;
807+
} else if (!strcmp("uploadpack.allowreachablesha1inwant", var)) {
808+
if (git_config_bool(var, value))
809+
allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
810+
else
811+
allow_unadvertised_object_request &= ~ALLOW_REACHABLE_SHA1;
812+
} else if (!strcmp("uploadpack.keepalive", var)) {
793813
keepalive = git_config_int(var, value);
794814
if (!keepalive)
795815
keepalive = -1;

0 commit comments

Comments
 (0)