Skip to content

Commit 29561ad

Browse files
author
Junio C Hamano
committed
refs outside refs/{heads,tags} match less strongly.
This changes the refname matching logic used to decide which ref is updated with git-send-pack. We used to error out when pushing 'master' when the other end has both 'master' branch and a tracking branch 'remotes/$name/master' but with this, 'master' matches only 'refs/heads/master' when both and no other 'master' exist. Pushing 'foo' when both heads/foo and tags/foo exist at the remote end is still considered an error and you would need to disambiguate between them by being more explicit. When neither heads/foo nor tags/foo exists at the remote, pushing 'foo' when there is only remotes/origin/foo is not ambiguous, while it still is ambiguous when there are more than one such weaker match (remotes/origin/foo and remotes/alt/foo, for example). Signed-off-by: Junio C Hamano <[email protected]>
1 parent f73da29 commit 29561ad

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

connect.c

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,21 +174,58 @@ static int count_refspec_match(const char *pattern,
174174
struct ref *refs,
175175
struct ref **matched_ref)
176176
{
177-
int match;
178177
int patlen = strlen(pattern);
178+
struct ref *matched_weak = NULL;
179+
struct ref *matched = NULL;
180+
int weak_match = 0;
181+
int match = 0;
179182

180-
for (match = 0; refs; refs = refs->next) {
183+
for (weak_match = match = 0; refs; refs = refs->next) {
181184
char *name = refs->name;
182185
int namelen = strlen(name);
186+
int weak_match;
187+
183188
if (namelen < patlen ||
184189
memcmp(name + namelen - patlen, pattern, patlen))
185190
continue;
186191
if (namelen != patlen && name[namelen - patlen - 1] != '/')
187192
continue;
188-
match++;
189-
*matched_ref = refs;
193+
194+
/* A match is "weak" if it is with refs outside
195+
* heads or tags, and did not specify the pattern
196+
* in full (e.g. "refs/remotes/origin/master") or at
197+
* least from the toplevel (e.g. "remotes/origin/master");
198+
* otherwise "git push $URL master" would result in
199+
* ambiguity between remotes/origin/master and heads/master
200+
* at the remote site.
201+
*/
202+
if (namelen != patlen &&
203+
patlen != namelen - 5 &&
204+
strncmp(name, "refs/heads/", 11) &&
205+
strncmp(name, "refs/tags/", 10)) {
206+
/* We want to catch the case where only weak
207+
* matches are found and there are multiple
208+
* matches, and where more than one strong
209+
* matches are found, as ambiguous. One
210+
* strong match with zero or more weak matches
211+
* are acceptable as a unique match.
212+
*/
213+
matched_weak = refs;
214+
weak_match++;
215+
}
216+
else {
217+
matched = refs;
218+
match++;
219+
}
220+
}
221+
if (!matched) {
222+
*matched_ref = matched_weak;
223+
return weak_match;
224+
}
225+
else {
226+
*matched_ref = matched;
227+
return match;
190228
}
191-
return match;
192229
}
193230

194231
static void link_dst_tail(struct ref *ref, struct ref ***tail)

0 commit comments

Comments
 (0)