@@ -489,6 +489,7 @@ static void print_current_branch_name(void)
#define IS_BISECTED 1
#define IS_REBASED 2
#define IS_HEAD 4
+#define IS_ORPHAN 8
static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
{
@@ -514,8 +515,11 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
for (int i = 0; worktrees[i]; i++) {
struct worktree *wt = worktrees[i];
- if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref))
+ if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref)) {
oldref_usage |= IS_HEAD;
+ if (is_null_oid(&wt->head_oid))
+ oldref_usage |= IS_ORPHAN;
+ }
if (!wt->is_detached)
continue;
@@ -531,8 +535,9 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
}
}
- if ((copy || !(oldref_usage & IS_HEAD)) && !ref_exists(oldref.buf)) {
- if (oldref_usage & IS_HEAD)
+ if ((copy || !(oldref_usage & IS_HEAD)) &&
+ ((oldref_usage & IS_ORPHAN) || !ref_exists(oldref.buf))) {
+ if (oldref_usage & IS_ORPHAN)
die(_("No commit on branch '%s' yet."), oldname);
else
die(_("No branch named '%s'."), oldname);
@@ -567,8 +572,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_usage & 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))
@@ -583,7 +587,7 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
interpreted_oldname);
}
- if (!copy) {
+ if (!copy && (oldref_usage & IS_HEAD)) {
/*
* Update all per-worktree HEADs pointing at the old ref to
* point the new ref.
@@ -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 &&
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. However the branch to be renamed can be an orphan branch in a different worktree than the current one, i.e. not the current HEAD. In "copy_or_rename_branch()" we are traversing the worktrees checking if the branch to be renamed is HEAD in any worktree. Let's include also a check for HEAD being NULL, which is the indication of an orphan branch, and use it to extend what we did in cfaff3aac, to all HEADs in the repository. Signed-off-by: Rubén Justo <rjusto@gmail.com> --- builtin/branch.c | 16 ++++++++++------ t/t3200-branch.sh | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 6 deletions(-)