int force;
int writeout_error;
- char *new_branch;
+ const char *new_branch;
int new_branch_log;
enum branch_track track;
};
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");
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.");
}
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