In cfaff3aac (branch -m: allow renaming a yet-unborn branch, 2020-12-13) we added support for renaming an orphan branch, skipping rename_ref() if the branch being renamed is an orphan branch; checking the current HEAD. But the orphan branch to be renamed can be an orphan branch in a different worktree than the current one, i.e. not the current HEAD. Let's make "die_if_branch_is_being_rebased_or_bisected()" return if the specified branch is HEAD and orphan, and use it to extend what we did in cfaff3aac, to check all HEADs in the repository. Signed-off-by: Rubén Justo <rjusto@xxxxxxxxx> --- builtin/branch.c | 16 +++++++++------- t/t3200-branch.sh | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/builtin/branch.c b/builtin/branch.c index 28cec344ad..7efda62224 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -488,7 +488,8 @@ static void print_current_branch_name(void) /* * Dies if the specified branch is being rebased or bisected. Otherwise returns - * 0 or, if the branch is HEAD in any worktree, returns 1. + * 0 or, if the branch is HEAD in any worktree, returns 1. If the branch is HEAD + * and also orphan, returns 2. */ static int die_if_branch_is_being_rebased_or_bisected(const char *target) { @@ -499,7 +500,7 @@ static int die_if_branch_is_being_rebased_or_bisected(const char *target) struct worktree *wt = worktrees[i]; if (wt->head_ref && !strcmp(target, wt->head_ref)) - ret = 1; + ret = is_null_oid(&wt->head_oid) ? 2 : 1; if (!wt->is_detached) continue; @@ -523,7 +524,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT; const char *interpreted_oldname = NULL; const char *interpreted_newname = NULL; - int recovery = 0, oldref_is_head; + int recovery = 0, oldref_is_head, oldref_is_orphan; if (strbuf_check_branch_ref(&oldref, oldname)) { /* @@ -537,9 +538,11 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int } oldref_is_head = die_if_branch_is_being_rebased_or_bisected(oldref.buf); + oldref_is_orphan = (oldref_is_head > 1); - if ((copy || !oldref_is_head) && !ref_exists(oldref.buf)) - die(oldref_is_head + if ((copy || !oldref_is_head) && + (oldref_is_orphan || !ref_exists(oldref.buf))) + die(oldref_is_orphan ? _("No commit on branch '%s' yet.") : _("No branch named '%s'."), oldname); @@ -564,8 +567,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int strbuf_addf(&logmsg, "Branch: renamed %s to %s", oldref.buf, newref.buf); - if (!copy && - (!head || strcmp(oldname, head) || !is_null_oid(&head_oid)) && + if (!copy && !oldref_is_orphan && rename_ref(oldref.buf, newref.buf, logmsg.buf)) die(_("Branch rename failed")); if (copy && copy_existing_ref(oldref.buf, newref.buf, logmsg.buf)) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 5a169b68d6..5aef00efde 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -279,6 +279,20 @@ test_expect_success 'git branch -M and -C fail on detached HEAD' ' test_cmp expect err ' +test_expect_success 'git branch -m should work with orphan branches' ' + test_when_finished git checkout - && + test_when_finished git worktree remove -f wt && + git worktree add wt --detach && + # rename orphan in another worktreee + git -C wt checkout --orphan orphan-foo-wt && + git branch -m orphan-foo-wt orphan-bar-wt && + test orphan-bar-wt=$(git -C orphan-worktree branch --show-current) && + # rename orphan in the current worktree + git checkout --orphan orphan-foo && + git branch -m orphan-foo orphan-bar && + test orphan-bar=$(git branch --show-current) +' + test_expect_success 'git branch -d on orphan HEAD (merged)' ' test_when_finished git checkout main && git checkout --orphan orphan && -- 2.39.0