Signed-off-by: Tay Ray Chuan <rctay89@xxxxxxxxx> --- Documentation/git-checkout.txt | 15 +++++++++++- builtin/checkout.c | 7 ++++- t/t2018-checkout-branch.sh | 45 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 261dd90..5849e13 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -9,7 +9,7 @@ SYNOPSIS -------- [verse] 'git checkout' [-q] [-f] [-m] [<branch>] -'git checkout' [-q] [-f] [-m] [[-b|--orphan] <new_branch>] [<start_point>] +'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>... 'git checkout' --patch [<tree-ish>] [--] [<paths>...] @@ -21,7 +21,7 @@ also update `HEAD` to set the specified branch as the current branch. 'git checkout' [<branch>]:: -'git checkout' -b <new branch> [<start point>]:: +'git checkout' -b|-B <branch> [<start point>]:: This form switches branches by updating the index, working tree, and HEAD to reflect the specified branch. @@ -31,6 +31,13 @@ were called and then checked out; in this case you can use the `--track` or `--no-track` options, which will be passed to 'git branch'. As a convenience, `--track` without `-b` implies branch creation; see the description of `--track` below. ++ +If `-B` is given, <branch> is created if it doesn't exist; otherwise, it +is reset. This is equivalent to ++ +------------ +$ git branch -f <branch> [<start point>] && git checkout <branch> +------------ 'git checkout' [--patch] [<tree-ish>] [--] <pathspec>...:: @@ -75,6 +82,10 @@ entries; instead, unmerged entries are ignored. Create a new branch named <new_branch> and start it at <start_point>; see linkgit:git-branch[1] for details. +-B:: + Checks out to the branch named <branch>, creating it if it does + not exist; otherwise, the branch is reset. + -t:: --track:: When creating a new branch, set up "upstream" configuration. See diff --git a/builtin/checkout.c b/builtin/checkout.c index e794e1e..f7c2cdd 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -512,7 +512,8 @@ static void update_refs_for_switch(struct checkout_opts *opts, } } else - create_branch(old->name, opts->new_branch_name, new->name, 0, + create_branch(old->name, opts->new_branch_name, new->name, + opts->new_branch > 1, opts->new_branch_log, opts->track); new->name = opts->new_branch_name; setup_branch_path(new); @@ -660,6 +661,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) OPT__QUIET(&opts.quiet), OPT_SET_INT('b', NULL, &opts.new_branch, "create and checkout a new branch", 1), + OPT_SET_INT('B', NULL, &opts.new_branch, + "create and checkout a branch, resetting it if it exists", 2), OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"), OPT_SET_INT('t', "track", &opts.track, "track", BRANCH_TRACK_EXPLICIT), @@ -869,7 +872,7 @@ no_reference: if (strbuf_check_branch_ref(&buf, opts.new_branch_name)) die("git checkout: we do not like '%s' as a branch name.", opts.new_branch_name); - if (!get_sha1(buf.buf, rev)) + if (!get_sha1(buf.buf, rev) && !(opts.new_branch > 1)) die("git checkout: branch %s already exists", opts.new_branch_name); strbuf_release(&buf); } diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh index 3c13065..1caffea 100755 --- a/t/t2018-checkout-branch.sh +++ b/t/t2018-checkout-branch.sh @@ -118,4 +118,49 @@ test_expect_success 'checkout -b to an existing branch fails' ' test_must_fail do_checkout branch2 $HEAD2 ' +test_expect_success 'checkout -B to an existing branch resets branch to HEAD' ' + git checkout branch1 && + + do_checkout branch2 "" -B +' + +test_expect_success 'checkout -B to an existing branch with an explicit ref resets branch to that ref' ' + git checkout branch1 && + + do_checkout branch2 $HEAD1 -B +' + +test_expect_success 'checkout -B to an existing branch with unmergeable changes fails' ' + git checkout branch1 && + + setup_dirty_unmergeable && + test_must_fail do_checkout branch2 $HEAD1 -B && + test_dirty_unmergeable +' + +test_expect_success 'checkout -f -B to an existing branch with unmergeable changes discards changes' ' + # still dirty and on branch1 + do_checkout branch2 $HEAD1 "-f -B" && + test_must_fail test_dirty_unmergeable +' + +test_expect_success 'checkout -B to an existing branch preserves mergeable changes' ' + git checkout branch1 && + + setup_dirty_mergeable && + do_checkout branch2 $HEAD1 -B && + test_dirty_mergeable +' + +test_expect_success 'checkout -f -B to an existing branch with mergeable changes discards changes' ' + # clean up from previous test + git reset --hard && + + git checkout branch1 && + + setup_dirty_mergeable && + do_checkout branch2 $HEAD1 "-f -B" && + test_must_fail test_dirty_mergeable +' + test_done -- 1.7.1.513.g4f18 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html