From: "Rubén Justo" <rjusto@gmail.com>
To: Git List <git@vger.kernel.org>
Cc: Junio C Hamano <gitster@pobox.com>
Subject: [PATCH v3 0/3] branch: operations on orphan branches
Date: Tue, 7 Feb 2023 00:01:27 +0100 [thread overview]
Message-ID: <2193a4ed-b263-068e-92f8-847dcb053f8c@gmail.com> (raw)
In-Reply-To: <34a58449-4f2e-66ef-ea01-119186aebd23@gmail.com>
Avoid some confusing errors operating with orphan branches when
working with worktrees.
Changes from v2:
- Renamed "ishead_and_reject_rebase_or_bisect_branch()" to
"die_if_branch_is_being_rebased_or_bisected()"
A proposed name "die_if_branch_is_is_use()" has not been used because
it could lead to confusion. We don't yet support copying or renaming
a branch being rebased or bisected, but we do under other uses.
- Comments added and variables renamed to make more clear the intention and
the functioning.
Rubén Justo (3):
branch: avoid unnecessary worktrees traversals
branch: description for orphan branch errors
branch: rename orphan branches in any worktree
builtin/branch.c | 47 ++++++++++++++++++++++++------------------
t/t3200-branch.sh | 14 +++++++++++++
t/t3202-show-branch.sh | 18 ++++++++++++++++
3 files changed, 59 insertions(+), 20 deletions(-)
Range-diff against v2:
1: d16819bc61 ! 1: 50fa7ed076 avoid unnecessary worktrees traversing
@@ Metadata
Author: Rubén Justo <rjusto@gmail.com>
## Commit message ##
- avoid unnecessary worktrees traversing
+ branch: avoid unnecessary worktrees traversals
"reject_rebase_or_bisect_branch()" was introduced [1] to prevent a
branch under bisect or rebase from being renamed or copied. It
traverses all worktrees in the repository and dies if the specified
- branch is being rebased or bisected in any them.
+ branch is being rebased or bisected in any of them.
"replace_each_worktree_head_symref()" was introduced [2] to adjust the
HEAD in all worktrees after a branch rename succeeded. It traverses all
@@ Commit message
to the renamed ref, it adjusts it.
If we could know in advance if the renamed branch is not HEAD in any
- worktree we could avoid calling "replace_each_worktree_head_symref()".
+ worktree we could avoid calling "replace_each_worktree_head_symref()",
+ and so avoid that unnecessary second traversing.
- Let's have "reject_rebase_or_bisect_branch()" check and return whether
- the specified branch is HEAD in any worktree, and use this information
- to avoid unnecessary calls to "replace_each_worktree_head_symref()".
+ Let's rename "reject_rebase_or_bisect_branch()" to a more meaningful
+ name "die_if_branch_is_being_rebased_or_bisected()" and make it return,
+ if it does not die(), if the specified branch is HEAD in any worktree.
+ Use this new information to avoid unnecessary calls to
+ "replace_each_worktree_head_symref()".
1.- 14ace5b (branch: do not rename a branch under bisect or rebase,
2016-04-22)
@@ builtin/branch.c: static void print_current_branch_name(void)
}
-static void reject_rebase_or_bisect_branch(const char *target)
-+static int ishead_and_reject_rebase_or_bisect_branch(const char *target)
++/*
++ * Dies if the specified branch is being rebased or bisected. Otherwise returns
++ * 0 or, if the branch is HEAD in any worktree, returns 1.
++ */
++static int die_if_branch_is_being_rebased_or_bisected(const char *target)
{
struct worktree **worktrees = get_worktrees();
- int i;
@@ builtin/branch.c: static void copy_or_rename_branch(const char *oldname, const c
const char *interpreted_oldname = NULL;
const char *interpreted_newname = NULL;
- int recovery = 0;
-+ int recovery = 0, ishead;
++ int recovery = 0, oldref_is_head;
if (strbuf_check_branch_ref(&oldref, oldname)) {
/*
@@ builtin/branch.c: static void copy_or_rename_branch(const char *oldname, const c
validate_new_branchname(newname, &newref, force);
- reject_rebase_or_bisect_branch(oldref.buf);
-+ ishead = ishead_and_reject_rebase_or_bisect_branch(oldref.buf);
++ oldref_is_head = die_if_branch_is_being_rebased_or_bisected(oldref.buf);
if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
!skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
@@ builtin/branch.c: static void copy_or_rename_branch(const char *oldname, const c
}
- if (!copy &&
-+ if (!copy && ishead &&
++ if (!copy && oldref_is_head &&
replace_each_worktree_head_symref(oldref.buf, newref.buf, logmsg.buf))
die(_("Branch renamed to %s, but HEAD is not updated!"), newname);
2: bc0ac43932 ! 2: ab277e5fcb branch: description for orphan branch errors
@@ Commit message
branch: description for orphan branch errors
In bcfc82bd48 (branch: description for non-existent branch errors,
- 2022-10-08) we check the current HEAD to detect if the branch to operate
- with is an orphan branch, to avoid the confusing error: "No branch
- named...".
+ 2022-10-08) we checked the current HEAD to detect if the branch to
+ operate with is an orphan branch, so as to avoid the confusing error:
+ "No branch named...".
If we are asked to operate with an orphan branch in a different working
tree than the current one, we need to check the HEAD in that different
@@ Commit message
repository, using the helper introduced in 31ad6b61bd (branch: add
branch_checked_out() helper, 2022-06-15)
- "ishead_reject_rebase_or_bised_branch()" already returns whether the
- branch to operate with is HEAD in any working tree in the repository.
+ "die_if_branch_is_being_rebased_or_bisected()" already returns whether
+ the branch to operate with is HEAD in any worktree in the repository.
Let's use this information in "copy_or_rename_branch()", instead of the
helper.
- Note that we now call reject_rebase_or_bisect_branch() earlier, which
- introduces a change in the error displayed when a combination of
- unsupported conditions occur simultaneously: the desired destination
- name is invalid, and the branch to operate on is being overrun or
- bisected. With "foo" being rebased or bisected, this:
+ Note that we now call "die_if_branch_is_being_rebased_or_bisected()"
+ earlier, which introduces a change in the error displayed when a
+ combination of unsupported conditions occur simultaneously: the desired
+ destination name is invalid, and the branch to operate with is being
+ rebased or bisected. i.e. with "foo" being rebased or bisected, this:
- $ git branch -m foo HEAD
- fatal: 'HEAD' is not a valid branch name.
+ $ git branch -m foo /
+ fatal: '/' is not a valid branch name.
... becomes:
- $ git branch -m foo HEAD
+ $ git branch -m foo /
fatal: Branch refs/heads/foo is being ...
Signed-off-by: Rubén Justo <rjusto@gmail.com>
@@ builtin/branch.c: static void copy_or_rename_branch(const char *oldname, const c
- else
- die(_("No branch named '%s'."), oldname);
- }
-+ ishead = ishead_and_reject_rebase_or_bisect_branch(oldref.buf);
++ oldref_is_head = die_if_branch_is_being_rebased_or_bisected(oldref.buf);
+
-+ if ((copy || !ishead) && !ref_exists(oldref.buf))
-+ die(ishead
++ if ((copy || !oldref_is_head) && !ref_exists(oldref.buf))
++ die(oldref_is_head
+ ? _("No commit on branch '%s' yet.")
+ : _("No branch named '%s'."), oldname);
@@ builtin/branch.c: static void copy_or_rename_branch(const char *oldname, const c
else
validate_new_branchname(newname, &newref, force);
-- ishead = ishead_and_reject_rebase_or_bisect_branch(oldref.buf);
+- oldref_is_head = die_if_branch_is_being_rebased_or_bisected(oldref.buf);
-
if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
!skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
3: 29f8b6044d ! 3: 9742b4ff1f branch: rename orphan branches in any worktree
@@ Commit message
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 to rename is an orphan branch, checking the current HEAD.
+ 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 working tree than the current one, i.e. not the current HEAD.
+ different worktree than the current one, i.e. not the current HEAD.
- Let's make "ishead_reject_rebase_or_bisect_branch()" return a flag
- indicating if the returned value refers to an orphan branch, and use it
- to extend what we did in cfaff3aac, to all HEADs in the repository.
+ 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@gmail.com>
## builtin/branch.c ##
-@@ builtin/branch.c: static int ishead_and_reject_rebase_or_bisect_branch(const char *target)
+@@ builtin/branch.c: 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)
+ {
+@@ builtin/branch.c: 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 = 1 + (is_null_oid(&wt->head_oid) ? 1 : 0);
++ ret = is_null_oid(&wt->head_oid) ? 2 : 1;
if (!wt->is_detached)
continue;
+@@ builtin/branch.c: 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)) {
+ /*
+@@ builtin/branch.c: 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);
+
@@ builtin/branch.c: 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 && !(ishead > 1) &&
++ 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))
@@ t/t3200-branch.sh: test_expect_success 'git branch -M and -C fail on detached HE
+ 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 &&
--
2.39.0
next prev parent reply other threads:[~2023-02-06 23:02 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-12-30 22:59 [PATCH 0/2] branch: operations on orphan branches Rubén Justo
2022-12-30 23:04 ` [PATCH 1/2] branch: description for orphan branch errors Rubén Justo
2023-01-01 3:45 ` Junio C Hamano
2023-01-03 1:15 ` Rubén Justo
2023-01-04 6:58 ` Junio C Hamano
2023-01-06 23:39 ` Rubén Justo
2023-01-06 23:59 ` Junio C Hamano
2023-01-07 0:35 ` Rubén Justo
2023-01-07 0:00 ` Junio C Hamano
2022-12-30 23:12 ` [PATCH 2/2] branch: rename orphan branches in any worktree Rubén Justo
2023-01-15 23:54 ` [PATCH v2 0/3] branch: operations on orphan branches Rubén Justo
2023-01-16 0:00 ` [PATCH v2 1/3] avoid unnecessary worktrees traversing Rubén Justo
2023-01-19 21:24 ` Junio C Hamano
2023-01-19 23:26 ` Rubén Justo
2023-01-16 0:02 ` [PATCH v2 2/3] branch: description for orphan branch errors Rubén Justo
2023-01-16 0:04 ` [PATCH 3/3] branch: rename orphan branches in any worktree Rubén Justo
2023-01-19 21:33 ` Junio C Hamano
2023-01-19 23:34 ` Rubén Justo
2023-01-16 0:06 ` [PATCH v2 " Rubén Justo
2023-02-06 23:01 ` Rubén Justo [this message]
2023-02-06 23:06 ` [PATCH v3 1/3] branch: avoid unnecessary worktrees traversals Rubén Justo
2023-02-11 4:16 ` Jonathan Tan
2023-02-15 22:00 ` Rubén Justo
2023-02-06 23:06 ` [PATCH v3 2/3] branch: description for orphan branch errors Rubén Justo
2023-02-06 23:06 ` [PATCH v3 3/3] branch: rename orphan branches in any worktree Rubén Justo
2023-02-07 0:11 ` [PATCH v3 0/3] branch: operations on orphan branches Junio C Hamano
2023-02-07 8:33 ` Ævar Arnfjörð Bjarmason
2023-02-08 0:35 ` Rubén Justo
2023-02-08 18:37 ` Junio C Hamano
2023-02-22 22:50 ` [PATCH v4 " Rubén Justo
2023-02-22 22:52 ` [PATCH v4 1/3] branch: avoid unnecessary worktrees traversals Rubén Justo
2023-02-25 15:08 ` Rubén Justo
2023-02-27 19:30 ` Jonathan Tan
2023-02-28 0:11 ` Rubén Justo
2023-02-22 22:55 ` [PATCH v4 2/3] branch: description for orphan branch errors Rubén Justo
2023-02-27 19:38 ` Jonathan Tan
2023-02-27 21:56 ` Junio C Hamano
2023-02-28 0:22 ` Rubén Justo
2023-02-22 22:56 ` [PATCH v4 3/3] branch: rename orphan branches in any worktree Rubén Justo
2023-02-27 19:41 ` Jonathan Tan
2023-02-28 0:23 ` Rubén Justo
2023-03-26 22:19 ` [PATCH v5 0/5] branch: operations on orphan branches Rubén Justo
2023-03-26 22:33 ` [PATCH v5 1/5] branch: test for failures while renaming branches Rubén Justo
2023-03-26 22:33 ` [PATCH v5 2/5] branch: use get_worktrees() in copy_or_rename_branch() Rubén Justo
2023-03-26 22:33 ` [PATCH v5 3/5] branch: description for orphan branch errors Rubén Justo
2023-03-26 22:33 ` [PATCH v5 4/5] branch: rename orphan branches in any worktree Rubén Justo
2023-03-26 22:33 ` [PATCH v5 5/5] branch: avoid unnecessary worktrees traversals Rubén Justo
2023-03-27 19:49 ` [PATCH v5 0/5] branch: operations on orphan branches Junio C Hamano
2023-05-01 22:19 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2193a4ed-b263-068e-92f8-847dcb053f8c@gmail.com \
--to=rjusto@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).