1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-22 22:36:09 +02:00

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:
Junio C Hamano 2018-08-17 13:09:55 -07:00
commit 72c11b7e62
3 changed files with 58 additions and 8 deletions

18
refs.c
View File

@ -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;
}

View File

@ -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)

View File

@ -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 () {