git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCHv2 7/8] branch.c: Validate tracking branches with refspecs instead of refs/remotes/*

From
Johan Herland <johan@herland.net>
Date
Apr 20, 2013, 15:06 UTC
Message-ID
<1366470363-22309-8-git-send-email-johan@herland.net>
In-Reply-To
<1366470363-22309-1-git-send-email-johan@herland.net>

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>
---
 branch.c                 | 17 ++++++++++++++++-
 t/t2024-checkout-dwim.sh |  2 +-
 t/t3200-branch.sh        |  2 +-
 3 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/branch.c b/branch.c
index 6ae6a4c..beaf11d 100644
--- a/branch.c
+++ b/branch.c
@@ -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[] =
@@ -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
diff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh
index fc6edc9..a8f0a90 100755
--- a/t/t2024-checkout-dwim.sh
+++ b/t/t2024-checkout-dwim.sh
@@ -108,7 +108,7 @@ test_expect_success 'checkout of branch from a single remote succeeds #3' '
 	test_tracking_branch spam repo_c refs/remotes/extra_dir/repo_c/extra_dir/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 eggs &&
 	test_tracking_branch eggs repo_d refs/repo_d/eggs
 '
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 1bfdadc..44ec6a4 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -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) &&
-- 
1.8.1.3.704.g33f7d4f
Previous: Eric WongNext: Johan Herland
Message 11 of 12 in “[PATCHv2 0/8] Improving the search for remote-tracking branches”
  1. Johan HerlandApr 20, 2013
  2. 1/8 t2024: Add tests verifying current DWIM behavior of 'git checkout <branch>'Johan Herland, Apr 20, 2013
  3. Jonathan NiederApr 20, 2013
  4. Johan HerlandApr 20, 2013
  5. 2/8 t2024: Show failure to use refspec when DWIMming remote branch namesJohan Herland, Apr 20, 2013
  6. 3/8 checkout: Use remote refspecs when DWIMming tracking branchesJohan Herland, Apr 20, 2013
  7. 4/8 t3200.39: tracking setup should fail if there is no matching refspec.Johan Herland, Apr 20, 2013
  8. 5/8 t7201.24: Add refspec to keep --track workingJohan Herland, Apr 20, 2013
  9. 6/8 t9114.2: Don't use --track option against "svn-remote"-tracking branchesJohan Herland, Apr 20, 2013
  10. Eric WongApr 21, 2013
  11. 7/8 branch.c: Validate tracking branches with refspecs instead of refs/remotes/*Johan Herland, Apr 20, 2013
  12. 8/8 glossary: Update and rephrase the definition of a remote-tracking branchJohan Herland, Apr 20, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.