diff mbox series

[v6,2/5] branch: make create_branch() always create a branch

Message ID 20211220233459.45739-3-chooglen@google.com (mailing list archive)
State New, archived
Headers show
Series implement branch --recurse-submodules | expand

Commit Message

Glen Choo Dec. 20, 2021, 11:34 p.m. UTC
create_branch() was formerly used to set tracking without creating a
branch. Since the previous commit replaces this use case with
dwim_and_setup_tracking(), we can simplify create_branch() so that it
always creates a branch.

Do this simplification, in particular:

* remove the special handling of BRANCH_TRACK_OVERRIDE because it is no
  longer used
* assert that clobber_head_ok can only be provided with force
* check that we're handling clobber_head_ok and force correctly by
  introducing tests for `git branch --force`

Signed-off-by: Glen Choo <chooglen@google.com>
---
 branch.c          | 55 +++++++++++++++++++++--------------------------
 branch.h          |  4 ++--
 t/t3200-branch.sh | 17 +++++++++++++++
 3 files changed, 44 insertions(+), 32 deletions(-)

Comments

Jonathan Tan Jan. 11, 2022, 2:19 a.m. UTC | #1
Glen Choo <chooglen@google.com> writes:
> create_branch() was formerly used to set tracking without creating a
> branch. Since the previous commit replaces this use case with
> dwim_and_setup_tracking(), we can simplify create_branch() so that it
> always creates a branch.
> 
> Do this simplification, in particular:
> 
> * remove the special handling of BRANCH_TRACK_OVERRIDE because it is no
>   longer used
> * assert that clobber_head_ok can only be provided with force
> * check that we're handling clobber_head_ok and force correctly by
>   introducing tests for `git branch --force`

This might have been more simply explained as:

  With the previous commit, these are true of create_branch():
   * BRANCH_TRACK_OVERRIDE is no longer passed
   * if clobber_head_ok is true, force is also true

  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`. This also means that create_branch() now always
  creates a branch.

> @@ -426,15 +426,17 @@ void create_branch(struct repository *r, const char *name,
>  	char *real_ref;
>  	struct strbuf ref = STRBUF_INIT;
>  	int forcing = 0;
> -	int dont_change_ref = 0;
> -
> -	if ((track == BRANCH_TRACK_OVERRIDE || clobber_head_ok)
> -	    ? validate_branchname(name, &ref)
> -	    : validate_new_branchname(name, &ref, force)) {
> -		if (!force)
> -			dont_change_ref = 1;
> -		else
> -			forcing = 1;
> +	struct ref_transaction *transaction;
> +	struct strbuf err = STRBUF_INIT;
> +	char *msg;
> +
> +	if (clobber_head_ok && !force)
> +		BUG("'clobber_head_ok' can only be used with 'force'");
> +
> +	if (clobber_head_ok ?
> +			  validate_branchname(name, &ref) :
> +			  validate_new_branchname(name, &ref, force)) {
> +		forcing = 1;
>  	}

Also assert that track is not BRANCH_TRACK_OVERRIDE.

> @@ -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
>  '
>  
> +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
> +'

These tests make sense.
Glen Choo Jan. 11, 2022, 5:51 p.m. UTC | #2
Jonathan Tan <jonathantanmy@google.com> writes:

> Glen Choo <chooglen@google.com> writes:
>> create_branch() was formerly used to set tracking without creating a
>> branch. Since the previous commit replaces this use case with
>> dwim_and_setup_tracking(), we can simplify create_branch() so that it
>> always creates a branch.
>> 
>> Do this simplification, in particular:
>> 
>> * remove the special handling of BRANCH_TRACK_OVERRIDE because it is no
>>   longer used
>> * assert that clobber_head_ok can only be provided with force
>> * check that we're handling clobber_head_ok and force correctly by
>>   introducing tests for `git branch --force`
>
> This might have been more simply explained as:
>
>   With the previous commit, these are true of create_branch():
>    * BRANCH_TRACK_OVERRIDE is no longer passed
>    * if clobber_head_ok is true, force is also true
>
>   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`. This also means that create_branch() now always
>   creates a branch.

This is a great suggestion, I'll incorporate some of this.

As an aside, it has always been the case that clobber_head_ok is only true
when force is true, so it might be misleading to include it under the
umbrella of 'With the previous commit'. I'll move things around
accordingly.

>> @@ -426,15 +426,17 @@ void create_branch(struct repository *r, const char *name,
>>  	char *real_ref;
>>  	struct strbuf ref = STRBUF_INIT;
>>  	int forcing = 0;
>> -	int dont_change_ref = 0;
>> -
>> -	if ((track == BRANCH_TRACK_OVERRIDE || clobber_head_ok)
>> -	    ? validate_branchname(name, &ref)
>> -	    : validate_new_branchname(name, &ref, force)) {
>> -		if (!force)
>> -			dont_change_ref = 1;
>> -		else
>> -			forcing = 1;
>> +	struct ref_transaction *transaction;
>> +	struct strbuf err = STRBUF_INIT;
>> +	char *msg;
>> +
>> +	if (clobber_head_ok && !force)
>> +		BUG("'clobber_head_ok' can only be used with 'force'");
>> +
>> +	if (clobber_head_ok ?
>> +			  validate_branchname(name, &ref) :
>> +			  validate_new_branchname(name, &ref, force)) {
>> +		forcing = 1;
>>  	}
>
> Also assert that track is not BRANCH_TRACK_OVERRIDE.

Makes sense, I'll do that.
diff mbox series

Patch

diff --git a/branch.c b/branch.c
index e271a4e0a7..de680f311d 100644
--- a/branch.c
+++ b/branch.c
@@ -426,15 +426,17 @@  void create_branch(struct repository *r, const char *name,
 	char *real_ref;
 	struct strbuf ref = STRBUF_INIT;
 	int forcing = 0;
-	int dont_change_ref = 0;
-
-	if ((track == BRANCH_TRACK_OVERRIDE || clobber_head_ok)
-	    ? validate_branchname(name, &ref)
-	    : validate_new_branchname(name, &ref, force)) {
-		if (!force)
-			dont_change_ref = 1;
-		else
-			forcing = 1;
+	struct ref_transaction *transaction;
+	struct strbuf err = STRBUF_INIT;
+	char *msg;
+
+	if (clobber_head_ok && !force)
+		BUG("'clobber_head_ok' can only be used with 'force'");
+
+	if (clobber_head_ok ?
+			  validate_branchname(name, &ref) :
+			  validate_new_branchname(name, &ref, force)) {
+		forcing = 1;
 	}
 
 	dwim_branch_start(r, start_name, track, &real_ref, &oid);
@@ -442,27 +444,20 @@  void create_branch(struct repository *r, const char *name,
 	if (reflog)
 		log_all_ref_updates = LOG_REFS_NORMAL;
 
-	if (!dont_change_ref) {
-		struct ref_transaction *transaction;
-		struct strbuf err = STRBUF_INIT;
-		char *msg;
-
-		if (forcing)
-			msg = xstrfmt("branch: Reset to %s", start_name);
-		else
-			msg = xstrfmt("branch: Created from %s", start_name);
-
-		transaction = ref_transaction_begin(&err);
-		if (!transaction ||
-		    ref_transaction_update(transaction, ref.buf,
-					   &oid, forcing ? NULL : null_oid(),
-					   0, msg, &err) ||
-		    ref_transaction_commit(transaction, &err))
-			die("%s", err.buf);
-		ref_transaction_free(transaction);
-		strbuf_release(&err);
-		free(msg);
-	}
+	if (forcing)
+		msg = xstrfmt("branch: Reset to %s", start_name);
+	else
+		msg = xstrfmt("branch: Created from %s", start_name);
+	transaction = ref_transaction_begin(&err);
+	if (!transaction ||
+		ref_transaction_update(transaction, ref.buf,
+					&oid, forcing ? NULL : null_oid(),
+					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)
 		setup_tracking(ref.buf + 11, real_ref, track, quiet);
diff --git a/branch.h b/branch.h
index ab2315c611..cf3a4d3ff3 100644
--- a/branch.h
+++ b/branch.h
@@ -52,8 +52,8 @@  void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
  *
  *   - force enables overwriting an existing (non-head) branch
  *
- *   - clobber_head_ok allows the currently checked out (hence existing)
- *     branch to be overwritten; without 'force', it has no effect.
+ *   - clobber_head_ok, when enabled with 'force', allows the currently
+ *     checked out (head) branch to be overwritten
  *
  *   - reflog creates a reflog for the branch
  *
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 09ab132377..71a72efcb2 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -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
 '
 
+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' '
 	git branch a/b/c && test_path_is_file .git/refs/heads/a/b/c
 '