Merge branch 'jt/fetch-allow-tip-sha1-implicitly'

There is no good reason why "git fetch $there $sha1" should fail
when the $sha1 names an object at the tip of an advertised ref,
even when the other side hasn't enabled allowTipSHA1InWant.

* jt/fetch-allow-tip-sha1-implicitly:
  fetch-pack: always allow fetching of literal SHA1s
This commit is contained in:
Junio C Hamano 2017-05-30 11:16:43 +09:00
commit 02c531eba2
2 changed files with 73 additions and 2 deletions

View File

@ -15,6 +15,7 @@
#include "version.h"
#include "prio-queue.h"
#include "sha1-array.h"
#include "oidset.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@ -592,13 +593,38 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
}
}
static void add_refs_to_oidset(struct oidset *oids, struct ref *refs)
{
for (; refs; refs = refs->next)
oidset_insert(oids, &refs->old_oid);
}
static int tip_oids_contain(struct oidset *tip_oids,
struct ref *unmatched, struct ref *newlist,
const struct object_id *id)
{
/*
* Note that this only looks at the ref lists the first time it's
* called. This works out in filter_refs() because even though it may
* add to "newlist" between calls, the additions will always be for
* oids that are already in the set.
*/
if (!tip_oids->map.tablesize) {
add_refs_to_oidset(tip_oids, unmatched);
add_refs_to_oidset(tip_oids, newlist);
}
return oidset_contains(tip_oids, id);
}
static void filter_refs(struct fetch_pack_args *args,
struct ref **refs,
struct ref **sought, int nr_sought)
{
struct ref *newlist = NULL;
struct ref **newtail = &newlist;
struct ref *unmatched = NULL;
struct ref *ref, *next;
struct oidset tip_oids = OIDSET_INIT;
int i;
i = 0;
@ -631,7 +657,8 @@ static void filter_refs(struct fetch_pack_args *args,
ref->next = NULL;
newtail = &ref->next;
} else {
free(ref);
ref->next = unmatched;
unmatched = ref;
}
}
@ -649,7 +676,9 @@ static void filter_refs(struct fetch_pack_args *args,
continue;
if ((allow_unadvertised_object_request &
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1))) {
(ALLOW_TIP_SHA1 | ALLOW_REACHABLE_SHA1)) ||
tip_oids_contain(&tip_oids, unmatched, newlist,
&ref->old_oid)) {
ref->match_status = REF_MATCHED;
*newtail = copy_ref(ref);
newtail = &(*newtail)->next;
@ -657,6 +686,13 @@ static void filter_refs(struct fetch_pack_args *args,
ref->match_status = REF_UNADVERTISED_NOT_ALLOWED;
}
}
oidset_clear(&tip_oids);
for (ref = unmatched; ref; ref = next) {
next = ref->next;
free(ref);
}
*refs = newlist;
}

View File

@ -547,6 +547,41 @@ test_expect_success 'fetch-pack can fetch a raw sha1' '
git fetch-pack hidden $(git -C hidden rev-parse refs/hidden/one)
'
test_expect_success 'fetch-pack can fetch a raw sha1 that is advertised as a ref' '
rm -rf server client &&
git init server &&
test_commit -C server 1 &&
git init client &&
git -C client fetch-pack ../server \
$(git -C server rev-parse refs/heads/master)
'
test_expect_success 'fetch-pack can fetch a raw sha1 overlapping a named ref' '
rm -rf server client &&
git init server &&
test_commit -C server 1 &&
test_commit -C server 2 &&
git init client &&
git -C client fetch-pack ../server \
$(git -C server rev-parse refs/tags/1) refs/tags/1
'
test_expect_success 'fetch-pack cannot fetch a raw sha1 that is not advertised as a ref' '
rm -rf server &&
git init server &&
test_commit -C server 5 &&
git -C server tag -d 5 &&
test_commit -C server 6 &&
git init client &&
test_must_fail git -C client fetch-pack ../server \
$(git -C server rev-parse refs/heads/master^) 2>err &&
test_i18ngrep "Server does not allow request for unadvertised object" err
'
check_prot_path () {
cat >expected <<-EOF &&
Diag: url=$1