Does one git worktree support multiple branches?
Asked Answered
I

4

5

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?

Inedited answered 9/9, 2021 at 22:54 Comment(3)
Can you point out where in the Git worktree docs it says a work tree serves only one branch?Bullyboy
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.Indrawn
It is possible, within an added working tree, to switch from branch to branch. But as Schwern notes, this isn't really the intended usage pattern—it's just that, as jthill notes, it's not prohibited, and in Git, anything not explicitly prohibited is implicitly supported.Oribel
F
2

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

Flaggy answered 12/7, 2022 at 8:53 Comment(1)
Git 2.43 continues this work.Flaggy
I
6

git worktree creates a new checkout which shares your existing local repository. It has its own HEAD, which tracks which commit is currently checked out, and its own staging area for building commits. It's main purpose is to be able to work on multiple branches at the same time without having to clone the whole repository or stash your changes.

A worktree works essentially like any other checkout. 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.

A worktree does not have to be for a new branch, it can be for an existing branch. git worktree add ../temp master will make a worktree with master checked out.

You only need to make worktrees if you intend to work on multiple branches simultaneously. For example, you're working on a feature and have lots of uncommitted changes and an emergency fix comes in. You can make a worktree for that fix, do the fix in the worktree, and then return to your original feature work. Or maybe you want to test something against an old version, you can make a work tree and checkout the old version.

A good development process does not require you to be working on multiple branches at the same time.

Indrawn answered 9/9, 2021 at 23:35 Comment(1)
If my main .git is in A/, for branch A, with a B worktree in folder B/. When I'm in B/, can I still cherry-pick commits from branch A? Somehow, git log in B worktree only shows commits from B branch, and complains when I try to cherry-pick an apparently unknown commit. EDIT: git fetch origin A:A inside B/ seems to make B worktree aware of the A branch.Lustihood
F
2

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

Flaggy answered 12/7, 2022 at 8:53 Comment(1)
Git 2.43 continues this work.Flaggy
M
2

If you git init or git clone <args> you get a repository with one worktree.[1]

A git init repository will start with only the default branch available, which is also checked out in the main worktree.

From there you can create however many branches you want. But there will always be only one checked out branch at most (you could also be in “detached head” mode where no branch is checked out).

So no, each branch does not have its own worktree; the repository contains all the branches, and each work tree can have at most one branch checked out at any given time.[3]

You always have a worktree when working on your code

Unless you are working in a “bare” repository, you are always working in a worktree. A simple git init will give you a worktree.

We haven’t used git worktree add yet. And yet the answer to the question falls out of basic repository management.

But it is most of the time either redundant or useless to talk about “worktrees” unless you have more than one; you can just say “my repository”.

Do you need more than one worktree?

Worktrees and branches are very different things. But they have one thing in common: how many of them you have is completely up to you and your workflow.

Say I’m making a repository for my own private notes. I will probably just use the default branch. Why would I need more branches than the default branch?

Same principle applies to worktrees. Do you need to:

  • Work on multiple things at the same time without changing the working tree each time (the working tree is unique to each worktree)[4]
  • Maybe run a long process (like a test suite) on a commit while you work on a branch in another worktree
  • Perhaps other use-cases mentioned in man git worktrees

If not then you might not ever need to use git-worktree(1).

More than one worktree

Finally, we can create one more worktree:

$ git worktree add -b quickfix ../wip
Preparing worktree (new branch 'quickfix')
HEAD is now at 7da80ac i
$ git worktree list
/home/kristoffer/programming/just-init  7da80ac [main]
/home/kristoffer/programming/wip        7da80ac [quickfix]

Two worktrees. How many branches do we have? We have at least two, but we might as well have two thousand. Because we don’t have to create a worktree for each branch that we have.

Worktree without a branch (detached head)

Just like your “main worktree”, the other (“linked” worktrees) don’t have to have a branch checked out:

$ git worktree add --detach ../test
Preparing worktree (detached HEAD 7da80ac)
HEAD is now at 7da80ac i

This might seem like an academic point to make but I would say that it is not: it can be very useful to check out whatever commit is at the tip of your branch, run a test suite in a separate worktree, and then (while the test suite is being run) continue hacking on that branch in your original (probably main) worktree.[5]

In fact this is the approach recommended when working with the cool program git-test by Michael Haggerty:

git test works really well together with git worktree. Keep a second worktree and use it for testing your current branch continuously as you work:

git worktree add --detach ../test HEAD cd ../test git test run master..mybranch

Notes

  1. $ mkdir just-init && cd just-init
    $ git init
    $ git worktree list
    /home/kristoffer/programming/just-init  0000000 [main]
    
  2. init.defaultBranch if set; else master

  3. And a branch cannot be checked out in two different worktrees at the same time.

  4. You in effect switch to using cd instead of git checkout or git switch

  5. Recall that any given branch cannot be checked out in multiple worktrees at the same time. So we have to “detach”.

  6. Source

Marchand answered 15/4, 2023 at 10:20 Comment(1)
Interesting take on worktree (that I presented here in 2015 with Git 2.5+). Upvoted.Flaggy
C
1

From https://git-scm.com/docs/git-worktree

A git repository can support multiple working trees, allowing you to check out more than one branch at a time. With git worktree add a new working tree is associated with the repository. This new working tree is called a "linked working tree" as opposed to the "main working tree" prepared by git-init or git-clone.

If you want to add a new branches to worktree you need to write:
git worktree add <path> <branch_name>

For example:

git checkout -B new_branch
git checkout main
git worktree add ./new_branch new_branch

To remove it: git worktree remove

And that how does it look: in tree view

In path parameter you can pass anything. So you can manage your branches as you want for example you can create folder where you will store only branches with bugfixes or futures.

Cahill answered 9/9, 2021 at 23:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.