Skip to content

Commit 72c11b7

Browse files
committed
Merge branch 'jt/refspec-dwim-precedence-fix'
"git fetch $there refs/heads/s" ought to fetch the tip of the branch 's', but when "refs/heads/refs/heads/s", i.e. a branch whose name is "refs/heads/s" exists at the same time, fetched that one instead by mistake. This has been corrected to honor the usual disambiguation rules for abbreviated refnames. * jt/refspec-dwim-precedence-fix: remote: make refspec follow the same disambiguation rule as local refs
2 parents 60858f3 + 60650a4 commit 72c11b7

File tree

3 files changed

+58
-8
lines changed

3 files changed

+58
-8
lines changed

refs.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -490,16 +490,24 @@ static const char *ref_rev_parse_rules[] = {
490490
NULL
491491
};
492492

493+
#define NUM_REV_PARSE_RULES (ARRAY_SIZE(ref_rev_parse_rules) - 1)
494+
495+
/*
496+
* Is it possible that the caller meant full_name with abbrev_name?
497+
* If so return a non-zero value to signal "yes"; the magnitude of
498+
* the returned value gives the precedence used for disambiguation.
499+
*
500+
* If abbrev_name cannot mean full_name, return 0.
501+
*/
493502
int refname_match(const char *abbrev_name, const char *full_name)
494503
{
495504
const char **p;
496505
const int abbrev_name_len = strlen(abbrev_name);
506+
const int num_rules = NUM_REV_PARSE_RULES;
497507

498-
for (p = ref_rev_parse_rules; *p; p++) {
499-
if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
500-
return 1;
501-
}
502-
}
508+
for (p = ref_rev_parse_rules; *p; p++)
509+
if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name)))
510+
return &ref_rev_parse_rules[num_rules] - p;
503511

504512
return 0;
505513
}

remote.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,11 +1689,18 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
16891689
static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
16901690
{
16911691
const struct ref *ref;
1692+
const struct ref *best_match = NULL;
1693+
int best_score = 0;
1694+
16921695
for (ref = refs; ref; ref = ref->next) {
1693-
if (refname_match(name, ref->name))
1694-
return ref;
1696+
int score = refname_match(name, ref->name);
1697+
1698+
if (best_score < score) {
1699+
best_match = ref;
1700+
best_score = score;
1701+
}
16951702
}
1696-
return NULL;
1703+
return best_match;
16971704
}
16981705

16991706
struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)

t/t5510-fetch.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,41 @@ test_expect_success "should be able to fetch with duplicate refspecs" '
535535
)
536536
'
537537

538+
test_expect_success 'LHS of refspec follows ref disambiguation rules' '
539+
mkdir lhs-ambiguous &&
540+
(
541+
cd lhs-ambiguous &&
542+
git init server &&
543+
test_commit -C server unwanted &&
544+
test_commit -C server wanted &&
545+
546+
git init client &&
547+
548+
# Check a name coming after "refs" alphabetically ...
549+
git -C server update-ref refs/heads/s wanted &&
550+
git -C server update-ref refs/heads/refs/heads/s unwanted &&
551+
git -C client fetch ../server +refs/heads/s:refs/heads/checkthis &&
552+
git -C server rev-parse wanted >expect &&
553+
git -C client rev-parse checkthis >actual &&
554+
test_cmp expect actual &&
555+
556+
# ... and one before.
557+
git -C server update-ref refs/heads/q wanted &&
558+
git -C server update-ref refs/heads/refs/heads/q unwanted &&
559+
git -C client fetch ../server +refs/heads/q:refs/heads/checkthis &&
560+
git -C server rev-parse wanted >expect &&
561+
git -C client rev-parse checkthis >actual &&
562+
test_cmp expect actual &&
563+
564+
# Tags are preferred over branches like refs/{heads,tags}/*
565+
git -C server update-ref refs/tags/t wanted &&
566+
git -C server update-ref refs/heads/t unwanted &&
567+
git -C client fetch ../server +t:refs/heads/checkthis &&
568+
git -C server rev-parse wanted >expect &&
569+
git -C client rev-parse checkthis >actual
570+
)
571+
'
572+
538573
# configured prune tests
539574

540575
set_config_tristate () {

0 commit comments

Comments
 (0)