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>
This commit is contained in:
Junio C Hamano
2011-01-11 15:00:38 -05:00
parent 6e97ef31ce
commit 0cb6ad3c3d
2 changed files with 72 additions and 10 deletions

View File

@ -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);