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
This commit is contained in:
commit
72c11b7e62
18
refs.c
18
refs.c
@ -490,16 +490,24 @@ static const char *ref_rev_parse_rules[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
#define NUM_REV_PARSE_RULES (ARRAY_SIZE(ref_rev_parse_rules) - 1)
|
||||
|
||||
/*
|
||||
* Is it possible that the caller meant full_name with abbrev_name?
|
||||
* If so return a non-zero value to signal "yes"; the magnitude of
|
||||
* the returned value gives the precedence used for disambiguation.
|
||||
*
|
||||
* If abbrev_name cannot mean full_name, return 0.
|
||||
*/
|
||||
int refname_match(const char *abbrev_name, const char *full_name)
|
||||
{
|
||||
const char **p;
|
||||
const int abbrev_name_len = strlen(abbrev_name);
|
||||
const int num_rules = NUM_REV_PARSE_RULES;
|
||||
|
||||
for (p = ref_rev_parse_rules; *p; p++) {
|
||||
if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (p = ref_rev_parse_rules; *p; p++)
|
||||
if (!strcmp(full_name, mkpath(*p, abbrev_name_len, abbrev_name)))
|
||||
return &ref_rev_parse_rules[num_rules] - p;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
13
remote.c
13
remote.c
@ -1689,11 +1689,18 @@ static struct ref *get_expanded_map(const struct ref *remote_refs,
|
||||
static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name)
|
||||
{
|
||||
const struct ref *ref;
|
||||
const struct ref *best_match = NULL;
|
||||
int best_score = 0;
|
||||
|
||||
for (ref = refs; ref; ref = ref->next) {
|
||||
if (refname_match(name, ref->name))
|
||||
return ref;
|
||||
int score = refname_match(name, ref->name);
|
||||
|
||||
if (best_score < score) {
|
||||
best_match = ref;
|
||||
best_score = score;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return best_match;
|
||||
}
|
||||
|
||||
struct ref *get_remote_ref(const struct ref *remote_refs, const char *name)
|
||||
|
@ -535,6 +535,41 @@ test_expect_success "should be able to fetch with duplicate refspecs" '
|
||||
)
|
||||
'
|
||||
|
||||
test_expect_success 'LHS of refspec follows ref disambiguation rules' '
|
||||
mkdir lhs-ambiguous &&
|
||||
(
|
||||
cd lhs-ambiguous &&
|
||||
git init server &&
|
||||
test_commit -C server unwanted &&
|
||||
test_commit -C server wanted &&
|
||||
|
||||
git init client &&
|
||||
|
||||
# Check a name coming after "refs" alphabetically ...
|
||||
git -C server update-ref refs/heads/s wanted &&
|
||||
git -C server update-ref refs/heads/refs/heads/s unwanted &&
|
||||
git -C client fetch ../server +refs/heads/s:refs/heads/checkthis &&
|
||||
git -C server rev-parse wanted >expect &&
|
||||
git -C client rev-parse checkthis >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
# ... and one before.
|
||||
git -C server update-ref refs/heads/q wanted &&
|
||||
git -C server update-ref refs/heads/refs/heads/q unwanted &&
|
||||
git -C client fetch ../server +refs/heads/q:refs/heads/checkthis &&
|
||||
git -C server rev-parse wanted >expect &&
|
||||
git -C client rev-parse checkthis >actual &&
|
||||
test_cmp expect actual &&
|
||||
|
||||
# Tags are preferred over branches like refs/{heads,tags}/*
|
||||
git -C server update-ref refs/tags/t wanted &&
|
||||
git -C server update-ref refs/heads/t unwanted &&
|
||||
git -C client fetch ../server +t:refs/heads/checkthis &&
|
||||
git -C server rev-parse wanted >expect &&
|
||||
git -C client rev-parse checkthis >actual
|
||||
)
|
||||
'
|
||||
|
||||
# configured prune tests
|
||||
|
||||
set_config_tristate () {
|
||||
|
Loading…
Reference in New Issue
Block a user