What would I use git-worktree for?
Asked Answered
P

12

332

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 in master. 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?

Prescriptive answered 11/8, 2015 at 7:32 Comment(3)
One thing you can’t stash is unmerged paths, after a merge or rebase with conflicts.Streusel
If you work with a compiled languages, stashing means you'll have to recompile everything when you are unstashing.Angi
We have several different products based on the same (300 MB) source code, and I'm planning to combine them all into one big repo and use worktree to keep each product checked out in a different folder, rather than having a bunch of huge clones that don't stay in syncNureyev
W
343

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.

Wahl answered 11/8, 2015 at 20:19 Comment(9)
You didn't have had to fetch the same changes from the repo several times. You could have had simply copied the .git directory of the first clone.Optometry
but this would still consume more disk space?October
@mxttie Doesn't git use hard links for cloning from a disk location? (Not sure how that would work on Windows...)Quadroon
@jdk1.0 sorry for the confusion, the comment was directed at misiu_mpOctober
As somebody who has used 2-3 highly replicated repos so I can build one feature branch while developing on another, I had each local repo as remotes of the others and I agree completely with Sebi's characterizations of the downsides (lots of fetching and pushing!) Also, once I switch to worktree I gather that I will no longer have to worry about local, same-named branches diverging (which happens about once every 6-10 months as I get interrupted multiple times over a period of days and end up working the same feature branch out of multiple repos, but forget to sync them back up...)Sirois
Reasons for my downvote. . .in order for this answer to make sense, I need to already know the answer! 1. How is an independent project any faster than switching your IDE to the new clone? 2. If you have a worktree, which checks out in a separate folder, how does that save space over a clone?Sparing
@Sparing — (1). It's faster if the IDE maintains external data files (such as indexing databases) associated with a given directory. If you thrash the content in the same directory, that will typically invalidate any IDE data caches, and it will have to re-index.Bartley
@Sparing — (2) Over time, the history of everything will grow much larger than the working tree files at any given point. The history of everything == the .git directory. With many local clones from the upstream, you have many local copies of the same database, since each clone has its own .git database. With many local working trees, each tree uses the same .git database. Yes, if you have local clones of your local worktree, Git will hard-link a lot of the .git contents, but not on Windows.Bartley
@SteveHollasch Yes, but this speaks to my point. The answer is pretty poorly written. If one didn't already know these things, it would be hard to elucidate them from the answer as being benefits of using git worktree over a clone. The questions I asked were pointing out specific aspects that are important to answering the original question which seem glossed over here and I think would still leave someone, who didn't understand what git worktree does, confused in that regard.Sparing
P
104

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.

Prostyle answered 11/8, 2015 at 7:45 Comment(6)
Wouldn't git clone work just as well for all of these?Jezreel
It would but cloning a big repository from the remote can take a long time. I'm working against one repository that takes several minutes to clone. I guess that you could do it with git clone --reference. Also, management of all other branches will be done just once instead of once per working directory.Prostyle
Don't clone from the remote, clone from your local one. I don't understand the branch-management issue, can you clarify?Jezreel
I tried to use clones, and there really is a management issue. Instead of single set of branches I have a set of clones, which I cannot see all together in single UI. If I need to cherry-pick some changes I have to fetch or push them around. It adds additional steps to all actions. Everything is doable, but there is always some friction.Salvidor
And when it comes to setting up a backup, single repository is so much easier.Salvidor
We can keep cloning for each branch. But that will consume disk space. Yes, to save bandwidth, you can clone local repo. What if your repo is 300MB and you need to work on 3 issues, would you clone 3 time, so you reach 1GB. What if you have mono-repo kind of setup where size generally big, would we clone multiple times. gi work tree solves this issue beautifully. I feel, people should not take disk space and Network bandwidth as cheap ones. If worktree can be adopted, number of repo in you org will reduce significantly...Zuleika
H
86

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

Hydrochloride answered 29/9, 2015 at 17:27 Comment(7)
I don't see how this explains the benefit of using worktree for this purpose over a clone.Sparing
@Sparing You could say the same about branch; the answer is the same too: it's lighter weight, and built for the job.Syconium
@Syconium that's kinda the point. This answer does not explain to me what worktree does that's different. It's obviously not an alias for branch or clone but the effect I'm seeing here seems to be the same. I don't see how this is any lighter weight than just using branch or clone.Sparing
@Sparing It's different than using branch - you can't use branches alone to get multiple states of worktree at once - and lighter weight than a second (.., nth) clone. What I meant was that you could say also of branch 'why not just clone and make your changes', but multiple branches in a single repo are a lighter weight and more easily managed way of getting that behaviour.Syconium
@Syconium I don't think this resolves my confusion with worktree. Let me put it this way, whether you use branch or clone or something else, the end goal of the process described here is to compare three different versions of something simultaneously. Based on what's in the answer, I don't understand why I'd use worktree over some alternative. The answer does not explain what worktree is doing that alternatives are not. You make a claim about something being lightweight (or lighter weight) but I don't see how worktree makes the branches any less "weighty".Sparing
@Syconium your last comment seems to suggest that one uses worktree to get multiple lightweight branches - but if that's the case, why are the git branch commands needed at all? Is the sequencing just explained poorly? Could I get the same end result if I reordered things so all the branch and edits happened first, then I carried out all the worktree commands last?Sparing
@Sparing I think the clearest bit of the answer is the final paragraph/bullet points: you can view the state of 'page1.html' on three different branches (or other ref) simultaneously. You can't achieve that just with branches, you need to use either clone or worktree as well. Worktree avoids the extra disk space and network usage that clone would use. (That's what I meant by 'lighter weight'.) It's also clearer semantically what you're doing than having a mess of myrepo1, myrepo2, myrepo3, and coming back to it wondering why you have three clones of the same repo and which you should be using.Syconium
P
41
  1. 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.

  2. 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:

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

      • Running 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.
    2. You can share refs between worktrees. If you want to compare or borrow changes from another local branch, now you can.

Pontormo answered 29/9, 2015 at 16:44 Comment(2)
Also you can list all worktrees with a single command, with clones you need to keep track of them yourself.Mammet
hmm. As of git 2.7.0 that seems to be the case. Nice to know.Pontormo
S
36

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

Sammysamoan answered 15/11, 2020 at 18:11 Comment(4)
won't you be reviewing on a platform like GitHub? What's the workflow for locally reviewing PRs?Aminta
@AyushMandowara In some cases the reviewer might want to run the code locally, to have a look at the UI, for example.Frag
@AyushMandowara locally you can use tig to browse the changes, you can add notes using git notes, you can git diff arbitrarily etc. etc.Longsufferance
I really want to see complicated diffs in the ui of my choice (KDiff3 in my case), not in the mediocre browser view we've got at work.Ludeman
C
15

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.

Carmina answered 22/4, 2016 at 7:32 Comment(1)
This is the same use case I use worktree for, plus you don't have to keep fetching from multiple clones of the same repos, saving bandwidth and time. I also save many GBs on my precious NVMe SSD since you only have one .git instance with the metadataGadolinite
P
14

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.

Phonetics answered 11/8, 2015 at 20:5 Comment(7)
Docs say you can't have the same branch in both working copies, which is a serious limitation. With Mercurial, it worked with only small issues.Presidency
Sure you can. The man page says how; look for --force. But it's inconvenient if you update the branch in one place and expect to work on it in another, since the worktree is not updated.Phonetics
Yep, branches in Mercurial are a more transparent concept in this aspect. How do branches from one worktree appear in the other? Same way as multiple uplinks? My first experiments with worktrees, with running fetch in both, ended up with two (!) different (!) pointers named origin/master.Presidency
A worktree is (as the name implies) just a worktree, with some extra added features; the repository is shared between all worktrees. The only difference between two worktrees is that the checked-out branch can be (and for sane workflows, is) different. It is possible to commit in a separate worktree, so it also has its own index (a.k.a. staging area) to make that work. The .git file in the separate worktree is a text file containing the path to its configuration, which resides in the original repository.Phonetics
@jsageryd: If I understand the documentation (and it's entirely possible I'm mis-reading it), it's possible to create a worktree that is checked out to a branch that is already checked out in another worktree, correct? If so, that's kind of good, but it's a shame that git checkout doesn't also have a --force flag (at least, not that I can make work) to allow one to do the same thing after the worktree has been created.Sporulate
@WilsonF: git checkout --ignore-other-worktrees <branch> git-scm.com/docs/git-checkout/…Phonetics
I would say it's better to just create a temporary branch at the same commit if you want to check out two copies of the same commit at the same time.Nureyev
W
8

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.

Wickerwork answered 18/7, 2016 at 22:59 Comment(1)
+1 This seems like a very effective workaround for Make not doing per-configuration build output directories natively. I have a similar VMware Workstation setup with Ubuntu and macOS guests.Air
A
5

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.

Artless answered 17/6, 2019 at 20:31 Comment(0)
C
4

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:

  1. You might need to recompile the whole project, and/or other build steps (e.g. building documentation)
  2. You have tools that rely on indexing the project (which happens to be the working tree of this repository), and changing the worktree can trigger an aggressive reindex if the worktree changes substantially
  3. You just started a program which relies on the content of your working tree (or derived files like compilation artifacts) to stay the same, but you either need to change task right now because something came up or you would be twiddling your thumb since you can’t change the working tree (e.g. because you started the test suite[3]).

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:

  1. Now you have three repositories to manage instead of one

    • Maybe you constantly fetch the remote refs in 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 work
    • If you ever need local branches from these three clones (say in both main-repo and restructuring) then you might end up either creating mutual remotes or going through an intermediary (like the central repository)
    • The repository might be so large that running maintenance tasks on it regularly might be something that you want to do[4]
  2. You have three repositories, which means you have three object databases with mostly the same contents

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

  1. All worktrees share the same repository, so you can manage things like git fetch in any one of the worktrees and be done with it
  2. No nearly-duplicate object databases
  3. All worktrees know about each other: git worktree list

Other uses

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:

  • Checkout a new worktree
  • Checkout the branch and detach (“detached head”)
  • Attempt the merge

Notes

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

  2. “The tree of actual checked out files.”, according to man gitglossary, Git 2.40.0

  3. One of the examples in the GitHub article: “So suppose that you want to run long-running tests on the current commit.”

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

Cunctation answered 16/4, 2023 at 9:34 Comment(0)
P
4

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.

Paramaribo answered 17/4, 2023 at 12:18 Comment(0)
S
2

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.

Snipes answered 12/9, 2016 at 6:34 Comment(1)
How does a worktree make this any easier than a clone, though? The question isn't asking for personal preference, but concrete differences.Algorism

© 2022 - 2024 — McMap. All rights reserved.