Schwern wrote:
You can switch to any branch you like, unless it's already checked out by another worktree. You can run git-bisect. You can rebase.
But... you should not switch branch if you are, in your current worktree, in the middle of a bisect or rebase.
And that was not enforced before Git 2.38.
With Git 2.38 (Q3 2022), introduce a helper to see if a branch is already being worked on (hence should not be newly checked out in a working tree), which performs much better than the existing find_shared_symref()
to replace many uses of the latter.
See commit 4b6e18f, commit b489b9d, commit 12d47e3, commit d2ba271, commit 31ad6b6 (14 Jun 2022) by Derrick Stolee (derrickstolee
).
See commit 9bef0b1, commit b2463fc (18 Jun 2022) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
-- in commit c2d0109, 11 Jul 2022)
branch
: check for bisects and rebases
Signed-off-by: Derrick Stolee
The branch_checked_out()
helper was added by the previous change, but it used an over-simplified view to check if a branch is checked out.
It only focused on the HEAD symref, but ignored whether a bisect or rebase was happening.
Teach branch_checked_out()
to check for these things, and also add tests to ensure that we do not lose this functionality in the future.
Now that this test coverage exists, we can safely refactor validate_new_branchname()
to use branch_checked_out()
.
Note that we need to prepend "refs/heads/" to the 'state.branch' after calling wt_status_check_*()
.
We also need to duplicate wt->path
so the value is not freed at the end of the call.
Changing branch in a worktree which is being rebased (or bisected) would result in:
cannot force update the branch <abranch> checked out at <worktree path>
With Git 2.42 (Q3 2023), "git branch -f X
"(man) to repoint the branch X
said that X
was checked out in another worktree, even when branch X
was not and instead being bisected or rebased.
The message was reworded to say the branch was "in use".
See commit 4970bed (21 Jul 2023) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit 65e25ae, 04 Aug 2023)
branch
: update the message to refuse touching a branch in-use
Helped-by: Josh Sref
The "git branch -f
"(man) command can refuse to force-update a branch that is used by another worktree.
The original rationale for this behaviour was that updating a branch that is checked out in another worktree, without making a matching change to the index and the working tree files in that worktree, will lead to a very confused user.
"git diff
"(man) HEAD will no longer give a useful patch, because HEAD is a commit unrelated to what the index and the working tree in the worktree were based on, for example.
These days, the same mechanism also protects branches that are being rebased or bisected, and the same machanism is expected to be the right place to add more checks, when we decide to protect branches undergoing other kinds of operations.
We however forgot to rethink the messaging, which originally said that we are refusing to touch the branch because it is "checked out" elsewhere, when d2ba271 ("branch
: check for bisects and rebases", 2022-06-14, Git v2.38.0-rc0 -- merge listed in batch #1) started to protect branches that are being rebased or bisected.
The spirit of the check has always been that we do not want to disrupt the use of the same branch in other worktrees.
Let's reword the message slightly to say that the branch is "used by" another worktree, instead of "checked out".
We could teach the branch.c:prepare_checked_out_branches()
function to remember why it decided that a particular branch needs protecting (i.e.
was it because it was checked out? being bisected? something else?) in addition to which worktree the branch was in use, and use that in the error message to say "you cannot force update this branch because it is being bisected in the worktree X
", etc., but it is dubious that such extra complexity is worth it.
The message already tells which directory the worktree in question is, and it should be just a "chdir
" away for the user to find out what state it is in, if the user felt curious enough.
So let's not go there yet.
No more:
checked out at ...
But instead:
used by worktree at ...
With Git 2.44 (Q1 2024), "git checkout -B <branch> [<start-point>]
"(man) allowed a branch that is in use in another worktree to be updated and checked out, which might be a bit unexpected.
The rule has been tightened, which is a breaking change.
"--ignore-other-worktrees
" option is required to unbreak you, if you are used to the current behavior that "-B
" overrides the safety.
See commit b23285a, commit 9263c40 (23 Nov 2023) by Junio C Hamano (gitster
).
(Merged by Junio C Hamano -- gitster
-- in commit f09e741, 27 Dec 2023)
checkout
: forbid "-B " from touching a branch used elsewhere
Reported-by: Willem Verstraeten
"git checkout -B <branch> [<start-point>]
"(man), being a "forced" version of "-b", switches to the <branch>
, after optionally resetting its tip to the <start-point>
, even if the <branch>
is in use in another worktree, which is somewhat unexpected.
Protect the <branch>
using the same logic that forbids "git checkout
"(man) <branch>
from touching a branch that is in use elsewhere.
This is a breaking change that may deserve backward compatibliity warning in the Release Notes.
The "--ignore-other-worktrees
" option can be used as an escape hatch if the finger memory of existing users depend on the current behaviour of "-B
".
git checkout
now includes in its man page:
successful (e.g., when the branch is in use in another worktree, not
just the current branch stays the same, but the branch is not reset to
the start-point, either).
git switch
now includes in its man page:
that is to say, the branch is not reset/created unless "git switch
" is
successful (e.g., when the branch is in use in another worktree, not
just the current branch stays the same, but the branch is not reset to the start-point, either).
git worktree
is intended as a temporary measure for when you're in the middle of working on something and need to quickly work on something else. It is not intended to be part of your regular workflow; each branch should not have its own worktree. See the example in the documentation. – Londrina