Merge branch 'db/maint-checkout-b'
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Sep 2008 06:50:05 +0000 (23:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Sep 2008 06:50:05 +0000 (23:50 -0700)
* db/maint-checkout-b:
Check early that a new branch is new and valid

1  2 
builtin-checkout.c
t/t7201-co.sh
diff --combined builtin-checkout.c
index 9377a1c71ea8571d3e36e9e19aa322db765e93c8,1ee23468ff27de8f8d35c15ce6b10ac11995c0f9..4497b7092d0e88aa731c64c0f22bf0d05ead0411
@@@ -184,7 -184,7 +184,7 @@@ struct checkout_opts 
        int force;
        int writeout_error;
  
 -      char *new_branch;
 +      const char *new_branch;
        int new_branch_log;
        enum branch_track track;
  };
@@@ -464,28 -464,13 +464,28 @@@ int cmd_checkout(int argc, const char *
  
        git_config(git_default_config, NULL);
  
 -      opts.track = git_branch_track;
 +      opts.track = BRANCH_TRACK_UNSPECIFIED;
  
        argc = parse_options(argc, argv, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
  
 -      if (!opts.new_branch && (opts.track != git_branch_track))
 -              die("git checkout: --track and --no-track require -b");
 +      /* --track without -b should DWIM */
 +      if (0 < opts.track && !opts.new_branch) {
 +              const char *argv0 = argv[0];
 +              if (!argc || !strcmp(argv0, "--"))
 +                      die ("--track needs a branch name");
 +              if (!prefixcmp(argv0, "refs/"))
 +                      argv0 += 5;
 +              if (!prefixcmp(argv0, "remotes/"))
 +                      argv0 += 8;
 +              argv0 = strchr(argv0, '/');
 +              if (!argv0 || !argv0[1])
 +                      die ("Missing branch name; try -b");
 +              opts.new_branch = argv0 + 1;
 +      }
 +
 +      if (opts.track == BRANCH_TRACK_UNSPECIFIED)
 +              opts.track = git_branch_track;
  
        if (opts.force && opts.merge)
                die("git checkout: -f and -m are incompatible");
@@@ -580,6 -565,18 +580,18 @@@ no_reference
                return checkout_paths(source_tree, pathspec);
        }
  
+       if (opts.new_branch) {
+               struct strbuf buf;
+               strbuf_init(&buf, 0);
+               strbuf_addstr(&buf, "refs/heads/");
+               strbuf_addstr(&buf, opts.new_branch);
+               if (!get_sha1(buf.buf, rev))
+                       die("git checkout: branch %s already exists", opts.new_branch);
+               if (check_ref_format(buf.buf))
+                       die("git checkout: we do not like '%s' as a branch name.", opts.new_branch);
+               strbuf_release(&buf);
+       }
        if (new.name && !new.commit) {
                die("Cannot switch branch to a non-commit.");
        }
diff --combined t/t7201-co.sh
index 25181388f8a8f1730d05fce128e0e1fc66eb3c0e,0679abd29d907944c5c246275adfcd760f001d55..62d73f934a0c0be2d41a30d11308430838f6c9c0
@@@ -337,38 -337,6 +337,38 @@@ test_expect_success 
      test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
      test_must_fail git checkout --track -b track'
  
 +test_expect_success \
 +    'checkout with --track fakes a sensible -b <name>' '
 +    git update-ref refs/remotes/origin/koala/bear renamer &&
 +    git update-ref refs/new/koala/bear renamer &&
 +
 +    git checkout --track origin/koala/bear &&
 +    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 +    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 +
 +    git checkout master && git branch -D koala/bear &&
 +
 +    git checkout --track refs/remotes/origin/koala/bear &&
 +    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 +    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 +
 +    git checkout master && git branch -D koala/bear &&
 +
 +    git checkout --track remotes/origin/koala/bear &&
 +    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 +    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
 +
 +    git checkout master && git branch -D koala/bear &&
 +
 +    git checkout --track refs/new/koala/bear &&
 +    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
 +    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
 +'
 +
 +test_expect_success \
 +    'checkout with --track, but without -b, fails with too short tracked name' '
 +    test_must_fail git checkout --track renamer'
 +
  test_expect_success 'checkout an unmerged path should fail' '
        rm -f .git/index &&
        O=$(echo original | git hash-object -w --stdin) &&
        test_cmp sample file
  '
  
+ test_expect_success 'failing checkout -b should not break working tree' '
+       git reset --hard master &&
+       git symbolic-ref HEAD refs/heads/master &&
+       test_must_fail git checkout -b renamer side^ &&
+       test $(git symbolic-ref HEAD) = refs/heads/master &&
+       git diff --exit-code &&
+       git diff --cached --exit-code
+ '
  test_done