path: root/remote.c
diff options
authorJunio C Hamano <>2018-08-01 16:22:37 (GMT)
committerJunio C Hamano <>2018-08-02 19:16:52 (GMT)
commit60650a48c0b24ecf64468426ec13b88c07069b28 (patch)
tree0dcc3970c6df710ecd78618212e865479ffea6d6 /remote.c
parentfc54c1af3ec09bab8b8ea09768c2da4069b7f53e (diff)
remote: make refspec follow the same disambiguation rule as local refs
When matching a non-wildcard LHS of a refspec against a list of refs, find_ref_by_name_abbrev() returns the first ref that matches using any DWIM rules used by refname_match() in refs.c, even if a better match occurs later in the list of refs. This causes unexpected behavior when (for example) fetching using the refspec "refs/heads/s:<something>" from a remote with both "refs/heads/refs/heads/s" and "refs/heads/s"; even if the former was inadvertently created, one would still expect the latter to be fetched. Similarly, when both a tag T and a branch T exist, fetching T should favor the tag, just like how local refname disambiguation rule works. But because the code walks over ls-remote output from the remote, which happens to be sorted in alphabetical order and has refs/heads/T before refs/tags/T, a request to fetch T is (mis)interpreted as fetching refs/heads/T. Update refname_match(), all of whose current callers care only if it returns non-zero (i.e. matches) to see if an abbreviated name can mean the full name being tested, so that it returns a positive integer whose magnitude can be used to tell the precedence, and fix the find_ref_by_name_abbrev() function not to stop at the first match but find the match with the highest precedence. This is based on an earlier work, which special cased only the exact matches, by Jonathan Tan. Helped-by: Jonathan Tan <> Helped-by: Jonathan Nieder <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'remote.c')
1 files changed, 10 insertions, 3 deletions
diff --git a/remote.c b/remote.c
index c10d87c..4a3e7ba 100644
--- a/remote.c
+++ b/remote.c
@@ -1880,11 +1880,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)