branch: make create_branch() always create a branch

With the previous commit, there are no more invocations of
create_branch() that do not create a branch because:

* BRANCH_TRACK_OVERRIDE is no longer passed
* clobber_head_ok = true and force = false is never passed

Assert these situations, delete dead code and ensure that we're handling
clobber_head_ok and force correctly by introducing tests for `git branch
--force`. As a result, create_branch() now always creates a branch.

Helped-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Glen Choo <chooglen@google.com>
Reviewed-by: Jonathan Tan <jonathantanmy@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Glen Choo 2022-01-28 16:04:42 -08:00 committed by Junio C Hamano
parent e89f151db1
commit bc0893cf3b
3 changed files with 45 additions and 31 deletions

View File

@ -429,15 +429,19 @@ void create_branch(struct repository *r,
char *real_ref; char *real_ref;
struct strbuf ref = STRBUF_INIT; struct strbuf ref = STRBUF_INIT;
int forcing = 0; int forcing = 0;
int dont_change_ref = 0; struct ref_transaction *transaction;
struct strbuf err = STRBUF_INIT;
char *msg;


if ((track == BRANCH_TRACK_OVERRIDE || clobber_head_ok) if (track == BRANCH_TRACK_OVERRIDE)
? validate_branchname(name, &ref) BUG("'track' cannot be BRANCH_TRACK_OVERRIDE. Did you mean to call dwim_and_setup_tracking()?");
: validate_new_branchname(name, &ref, force)) { if (clobber_head_ok && !force)
if (!force) BUG("'clobber_head_ok' can only be used with 'force'");
dont_change_ref = 1;
else if (clobber_head_ok ?
forcing = 1; validate_branchname(name, &ref) :
validate_new_branchname(name, &ref, force)) {
forcing = 1;
} }


dwim_branch_start(r, start_name, track, &real_ref, &oid); dwim_branch_start(r, start_name, track, &real_ref, &oid);
@ -445,27 +449,20 @@ void create_branch(struct repository *r,
if (reflog) if (reflog)
log_all_ref_updates = LOG_REFS_NORMAL; log_all_ref_updates = LOG_REFS_NORMAL;


if (!dont_change_ref) { if (forcing)
struct ref_transaction *transaction; msg = xstrfmt("branch: Reset to %s", start_name);
struct strbuf err = STRBUF_INIT; else
char *msg; msg = xstrfmt("branch: Created from %s", start_name);

transaction = ref_transaction_begin(&err);
if (forcing) if (!transaction ||
msg = xstrfmt("branch: Reset to %s", start_name); ref_transaction_update(transaction, ref.buf,
else &oid, forcing ? NULL : null_oid(),
msg = xstrfmt("branch: Created from %s", start_name); 0, msg, &err) ||

ref_transaction_commit(transaction, &err))
transaction = ref_transaction_begin(&err); die("%s", err.buf);
if (!transaction || ref_transaction_free(transaction);
ref_transaction_update(transaction, ref.buf, strbuf_release(&err);
&oid, forcing ? NULL : null_oid(), free(msg);
0, msg, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
ref_transaction_free(transaction);
strbuf_release(&err);
free(msg);
}


if (real_ref && track) if (real_ref && track)
setup_tracking(ref.buf + 11, real_ref, track, quiet); setup_tracking(ref.buf + 11, real_ref, track, quiet);

View File

@ -52,8 +52,8 @@ void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
* *
* - force enables overwriting an existing (non-head) branch * - force enables overwriting an existing (non-head) branch
* *
* - clobber_head_ok allows the currently checked out (hence existing) * - clobber_head_ok, when enabled with 'force', allows the currently
* branch to be overwritten; without 'force', it has no effect. * checked out (head) branch to be overwritten
* *
* - reflog creates a reflog for the branch * - reflog creates a reflog for the branch
* *

View File

@ -42,6 +42,23 @@ test_expect_success 'git branch abc should create a branch' '
git branch abc && test_path_is_file .git/refs/heads/abc git branch abc && test_path_is_file .git/refs/heads/abc
' '


test_expect_success 'git branch abc should fail when abc exists' '
test_must_fail git branch abc
'

test_expect_success 'git branch --force abc should fail when abc is checked out' '
test_when_finished git switch main &&
git switch abc &&
test_must_fail git branch --force abc HEAD~1
'

test_expect_success 'git branch --force abc should succeed when abc exists' '
git rev-parse HEAD~1 >expect &&
git branch --force abc HEAD~1 &&
git rev-parse abc >actual &&
test_cmp expect actual
'

test_expect_success 'git branch a/b/c should create a branch' ' test_expect_success 'git branch a/b/c should create a branch' '
git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c
' '