Allow checkout -B <current-branch> to update the current branch

When on master, "git checkout -B master <commit>" is a more natural way to say "git reset --keep <commit>", which was originally invented for the exact purpose of moving to the named commit while keeping the local changes around. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Nieder committed Nov 26, 2011 at 02:54 UTC 39bd6f726109942c6f77f59638f6763c9f00706c
5 files changed +23 -12
branch.c
+4 -2
@@ -160,7 +160,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
160
161 void create_branch(const char *head,
162 const char *name, const char *start_name,
163 - int force, int reflog, enum branch_track track)
163 + int force, int reflog, int clobber_head,
164 + enum branch_track track)
165 {
166 struct ref_lock *lock = NULL;
167 struct commit *commit;
@@ -175,7 +176,8 @@ void create_branch(const char *head,
176 explicit_tracking = 1;
177
178 if (validate_new_branchname(name, &ref, force,
178 - track == BRANCH_TRACK_OVERRIDE)) {
179 + track == BRANCH_TRACK_OVERRIDE ||
180 + clobber_head)) {
181 if (!force)
182 dont_change_ref = 1;
183 else
branch.h
+2 -1
@@ -13,7 +13,8 @@
13 * branch for (if any).
14 */
15 void create_branch(const char *head, const char *name, const char *start_name,
16 - int force, int reflog, enum branch_track track);
16 + int force, int reflog,
17 + int clobber_head, enum branch_track track);
18
19 /*
20 * Validates that the requested branch may be created, returning the
builtin/branch.c
+1 -1
@@ -737,7 +737,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
737 if (kinds != REF_LOCAL_BRANCH)
738 die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
739 create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
740 - force_create, reflog, track);
740 + force_create, reflog, 0, track);
741 } else
742 usage_with_options(builtin_branch_usage, options);
743
builtin/checkout.c
+11 -4
@@ -540,7 +540,9 @@ static void update_refs_for_switch(struct checkout_opts *opts,
540 else
541 create_branch(old->name, opts->new_branch, new->name,
542 opts->new_branch_force ? 1 : 0,
543 - opts->new_branch_log, opts->track);
543 + opts->new_branch_log,
544 + opts->new_branch_force ? 1 : 0,
545 + opts->track);
546 new->name = opts->new_branch;
547 setup_branch_path(new);
548 }
@@ -565,8 +567,12 @@ static void update_refs_for_switch(struct checkout_opts *opts,
567 create_symref("HEAD", new->path, msg.buf);
568 if (!opts->quiet) {
569 if (old->path && !strcmp(new->path, old->path)) {
568 - fprintf(stderr, _("Already on '%s'\n"),
569 - new->name);
570 + if (opts->new_branch_force)
571 + fprintf(stderr, _("Reset branch '%s'\n"),
572 + new->name);
573 + else
574 + fprintf(stderr, _("Already on '%s'\n"),
575 + new->name);
576 } else if (opts->new_branch) {
577 if (opts->branch_exists)
578 fprintf(stderr, _("Switched to and reset branch '%s'\n"), new->name);
@@ -1057,7 +1063,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
1063 struct strbuf buf = STRBUF_INIT;
1064
1065 opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
1060 - !!opts.new_branch_force, 0);
1066 + !!opts.new_branch_force,
1067 + !!opts.new_branch_force);
1068
1069 strbuf_release(&buf);
1070 }
t/t2018-checkout-branch.sh
+5 -4
@@ -189,12 +189,13 @@ test_expect_success 'checkout -b <describe>' '
189 test_cmp expect actual
190 '
191
192 -test_expect_success 'checkout -B to the current branch fails before merging' '
192 +test_expect_success 'checkout -B to the current branch works' '
193 git checkout branch1 &&
194 + git checkout -B branch1-scratch &&
195 +
196 setup_dirty_mergeable &&
195 - git commit -mfooble &&
196 - test_must_fail git checkout -B branch1 initial &&
197 - test_must_fail test_dirty_mergeable
197 + git checkout -B branch1-scratch initial &&
198 + test_dirty_mergeable
199 '
200
201 test_done