gitgit-worktree

Does one git worktree support multiple branches?


Per the documentation, each git worktree serves one branch (dev/feature/prod and so on), but it also sound not reasonable to me, that each branch will have its own worktree as it will creates many folders, and at some point might be confusing.

Does one git worktree can support multiple branches? for example all the branches which belongs to feature and then switch between what relevant for the moment? Is it correct approach?


Solution

  • 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).