Merge "checkout ambiguous ref bugfix" into maint
authorJunio C Hamano <gitster@pobox.com>
Fri, 1 Apr 2011 23:16:23 +0000 (16:16 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 1 Apr 2011 23:16:51 +0000 (16:16 -0700)
* commit '0cb6ad3':
checkout: fix bug with ambiguous refs

1  2 
builtin/checkout.c
t/t2019-checkout-ambiguous-ref.sh
diff --combined builtin/checkout.c
index cd7f56e6c4b6e1b1059ffa0eae91b46e579b9e97,953abdd0fae5345676806570951a325862148ebc..e98576f22ee3aeb9caef3b18b3775b5aabb7da4b
@@@ -161,7 -161,7 +161,7 @@@ static int checkout_merged(int pos, str
         * merge.renormalize set, too
         */
        status = ll_merge(&result_buf, path, &ancestor, "base",
 -                        &ours, "ours", &theirs, "theirs", 0);
 +                        &ours, "ours", &theirs, "theirs", NULL);
        free(ancestor.ptr);
        free(ours.ptr);
        free(theirs.ptr);
@@@ -404,7 -404,7 +404,7 @@@ static int merge_working_tree(struct ch
                topts.dir->exclude_per_dir = ".gitignore";
                tree = parse_tree_indirect(old->commit ?
                                           old->commit->object.sha1 :
 -                                         (unsigned char *)EMPTY_TREE_SHA1_BIN);
 +                                         EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(new->commit->object.sha1);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
@@@ -678,7 -678,7 +678,7 @@@ static const char *unique_tracking_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;
        int patch_mode = 0;
        int dwim_new_local_branch = 1;
        struct option options[] = {
 -              OPT__QUIET(&opts.quiet),
 +              OPT__QUIET(&opts.quiet, "suppress progress reporting"),
                OPT_STRING('b', NULL, &opts.new_branch, "branch",
                           "create and checkout a new branch"),
                OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
                            2),
                OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
                            3),
 -              OPT_BOOLEAN('f', "force", &opts.force, "force checkout (throw away local modifications)"),
 +              OPT__FORCE(&opts.force, "force checkout (throw away local modifications)"),
                OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
         *   between A and B, A...B names that merge base.
         *
         *   With no paths, if <something> is _not_ a commit, no -t nor -b
 -       *   was given, and there is a tracking branch whose name is
 +       *   was given, and there is a remote-tracking branch whose name is
         *   <something> in one and only one remote, then this is a short-hand
 -       *   to fork local <something> from that remote tracking branch.
 +       *   to fork local <something> from that remote-tracking branch.
         *
         *   Otherwise <something> shall not be ambiguous.
         *   - If it's *only* a reference, treat it like case (1).
                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);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..943541d40d7ea331dd0ae85624a33b9f2258246c
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,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