Skip to content

Commit 41c21f2

Browse files
jherlandgitster
authored andcommitted
branch.c: Validate tracking branches with refspecs instead of refs/remotes/*
The current code for validating tracking branches (e.g. the argument to the -t/--track option) hardcodes refs/heads/* and refs/remotes/* as the potential locations for tracking branches. This works with the refspecs created by "git clone" or "git remote add", but is suboptimal in other cases: - If "refs/remotes/foo/bar" exists without any association to a remote (i.e. there is no remote named "foo", or no remote with a refspec that matches "refs/remotes/foo/bar"), then it is impossible to set up a valid upstream config that tracks it. Currently, the code defaults to using "refs/remotes/foo/bar" from repo "." as the upstream, which works, but is probably not what the user had in mind when running "git branch baz --track foo/bar". - If the user has tweaked the fetch refspec for a remote to put its remote-tracking branches outside of refs/remotes/*, e.g. by running git config remote.foo.fetch "+refs/heads/*:refs/foo_stuff/*" then the current code will refuse to use its remote-tracking branches as --track arguments, since they do not match refs/remotes/*. This patch removes the "refs/remotes/*" requirement for upstream branches, and replaces it with explicit checking of the refspecs for each remote to determine whether a given --track argument is a valid remote-tracking branch. This solves both of the above problems, since the matching refspec guarantees that there is a both a remote name and a remote branch name that can be used for the upstream config. However, this means that refs located within refs/remotes/* without a corresponding remote/refspec will no longer be usable as upstreams. The few existing tests which depended on this behavioral quirk has already been fixed in the preceding patches. This patch fixes the last remaining test failure in t2024-checkout-dwim. Signed-off-by: Johan Herland <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 983b17d commit 41c21f2

File tree

3 files changed

+18
-3
lines changed

3 files changed

+18
-3
lines changed

branch.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,21 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
197197
return 1;
198198
}
199199

200+
static int check_tracking_branch(struct remote *remote, void *cb_data)
201+
{
202+
char *tracking_branch = cb_data;
203+
struct refspec query;
204+
memset(&query, 0, sizeof(struct refspec));
205+
query.dst = tracking_branch;
206+
return !(remote_find_tracking(remote, &query) ||
207+
prefixcmp(query.src, "refs/heads/"));
208+
}
209+
210+
static int validate_remote_tracking_branch(char *ref)
211+
{
212+
return !for_each_remote(check_tracking_branch, ref);
213+
}
214+
200215
static const char upstream_not_branch[] =
201216
N_("Cannot setup tracking information; starting point '%s' is not a branch.");
202217
static const char upstream_missing[] =
@@ -259,7 +274,7 @@ void create_branch(const char *head,
259274
case 1:
260275
/* Unique completion -- good, only if it is a real branch */
261276
if (prefixcmp(real_ref, "refs/heads/") &&
262-
prefixcmp(real_ref, "refs/remotes/")) {
277+
validate_remote_tracking_branch(real_ref)) {
263278
if (explicit_tracking)
264279
die(_(upstream_not_branch), start_name);
265280
else

t/t2024-checkout-dwim.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ test_expect_success 'checkout of branch from a single remote succeeds #3' '
154154
test_branch_upstream spam repo_c spam
155155
'
156156

157-
test_expect_failure 'checkout of branch from a single remote succeeds #4' '
157+
test_expect_success 'checkout of branch from a single remote succeeds #4' '
158158
git checkout -B master &&
159159
test_might_fail git branch -D eggs &&
160160

t/t3200-branch.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '
317317
test $(git config branch.my4.merge) = refs/heads/master
318318
'
319319

320-
test_expect_failure 'tracking setup fails on non-matching refspec' '
320+
test_expect_success 'tracking setup fails on non-matching refspec' '
321321
git config remote.local.url . &&
322322
git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
323323
(git show-ref -q refs/remotes/local/master || git fetch local) &&

0 commit comments

Comments
 (0)