Skip to content

Commit fdb69d3

Browse files
jonathantanmygitster
authored andcommitted
fetch-pack: always allow fetching of literal SHA1s
fetch-pack, when fetching a literal SHA-1 from a server that is not configured with uploadpack.allowtipsha1inwant (or similar), always returns an error message of the form "Server does not allow request for unadvertised object %s". However, it is sometimes the case that such object is advertised. This situation would occur, for example, if a user or a script was provided a SHA-1 instead of a branch or tag name for fetching, and wanted to invoke "git fetch" or "git fetch-pack" using that SHA-1. Teach fetch-pack to also check the SHA-1s of the refs in the received ref advertisement if a literal SHA-1 was given by the user. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Reviewed-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent b06d364 commit fdb69d3

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

fetch-pack.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "version.h"
1616
#include "prio-queue.h"
1717
#include "sha1-array.h"
18+
#include "oidset.h"
1819

1920
static int transfer_unpack_limit = -1;
2021
static int fetch_unpack_limit = -1;
@@ -592,13 +593,38 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
592593
}
593594
}
594595

596+
static void add_refs_to_oidset(struct oidset *oids, struct ref *refs)
597+
{
598+
for (; refs; refs = refs->next)
599+
oidset_insert(oids, &refs->old_oid);
600+
}
601+
602+
static int tip_oids_contain(struct oidset *tip_oids,
603+
struct ref *unmatched, struct ref *newlist,
604+
const struct object_id *id)
605+
{
606+
/*
607+
* Note that this only looks at the ref lists the first time it's
608+
* called. This works out in filter_refs() because even though it may
609+
* add to "newlist" between calls, the additions will always be for
610+
* oids that are already in the set.
611+
*/
612+
if (!tip_oids->map.tablesize) {
613+
add_refs_to_oidset(tip_oids, unmatched);
614+
add_refs_to_oidset(tip_oids, newlist);
615+
}
616+
return oidset_contains(tip_oids, id);
617+
}
618+
595619
static void filter_refs(struct fetch_pack_args *args,
596620
struct ref **refs,
597621
struct ref **sought, int nr_sought)
598622
{
599623
struct ref *newlist = NULL;
600624
struct ref **newtail = &newlist;
625+
struct ref *unmatched = NULL;
601626
struct ref *ref, *next;
627+
struct oidset tip_oids = OIDSET_INIT;
602628
int i;
603629

604630
i = 0;
@@ -631,7 +657,8 @@ static void filter_refs(struct fetch_pack_args *args,
631657
ref->next = NULL;
632658
newtail = &ref->next;
633659
} else {
634-
free(ref);
660+
ref->next = unmatched;
661+
unmatched = ref;
635662
}
636663
}
637664

@@ -648,14 +675,23 @@ static void filter_refs(struct fetch_pack_args *args,
648675
continue;
649676

650677
if ((allow_unadvertised_object_request &
651-
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
678+
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) ||
679+
tip_oids_contain(&tip_oids, unmatched, newlist,
680+
&ref->old_oid)) {
652681
ref->match_status = REF_MATCHED;
653682
*newtail = copy_ref(ref);
654683
newtail = &(*newtail)->next;
655684
} else {
656685
ref->match_status = REF_UNADVERTISED_NOT_ALLOWED;
657686
}
658687
}
688+
689+
oidset_clear(&tip_oids);
690+
for (ref = unmatched; ref; ref = next) {
691+
next = ref->next;
692+
free(ref);
693+
}
694+
659695
*refs = newlist;
660696
}
661697

t/t5500-fetch-pack.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,41 @@ test_expect_success 'fetch-pack can fetch a raw sha1' '
547547
git fetch-pack hidden $(git -C hidden rev-parse refs/hidden/one)
548548
'
549549

550+
test_expect_success 'fetch-pack can fetch a raw sha1 that is advertised as a ref' '
551+
rm -rf server client &&
552+
git init server &&
553+
test_commit -C server 1 &&
554+
555+
git init client &&
556+
git -C client fetch-pack ../server \
557+
$(git -C server rev-parse refs/heads/master)
558+
'
559+
560+
test_expect_success 'fetch-pack can fetch a raw sha1 overlapping a named ref' '
561+
rm -rf server client &&
562+
git init server &&
563+
test_commit -C server 1 &&
564+
test_commit -C server 2 &&
565+
566+
git init client &&
567+
git -C client fetch-pack ../server \
568+
$(git -C server rev-parse refs/tags/1) refs/tags/1
569+
'
570+
571+
test_expect_success 'fetch-pack cannot fetch a raw sha1 that is not advertised as a ref' '
572+
rm -rf server &&
573+
574+
git init server &&
575+
test_commit -C server 5 &&
576+
git -C server tag -d 5 &&
577+
test_commit -C server 6 &&
578+
579+
git init client &&
580+
test_must_fail git -C client fetch-pack ../server \
581+
$(git -C server rev-parse refs/heads/master^) 2>err &&
582+
test_i18ngrep "Server does not allow request for unadvertised object" err
583+
'
584+
550585
check_prot_path () {
551586
cat >expected <<-EOF &&
552587
Diag: url=$1

0 commit comments

Comments
 (0)