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

Re: bug? in checkout with ambiguous refnames

From
Jeff King <peff@peff.net>
Date
Jan 11, 2011, 20:00 UTC
Message-ID
<20110111200037.GA24777@sigill.intra.peff.net>
In-Reply-To
<20110111192020.GA15608@sigill.intra.peff.net>
On Tue, Jan 11, 2011 at 02:20:20PM -0500, Jeff King wrote:
> Hmm. One other thing to note on these ambiguity tests.

I was starting to get confused with all the back-and-forth, so here is a squashed patch that contains everything discussed so far: my original tests, your squashed patches, my test fixups, and the less-subtle resolve_ref thing.

I didn't bisect the breakage, so I'm not sure how far back it goes. But this is potentially maint-worthy.

This doesn't include any tests or fixes for "git checkout -b newbranch ambiguous". I'll work on that separately as a patch on top.

-- >8 --
From: Junio C Hamano <gitster@pobox.com>
Subject: [PATCH] checkout: fix bug with ambiguous refs

The usual dwim_ref lookup prefers tags to branches. Because checkout primarily works on branches, though, we switch that behavior to prefer branches.

However, there was a bug in the implementation in which we used lookup_commit_reference (which used the regular lookup rules) to get the actual commit to checkout. Checking out an ambiguous ref therefore ended up putting us in an extremely broken state in which we wrote the branch ref into HEAD, but actually checked out the tree for the tag.

This patch fixes the bug by always attempting to pull the commit to be checked out from the branch-ified version of the name we were given.

Patch by Junio, tests and commit message from Jeff King.
Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/checkout.c               |   23 ++++++++------
 t/t2019-checkout-amiguous-ref.sh |   59 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 10 deletions(-)
 create mode 100755 t/t2019-checkout-amiguous-ref.sh
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 757f9a0..d3cfaf0 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -678,7 +678,7 @@ static const char *unique_tracking_name(const char *name)
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
 	struct checkout_opts opts;
-	unsigned char rev[20];
+	unsigned char rev[20], branch_rev[20];
 	const char *arg;
 	struct branch_info new;
 	struct tree *source_tree = NULL;
@@ -832,18 +832,21 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 		argc--;
 
 		new.name = arg;
-		if ((new.commit = lookup_commit_reference_gently(rev, 1))) {
-			setup_branch_path(&new);
+		setup_branch_path(&new);
 
-			if ((check_ref_format(new.path) == CHECK_REF_FORMAT_OK) &&
-			    resolve_ref(new.path, rev, 1, NULL))
-				;
-			else
-				new.path = NULL;
+		if (check_ref_format(new.path) == CHECK_REF_FORMAT_OK &&
+		    resolve_ref(new.path, branch_rev, 1, NULL))
+			hashcpy(rev, branch_rev);
+		else
+			new.path = NULL; /* not an existing branch */
+
+		if (!(new.commit = lookup_commit_reference_gently(rev, 1))) {
+			/* not a commit */
+			source_tree = parse_tree_indirect(rev);
+		} else {
 			parse_commit(new.commit);
 			source_tree = new.commit->tree;
-		} else
-			source_tree = parse_tree_indirect(rev);
+		}
 
 		if (!source_tree)                   /* case (1): want a tree */
 			die("reference is not a tree: %s", arg);
diff --git a/t/t2019-checkout-amiguous-ref.sh b/t/t2019-checkout-amiguous-ref.sh
new file mode 100755
index 0000000..943541d
--- /dev/null
+++ b/t/t2019-checkout-amiguous-ref.sh
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='checkout handling of ambiguous (branch/tag) refs'
+. ./test-lib.sh
+
+test_expect_success 'setup ambiguous refs' '
+	test_commit branch file &&
+	git branch ambiguity &&
+	git branch vagueness &&
+	test_commit tag file &&
+	git tag ambiguity &&
+	git tag vagueness HEAD:file &&
+	test_commit other file
+'
+
+test_expect_success 'checkout ambiguous ref succeeds' '
+	git checkout ambiguity >stdout 2>stderr
+'
+
+test_expect_success 'checkout produces ambiguity warning' '
+	grep "warning.*ambiguous" stderr
+'
+
+test_expect_success 'checkout chooses branch over tag' '
+	echo refs/heads/ambiguity >expect &&
+	git symbolic-ref HEAD >actual &&
+	test_cmp expect actual &&
+	echo branch >expect &&
+	test_cmp expect file
+'
+
+test_expect_success 'checkout reports switch to branch' '
+	grep "Switched to branch" stderr &&
+	! grep "^HEAD is now at" stderr
+'
+
+test_expect_success 'checkout vague ref succeeds' '
+	git checkout vagueness >stdout 2>stderr &&
+	test_set_prereq VAGUENESS_SUCCESS
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout produces ambiguity warning' '
+	grep "warning.*ambiguous" stderr
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout chooses branch over tag' '
+	echo refs/heads/vagueness >expect &&
+	git symbolic-ref HEAD >actual &&
+	test_cmp expect actual &&
+	echo branch >expect &&
+	test_cmp expect file
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
+	grep "Switched to branch" stderr &&
+	! grep "^HEAD is now at" stderr
+'
+
+test_done
-- 
1.7.3.5.4.g0dc52
Previous: Jeff KingNext: Martin von Zweigbergk
Message 15 of 23 in “bug? in checkout with ambiguous refnames”
  1. Uwe Kleine-KönigJan 7, 2011
  2. Junio C HamanoJan 7, 2011
  3. Jeff KingJan 7, 2011
  4. Jeff KingJan 7, 2011
  5. Junio C HamanoJan 7, 2011
  6. Junio C HamanoJan 7, 2011
  7. Jeff KingJan 11, 2011
  8. Junio C HamanoJan 11, 2011
  9. Jeff KingJan 11, 2011
  10. Jeff KingJan 12, 2011
  11. Junio C HamanoJan 12, 2011
  12. Jeff KingJan 12, 2011
  13. Jeff KingJan 11, 2011
  14. Jeff KingJan 11, 2011
  15. Jeff KingJan 11, 2011
  16. Martin von ZweigbergkJan 8, 2011
  17. Jeff KingJan 8, 2011
  18. Martin von ZweigbergkJan 9, 2011
  19. Junio C HamanoJan 9, 2011
  20. Martin von ZweigbergkJan 9, 2011
  21. Uwe Kleine-KönigJan 12, 2011
  22. Jeff KingJan 12, 2011
  23. Uwe Kleine-KönigJan 12, 2011

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.