All of lore.kernel.org
 help / color / mirror / Atom feed
* git branch -M" regression in 1.7.7?
@ 2011-11-26  0:36 ☂Josh Chia (谢任中)
  2011-11-26  2:30 ` Jonathan Nieder
  0 siblings, 1 reply; 9+ messages in thread
From: ☂Josh Chia (谢任中) @ 2011-11-26  0:36 UTC (permalink / raw)
  To: git

On git 1.7.7.3, when I try to "git branch -M master" when I'm already
on a branch 'master', I get this error message:
Cannot force update the current branch

On 1.7.6.4, the command succeeds.

Is this intended?

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git branch -M" regression in 1.7.7?
  2011-11-26  0:36 git branch -M" regression in 1.7.7? ☂Josh Chia (谢任中)
@ 2011-11-26  2:30 ` Jonathan Nieder
  2011-11-26  6:52   ` [PATCH] Test renaming a branch to itself Conrad Irwin
                     ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Jonathan Nieder @ 2011-11-26  2:30 UTC (permalink / raw)
  To: ☂Josh Chia (谢任中)
  Cc: git, Soeren Sonnenburg, Conrad Irwin

Hi,

Josh Chia (谢任中) wrote:

> On git 1.7.7.3, when I try to "git branch -M master" when I'm already
> on a branch 'master', I get this error message:
> Cannot force update the current branch
>
> On 1.7.6.4, the command succeeds.
>
> Is this intended?

Yes, but it probably wasn't a good idea.  How about this patch?

A reproduction recipe (preferrably in the form of a patch to
t/t3200-branch.sh would be welcome.

-- >8 --
Subject: treat "git branch -M master master" as a no-op again

Before v1.7.7-rc2~1^2~2 (Prevent force-updating of the current branch,
2011-08-20), commands like "git branch -M topic master" could be used
even when "master" was the current branch, with the somewhat
counterintuitive result that HEAD would point to some place new while
the index and worktree kept the content of the old commit.  This is
not a very sensible operation and the result is what almost nobody
would expect, so erroring out in this case was a good change.

However, there is one exception to the "it's usually not obvious what
it would mean to overwrite the current branch by another one" rule.
Namely:

	git branch -M master master

is clearly meant to be a no-op, even if you are on the master branch.
And in the latter case, it can be abbreviated:

	git branch -M master

This seems like a valuable exception to allow, because then "git
branch -M foo" would _always_ be allowed --- either 'foo' is not the
current branch, and it does the obvious thing, or 'foo' is the current
branch, and nothing happens.

Buildbot uses this idiom and was broken in 1.7.7 (it would emit the
message "Cannot force update the current branch").

Reported-by: Soeren Sonnenburg <sonne@debian.org>
Reported-by: Josh Chia (谢任中)
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 builtin/branch.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 51ca6a02..24f33b24 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -568,6 +568,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 	unsigned char sha1[20];
 	struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
 	int recovery = 0;
+	int clobber_head_ok;
 
 	if (!oldname)
 		die(_("cannot rename the current branch while not on any."));
@@ -583,7 +584,13 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 			die(_("Invalid branch name: '%s'"), oldname);
 	}
 
-	validate_new_branchname(newname, &newref, force, 0);
+	/*
+	 * A command like "git branch -M currentbranch currentbranch" cannot
+	 * cause the worktree to become inconsistent with HEAD, so allow it.
+	 */
+	clobber_head_ok = !strcmp(oldname, newname);
+
+	validate_new_branchname(newname, &newref, force, clobber_head_ok);
 
 	strbuf_addf(&logmsg, "Branch: renamed %s to %s",
 		 oldref.buf, newref.buf);
-- 
1.7.8.rc3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH] Test renaming a branch to itself
  2011-11-26  2:30 ` Jonathan Nieder
@ 2011-11-26  6:52   ` Conrad Irwin
  2011-11-26  6:59     ` Jonathan Nieder
  2011-11-26  7:05   ` git branch -M" regression in 1.7.7? Conrad Irwin
  2011-11-28 19:38   ` Junio C Hamano
  2 siblings, 1 reply; 9+ messages in thread
From: Conrad Irwin @ 2011-11-26  6:52 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: git, Soeren Sonnenburg,
	☂Josh Chia (谢任中),
	Conrad Irwin

Test for a regression introduced in v1.7.7-rc2~1^2~2.

Requested-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Conrad Irwin <conrad.irwin@gmail.com>
---
 t/t3200-branch.sh |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index bc73c20..7690332 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -115,6 +115,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
 	git branch -M baz bam
 '
 
+test_expect_success 'git branch -M master should work when master is checked out' '
+	git checkout master &&
+	git branch -M master
+'
+
+test_expect_success 'git branch -M master master should work when master is checked out' '
+	git checkout master &&
+	git branch -M master master
+'
+
+test_expect_success 'git branch -M master2 master2 should work when master is checked out' '
+	git checkout master &&
+	git branch master2 &&
+	git branch -M master2 master2
+'
+
 test_expect_success 'git branch -v -d t should work' '
 	git branch t &&
 	test_path_is_file .git/refs/heads/t &&
-- 
1.7.7.1.433.ga2d04a

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH] Test renaming a branch to itself
  2011-11-26  6:52   ` [PATCH] Test renaming a branch to itself Conrad Irwin
@ 2011-11-26  6:59     ` Jonathan Nieder
  0 siblings, 0 replies; 9+ messages in thread
From: Jonathan Nieder @ 2011-11-26  6:59 UTC (permalink / raw)
  To: Conrad Irwin
  Cc: git, Soeren Sonnenburg, ☂Josh Chia (谢任中)

Conrad Irwin wrote:

> Test for a regression introduced in v1.7.7-rc2~1^2~2.

Thanks!  I take it that means you like the patch. :)

The tests look sane fwiw (and it looks like the tests you wrote before
cover the "branch -M" safety valve pretty well).

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git branch -M" regression in 1.7.7?
  2011-11-26  2:30 ` Jonathan Nieder
  2011-11-26  6:52   ` [PATCH] Test renaming a branch to itself Conrad Irwin
@ 2011-11-26  7:05   ` Conrad Irwin
  2011-11-26  8:54     ` Jonathan Nieder
  2011-11-28 19:38   ` Junio C Hamano
  2 siblings, 1 reply; 9+ messages in thread
From: Conrad Irwin @ 2011-11-26  7:05 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: ☂Josh Chia (谢任中), git, Soeren Sonnenburg

On Fri, Nov 25, 2011 at 6:30 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:
> A reproduction recipe (preferrably in the form of a patch to
> t/t3200-branch.sh would be welcome.

Sent in a separate email. Feel free to add a "Tested-by:" header to
your patch if you want :).

>
> -- >8 --
> Subject: treat "git branch -M master master" as a no-op again
>
> Before v1.7.7-rc2~1^2~2 (Prevent force-updating of the current branch,
> 2011-08-20), commands like "git branch -M topic master" could be used
> even when "master" was the current branch, with the somewhat
> counterintuitive result that HEAD would point to some place new while
> the index and worktree kept the content of the old commit.  This is
> not a very sensible operation and the result is what almost nobody
> would expect, so erroring out in this case was a good change.
>
> However, there is one exception to the "it's usually not obvious what
> it would mean to overwrite the current branch by another one" rule.
> Namely:
>
>        git branch -M master master
>
> is clearly meant to be a no-op, even if you are on the master branch.

Agreed. I thought after reading your patch about making it just do:

    if (!strcmp(oldname, newname))
        exit(0);

but I guess it would then not mark an entry in the reflog that people
could be relying on...

> +       clobber_head_ok = !strcmp(oldname, newname);
> +
> +       validate_new_branchname(newname, &newref, force, clobber_head_ok);

This looks ok, and will be improvable if the NEEDSWORK in branch.h is done.

The other thing I wonder is whether "git checkout -B master HEAD" or
"git branch -f master master" should have the same short-cut?

Conrad

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git branch -M" regression in 1.7.7?
  2011-11-26  7:05   ` git branch -M" regression in 1.7.7? Conrad Irwin
@ 2011-11-26  8:54     ` Jonathan Nieder
  2011-11-26 22:38       ` Junio C Hamano
  0 siblings, 1 reply; 9+ messages in thread
From: Jonathan Nieder @ 2011-11-26  8:54 UTC (permalink / raw)
  To: Conrad Irwin
  Cc: ☂Josh Chia (谢任中), git, Soeren Sonnenburg

Conrad Irwin wrote:

> I thought after reading your patch about making it just do:
>
>     if (!strcmp(oldname, newname))
>         exit(0);
>
> but I guess it would then not mark an entry in the reflog that people
> could be relying on...

Ah, this deserves a comment.

I thought about doing the same thing, and then didn't do it because I
wanted to make sure that

	git branch -M nonexistent nonexistent

does not succeed.  Which presumably warrants another test:

 test_expect_success "rename-to-self dwimery doesn't hide nonexistent ref" '
	test_must_fail git branch -M nonexistent nonexistent &&
	test_must_fail git rev-parse --verify nonexistent
 '

Sloppy of me.

>> +       clobber_head_ok = !strcmp(oldname, newname);
>> +
>> +       validate_new_branchname(newname, &newref, force, clobber_head_ok);
>
> This looks ok, and will be improvable if the NEEDSWORK in branch.h is done.

Thanks for looking it over.

> The other thing I wonder is whether "git checkout -B master HEAD" or
> "git branch -f master master" should have the same short-cut?

I think "git branch -M" is the only one buildbot was relying on.

As an aside, I'm not convinced the check is needed for checkout -B at
all.  In an ideal world, the order of operations would be:

	1. look up commit argument
	2. merge working tree
	3. update branch to match commit
	4. update HEAD symref to point to branch

In other words, when on master, "git checkout -B master <commit>"
would be another way to say "git reset --keep <commit>", except that
it also sets up tracking.

Surprisingly, switch_branches() seems to match that pretty well already.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 branch.c                   |    6 ++++--
 branch.h                   |    3 ++-
 builtin/branch.c           |    2 +-
 builtin/checkout.c         |   15 +++++++++++----
 t/t2018-checkout-branch.sh |    9 +++++----
 5 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/branch.c b/branch.c
index 025a97be..f85c4382 100644
--- a/branch.c
+++ b/branch.c
@@ -160,7 +160,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
 
 void create_branch(const char *head,
 		   const char *name, const char *start_name,
-		   int force, int reflog, enum branch_track track)
+		   int force, int reflog, int clobber_head,
+		   enum branch_track track)
 {
 	struct ref_lock *lock = NULL;
 	struct commit *commit;
@@ -175,7 +176,8 @@ void create_branch(const char *head,
 		explicit_tracking = 1;
 
 	if (validate_new_branchname(name, &ref, force,
-				    track == BRANCH_TRACK_OVERRIDE)) {
+				    track == BRANCH_TRACK_OVERRIDE ||
+				    clobber_head)) {
 		if (!force)
 			dont_change_ref = 1;
 		else
diff --git a/branch.h b/branch.h
index 1285158d..e125ff4c 100644
--- a/branch.h
+++ b/branch.h
@@ -13,7 +13,8 @@
  * branch for (if any).
  */
 void create_branch(const char *head, const char *name, const char *start_name,
-		   int force, int reflog, enum branch_track track);
+		   int force, int reflog,
+		   int clobber_head, enum branch_track track);
 
 /*
  * Validates that the requested branch may be created, returning the
diff --git a/builtin/branch.c b/builtin/branch.c
index 51ca6a02..730f9139 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -730,7 +730,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 		if (kinds != REF_LOCAL_BRANCH)
 			die(_("-a and -r options to 'git branch' do not make sense with a branch name"));
 		create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
-			      force_create, reflog, track);
+			      force_create, reflog, 0, track);
 	} else
 		usage_with_options(builtin_branch_usage, options);
 
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 2a807724..ca00a853 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -540,7 +540,9 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 		else
 			create_branch(old->name, opts->new_branch, new->name,
 				      opts->new_branch_force ? 1 : 0,
-				      opts->new_branch_log, opts->track);
+				      opts->new_branch_log,
+				      opts->new_branch_force ? 1 : 0,
+				      opts->track);
 		new->name = opts->new_branch;
 		setup_branch_path(new);
 	}
@@ -565,8 +567,12 @@ static void update_refs_for_switch(struct checkout_opts *opts,
 		create_symref("HEAD", new->path, msg.buf);
 		if (!opts->quiet) {
 			if (old->path && !strcmp(new->path, old->path)) {
-				fprintf(stderr, _("Already on '%s'\n"),
-					new->name);
+				if (opts->new_branch_force)
+					fprintf(stderr, _("Reset branch '%s'\n"),
+						new->name);
+				else
+					fprintf(stderr, _("Already on '%s'\n"),
+						new->name);
 			} else if (opts->new_branch) {
 				if (opts->branch_exists)
 					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)
 		struct strbuf buf = STRBUF_INIT;
 
 		opts.branch_exists = validate_new_branchname(opts.new_branch, &buf,
-							     !!opts.new_branch_force, 0);
+							     !!opts.new_branch_force,
+							     !!opts.new_branch_force);
 
 		strbuf_release(&buf);
 	}
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 75874e85..27412623 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -189,12 +189,13 @@ test_expect_success 'checkout -b <describe>' '
 	test_cmp expect actual
 '
 
-test_expect_success 'checkout -B to the current branch fails before merging' '
+test_expect_success 'checkout -B to the current branch works' '
 	git checkout branch1 &&
+	git checkout -B branch1-scratch &&
+
 	setup_dirty_mergeable &&
-	git commit -mfooble &&
-	test_must_fail git checkout -B branch1 initial &&
-	test_must_fail test_dirty_mergeable
+	git checkout -B branch1-scratch initial &&
+	test_dirty_mergeable
 '
 
 test_done
-- 
1.7.8.rc3

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: git branch -M" regression in 1.7.7?
  2011-11-26  8:54     ` Jonathan Nieder
@ 2011-11-26 22:38       ` Junio C Hamano
  2011-11-26 23:09         ` Andreas Schwab
  0 siblings, 1 reply; 9+ messages in thread
From: Junio C Hamano @ 2011-11-26 22:38 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: Conrad Irwin, ☂Josh Chia (谢任中),
	git, Soeren Sonnenburg

Jonathan Nieder <jrnieder@gmail.com> writes:

> In other words, when on master, "git checkout -B master <commit>"
> would be another way to say "git reset --keep <commit>", except that
> it also sets up tracking.

I havn't look at the patch (not a regression between 1.7.7 and 1.7.8 so
not a candidate for the remainder of this cycle), but I like the above
description quite a lot. I think Linus's "git reset --sane" which was
initially called "git reset --merge" but ended up as "git reset --keep"
should have been spelled as "checkout -B <current-branch>" from the
beginning.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git branch -M" regression in 1.7.7?
  2011-11-26 22:38       ` Junio C Hamano
@ 2011-11-26 23:09         ` Andreas Schwab
  0 siblings, 0 replies; 9+ messages in thread
From: Andreas Schwab @ 2011-11-26 23:09 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jonathan Nieder, Conrad Irwin,
	☂Josh Chia (谢任中),
	git, Soeren Sonnenburg

Junio C Hamano <gitster@pobox.com> writes:

> I havn't look at the patch (not a regression between 1.7.7 and 1.7.8 so
> not a candidate for the remainder of this cycle), but I like the above
> description quite a lot. I think Linus's "git reset --sane" which was
> initially called "git reset --merge" but ended up as "git reset --keep"
> should have been spelled as "checkout -B <current-branch>" from the
> beginning.

It is more convenient if you don't have to spell out the name of the
current branch (which fails if you aren't on a branch).

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: git branch -M" regression in 1.7.7?
  2011-11-26  2:30 ` Jonathan Nieder
  2011-11-26  6:52   ` [PATCH] Test renaming a branch to itself Conrad Irwin
  2011-11-26  7:05   ` git branch -M" regression in 1.7.7? Conrad Irwin
@ 2011-11-28 19:38   ` Junio C Hamano
  2 siblings, 0 replies; 9+ messages in thread
From: Junio C Hamano @ 2011-11-28 19:38 UTC (permalink / raw)
  To: Jonathan Nieder
  Cc: ☂Josh Chia (谢任中),
	git, Soeren Sonnenburg, Conrad Irwin

Jonathan Nieder <jrnieder@gmail.com> writes:

> 	git branch -M master
>
> This seems like a valuable exception to allow, because then "git
> branch -M foo" would _always_ be allowed --- either 'foo' is not the
> current branch, and it does the obvious thing, or 'foo' is the current
> branch, and nothing happens.
>
> Buildbot uses this idiom and was broken in 1.7.7 (it would emit the
> message "Cannot force update the current branch").

Although I am not sure the practice deserves to be called "idiom", I agree
that there is no reason to forbid renaming the current branch to the tip
commit of itself.

Will queue.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2011-11-28 19:39 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-26  0:36 git branch -M" regression in 1.7.7? ☂Josh Chia (谢任中)
2011-11-26  2:30 ` Jonathan Nieder
2011-11-26  6:52   ` [PATCH] Test renaming a branch to itself Conrad Irwin
2011-11-26  6:59     ` Jonathan Nieder
2011-11-26  7:05   ` git branch -M" regression in 1.7.7? Conrad Irwin
2011-11-26  8:54     ` Jonathan Nieder
2011-11-26 22:38       ` Junio C Hamano
2011-11-26 23:09         ` Andreas Schwab
2011-11-28 19:38   ` Junio C Hamano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.