branch: allow a no-op "branch -M <current-branch> HEAD"

Overwriting the current branch with a different commit is forbidden, as it will make the status recorded in the index and the working tree out of sync with respect to the HEAD. There however is no reason to forbid it if the current branch is renamed to itself, which admittedly is something only an insane user would do, but is handy for scripts. Test script is by Conrad Irwin. Reported-by: Soeren Sonnenburg <sonne@debian.org> Reported-by: Josh Chia (谢任中) Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Conrad Irwin <conrad.irwin@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Nieder committed Nov 25, 2011 at 20:30 UTC 3f59481e338c2d3167b9654a4289a9d1201f7944
2 files changed +24 -1
builtin/branch.c
+8 -1
@@ -568,6 +568,7 @@ static void rename_branch(const char *oldname, const char *newname, int force)
568 unsigned char sha1[20];
569 struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
570 int recovery = 0;
571 + int clobber_head_ok;
572
573 if (!oldname)
574 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)
584 die(_("Invalid branch name: '%s'"), oldname);
585 }
586
586 - validate_new_branchname(newname, &newref, force, 0);
587 + /*
588 + * A command like "git branch -M currentbranch currentbranch" cannot
589 + * cause the worktree to become inconsistent with HEAD, so allow it.
590 + */
591 + clobber_head_ok = !strcmp(oldname, newname);
592 +
593 + validate_new_branchname(newname, &newref, force, clobber_head_ok);
594
595 strbuf_addf(&logmsg, "Branch: renamed %s to %s",
596 oldref.buf, newref.buf);
t/t3200-branch.sh
+16
@@ -115,6 +115,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
115 git branch -M baz bam
116 '
117
118 +test_expect_success 'git branch -M master should work when master is checked out' '
119 + git checkout master &&
120 + git branch -M master
121 +'
122 +
123 +test_expect_success 'git branch -M master master should work when master is checked out' '
124 + git checkout master &&
125 + git branch -M master master
126 +'
127 +
128 +test_expect_success 'git branch -M master2 master2 should work when master is checked out' '
129 + git checkout master &&
130 + git branch master2 &&
131 + git branch -M master2 master2
132 +'
133 +
134 test_expect_success 'git branch -v -d t should work' '
135 git branch t &&
136 test_path_is_file .git/refs/heads/t &&