aboutsummaryrefslogtreecommitdiff
path: root/builtin
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2011-01-11 15:00:38 -0500
committerJunio C Hamano <gitster@pobox.com>2011-01-11 13:14:56 -0800
commit0cb6ad3c3d8e9c738686ef8dc6f173f725e509bc (patch)
treec218deb54009b1f59a959103a0390fc7d330f2a7 /builtin
parent6e97ef31ce20ff93a4cc0e3c6ab5171fd6dda5f3 (diff)
downloadgit-0cb6ad3c3d8e9c738686ef8dc6f173f725e509bc.tar.gz
git-0cb6ad3c3d8e9c738686ef8dc6f173f725e509bc.tar.xz
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin')
-rw-r--r--builtin/checkout.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/builtin/checkout.c b/builtin/checkout.c
index a54583b3a..953abdd0f 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);