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 need to recompile the whole project, and/or other build
steps (e.g. building documentation)
- 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
- 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:
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]
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):
- 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
- No nearly-duplicate object databases
- 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
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.