Skip to content

Commit

Permalink
branch.c: Validate tracking branches with refspecs instead of refs/re…
Browse files Browse the repository at this point in the history
…motes/*

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 <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
jherland authored and gitster committed Apr 21, 2013
1 parent 983b17d commit 41c21f2
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 3 deletions.
17 changes: 16 additions & 1 deletion branch.c
Expand Up @@ -197,6 +197,21 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
return 1;
}

static int check_tracking_branch(struct remote *remote, void *cb_data)
{
char *tracking_branch = cb_data;
struct refspec query;
memset(&query, 0, sizeof(struct refspec));
query.dst = tracking_branch;
return !(remote_find_tracking(remote, &query) ||
prefixcmp(query.src, "refs/heads/"));
}

static int validate_remote_tracking_branch(char *ref)
{
return !for_each_remote(check_tracking_branch, ref);
}

static const char upstream_not_branch[] =
N_("Cannot setup tracking information; starting point '%s' is not a branch.");
static const char upstream_missing[] =
Expand Down Expand Up @@ -259,7 +274,7 @@ void create_branch(const char *head,
case 1:
/* Unique completion -- good, only if it is a real branch */
if (prefixcmp(real_ref, "refs/heads/") &&
prefixcmp(real_ref, "refs/remotes/")) {
validate_remote_tracking_branch(real_ref)) {
if (explicit_tracking)
die(_(upstream_not_branch), start_name);
else
Expand Down
2 changes: 1 addition & 1 deletion t/t2024-checkout-dwim.sh
Expand Up @@ -154,7 +154,7 @@ test_expect_success 'checkout of branch from a single remote succeeds #3' '
test_branch_upstream spam repo_c spam
'

test_expect_failure 'checkout of branch from a single remote succeeds #4' '
test_expect_success 'checkout of branch from a single remote succeeds #4' '
git checkout -B master &&
test_might_fail git branch -D eggs &&
Expand Down
2 changes: 1 addition & 1 deletion t/t3200-branch.sh
Expand Up @@ -317,7 +317,7 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '
test $(git config branch.my4.merge) = refs/heads/master
'

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

0 comments on commit 41c21f2

Please sign in to comment.