Reputation: 13663
I read Github's post on git-worktree. They write:
Suppose you're working in a Git repository on a branch called
feature
, when a user reports a high-urgency bug inmaster
. First you create a linked working tree with a new branch,hotfix
, checked out relative to master […] You can fix the bug, push hotfix, and create a pull request.
When I'm working on a branch called feature and some high-urgency bug in master is reported, I usually stash away whatever I'm working on and create a new branch. When I'm done, I can continue working. This is a very simple model, I've been working like that for years.
On the other hand, using git-worktree has its own limitations:
For example, it's not allowed to have the same branch checked out in two linked working trees at the same time, because that would allow changes committed in one working tree to bring the other one out of sync.
Why would I choose a more complicated workflow for a problem that's already been solved?
Is there anything about git-worktree
that couldn't be done beforehand and that justifies this whole new, complex feature?
Upvotes: 360
Views: 138618
Reputation: 3469
I posted this question 11 years ago and somehow it's had 120k views.
I'm not sure if this is something supported by Git, but in theory it seems like it should work to me.
My workflow often involves my editing of files in multiple branches simultaneously. In other words, I often want to open a few files in one branch is while I edit the contents of another file in another branch.
My typical solution to this is to make two checkouts, but it's a shame I can't share branches and refs between them. What I would like is to just have two working directories managed by the same .git folder.
I'm aware of local git clone solutions (the default, which is to hardlink shared objects, and the --shared option, which sets up an alternate object store with the original repo), but these solutions only cut down on disk space usage, and especially in the case of --shared, seem fraught with peril.
Is there a way to use one .git folder, and have two working directories backed by it? Or is Git hardcoded to have just one working directory checked out at any time?
The answer is git worktree.
Upvotes: 8
Reputation: 3781
git-worktree(1) is in my opinion a tool that supports workflows that for most of us could be replicated by using more common tools.[1] So first we need to motivate the workflows themselves.
Most of the time you just switch branches when you want to switch from one task to another. But switching a branch might mean having to change a lot of your files in your working tree.[2] And then you might run into hurdles:
You might run into these problems if you need to check out working trees for versions of your repository that are years apart (as explained in this answer).
But this might also happen during active development: say you’re restructuring one part of the application in your topic branch, but you often return to the main branch in order to work on minor improvements.
What do you do? Maybe you just clone the repository multiple times:
# The main “worktree”
git clone <repo> main-repo
# Your big restructuring
git clone <repo> restructure
# That long-time-support branch
git clone <repo> our-app-v5
This is fine. But there are some downsides:
Now you have three repositories to manage instead of one
main-repo
, but you
slightly neglect to fetch the main branch from your central
repository while in restructuring
, meaning that you forget to keep
your long-running branch up to date with the main development workmain-repo
and restructuring
) then you might end up either creating
mutual remotes or going through an intermediary (like the central
repository)You have three repositories, which means you have three object databases with mostly the same contents
These three repositories know nothing about each other, so if you forget about one of your repositories then there’s nothing that can help you remember that it’s just lying around, perhaps with branches that you forgot to push upstream and whatnot
Adopting git-worktree(1) means that (point by point):
git fetch
in any one of the worktrees and be done with itgit worktree list
So far we’ve focused on cases where the working trees might be very different between branches. But another use-case is when you simply want to do something real quick and you don’t want to care about what your working tree state is, whether you are in the middle of a rebase, or anything else.
Concretely, you want to do a throw-away merge in order to see how a merge between two branches would pan out. So you:
There might be users of this tool who directly rely on certain features of this tool, like e.g. the disk-saving feature. But many of us could also get by with ad hoc workflows like cloning the repository multiple times if git-worktree(1) wasn’t available to us.
“The tree of actual checked out files.”, according to man gitglossary
, Git 2.40.0
One of the examples in the GitHub article: “So suppose that you want to run long-running tests on the current commit.”
This should perhaps not be needed for “client” repositories, but nonetheless: a bug report was filed against Git recently because a git-log(1) “hung” when it was used in the Linux repository; the issue was seemingly fixed by running git-commit-graph(1), which reduced the time it took to display one line of log input from about ten seconds to about 32 milliseconds. So it might matter in practice, even for consumers of a repository.
Note: I should delete this bullet point if it turns out to be irrelevant, since it might be that such micromanagement should not be necessary.
Upvotes: 6
Reputation: 3207
My absolute favorite and probably the most common use-case where everyone should use git worktree
is reviewing the pull requests of team-mates, while still working on your changes in the main worktree. 😎
Upvotes: 45
Reputation: 8993
For me, git worktree is the biggest improvement since a long time. I'm working in enterprise software development. There, it is very common that you have to maintain old versions like what you released 3 years ago. Of course you have a branch for each version so that you can easily switch to it and fix a bug. However, switching is expensive, because in the meantime you completely restructured the repository and maybe build system. If you switch, your IDE will run mad trying to adapt the project settings.
With worktree, you can avoid that constant reconfiguration. Checkout those old branches in separate folders using worktree. For each branch, you got an independent IDE project.
Of course this could have been done in the past by cloning the repo several times and this has been my approach so far. However, that also meant wasting hardrive space and worse needing to fetching the same changes from the repo several times.
Upvotes: 373
Reputation: 1007
I'm using git worktree
for machine learning development.
I have a main functional code and then I want to split branches of different experiments (different algorithms and different hyperparameters). git worktree
allows me to integrate dvc alongside different versions of my code specialized to different algorithms. After running all training jobs I evaluate final metrics and merge to master the best branch/model.
Upvotes: 7
Reputation: 1027
One obvious use is to simultaneously compare the behavior (not source) of different versions - for example different versions of a web site or just a web page.
I tried this out locally.
create a directory page1
.
inside create the directory src
and git init
it.
in src
create page1.html
with a little content and commit it.
$ git branch ver0
$ git worktree add ../V0 ver0
in src
master add more text to page1.html
and commit it.
$ git branch sty1
edit page1.html
in the sty1
branch (add some distinctive CSS style) and add commit it.
$ git worktree add ../S1 sty1
You can now use a web browser to open and view these 3 versions simultaneously:
..\page1\src\page1.html
// whatever git has as current
..\page1\V0\page1.html
// the initial version
..\page1\S1\page1.html
// the experimentally styled version
Upvotes: 91
Reputation: 17919
In new project for me, I've created a feature.
But some specs failed. To compare results with master
I created a work-tree
repo. I compared results step by step in run code, until understand what went wrong.
Upvotes: 2
Reputation: 1782
I've got a rather unusual one: I am doing Windows and Linux development on the same machine. I have a VirtualBox running Linux inside of my Windows box. The VirtualBox mounts some Windows directories and uses them directly inside of the Linux machine. This lets me use Windows to manage files but build within Linux. This is a cross-platform project, so it builds on both Windows and Linux from the same directory structure.
The problem is that the Linux and Windows build systems crash into each other when used in the same directory; there are some complicated build steps for downloading libraries, etc., that use the same directory names. The Windows version of the build system downloads the Windows-specific libraries, and the Linux version of the build system downloads the Linux-specific libraries.
In an ideal world, the build system would be modified so that Windows & Linux can co-exist within the directory, but for now, the problem is being addressed with worktrees. The "Linux" folder can generate Linux-specific build artifacts, and the "Windows" folder can generate Windows-specific build artifacts. While this is hardly an ideal solution, it makes a nice stopgap while waiting for the build system bugs to be addressed.
Admittedly, worktree wasn't designed for this; I have to keep the Windows version and the Linux version on separate branches, even though I'd really prefer them to be on the same branch. Still, it's doing the job, and is a somewhat unconventional case of worktree saving the day.
Upvotes: 9
Reputation: 8413
I originally stumbled on this question after wondering what these fancy worktrees could be used for. Since then I have integrated them into my workflow and in spite of my initial scepticism I have come to find them quite useful.
I work on a rather large code-base, which takes quite some time to compile. I usually have the current development branch on my machine along with the feature branch I am currently working on plus the master branch, which represents the current state of the live system.
One of the biggest benefits for me is obviously that I don't have to recompile the entire thing everytime I switch branches (that is, worktrees). A nice side-effect is that I can go to the development worktree, do stuff there, change directory to the worktree for my current feature branch and then rebase it without having to pull first.
Upvotes: 16
Reputation: 40639
There are legitimate reasons why you may want/need multiple worktrees in the filesystem at once.
manipulating the checked out files while needing to make changes somewhere else (eg. compiling/testing)
diffing the files via normal diff tools
during merge conflicts, I often want to navigate through the source code as it is on source side while resolving conflicts in the files.
If you need to switch back and forth a lot, there is wasted time checkout out and rechecking out that you don't need to do with multiple worktrees.
the mental cost of mental context switching between branches via git stashing is not really measurable. Some people find that there is mental cost to stashing that isn't there by simply opening files from a different directory.
Some people ask "why not do multiple local clones". It is true that with the "--local" flag you don't have to worry about extra disc space usage. This (or similar ideas) is what I have done up to this point. Functional advantages to linked worktrees over local clones are:
With local clones, your extra worktrees (which are in the local clones) simply do not have access to origin or upstream branches. The 'origin' in the clone will not be the same as the 'origin' in the first clone.
git log @{u}..
or git diff origin/feature/other-feature
can be very helpful and these are either not possible anymore or more difficult. These ideas are technically possible with local clones via an assortment of workarouns, but every workaround you could do are done better and/or simpler through linked worktrees.You can share refs between worktrees. If you want to compare or borrow changes from another local branch, now you can.
Upvotes: 43
Reputation: 39981
I can see some uses for this.
If you have a test suite that runs for a long time, imagine hours, and you start it it effectively blocks that working copy until the tests are completed. Switching branches during those tests would break them in ways that would be hard to understand.
So with git-worktree
I could have a second idea launched for another branch doing work there.
Also, when I switch to some other branch to do some quick investigation my IDE thinks a lot of files suddenly changed and will index all those changes, just to have to re-index them again when I'm switching back.
A third use case would be to do file comparison using other tools than git-diff
, like normal diff
, between two directories instead if two branches.
Upvotes: 110
Reputation: 4633
tl;dr: Any time you want to have two work trees checked out at the same time for whatever reason, git-worktree
is a quick and space-efficient way to do it.
If you create another worktree, most parts of the repo (i.e. .git
) will be shared, meaning if you create a branch or fetch data while you are in one work tree, it will also be accessible from any other work trees you have. Say you want to run your test suite on branch foo without having to push it somewhere to clone it, and you want to avoid the hassle of cloning your repo locally, using git-worktree
is a nice way to create just a new checkout of some state in a separate place, either temporarily or permanently. Just like with a clone, all you need to do when you are done with it is delete it, and the reference to it will be garbage collected after some time.
Upvotes: 16