git worktree to have multiple branches checked out at once
On some of the projects I work on (such as this site) I'll be often multi-tasking between pieces of work. I'll be regularly context switching between branches i.e. responding to review comments, or moving further on development of a feature. One of the most painful things about this is only being able to check out one branch at a time.
That is, unless you know about
git worktree! The command allows you to have an arbitrary number of branches checked out from the same Git repo in different folders, saving you from re-cloning the repo.
Checkout out a branch
If we follow the approach of context switching, we'll use the example of having two branches open - our primary branch is
feature/h-card-entry and we will be we will be switching back and forth from
article/git-worktree-multiple-branches as review comments arrive.
repo $ git status On branch feature/hcard-entry nothing to commit, working tree clean repo $ git log commit c8340c91c458aa886a8281792e08b67c1b535056 Author: Jamie Tanna <firstname.lastname@example.org> Date: Tue Jan 29 20:45:52 2019 +0000 Configure h-card entry for me commit 99e99f47f2a81d4d6823349f40d1420e61c2b9b5 Author: Jamie Tanna <email@example.com> Date: Tue Jan 29 20:23:25 2019 +0000 New Hugo site
We've just seen some emails come in to say we've received some review comments on our second branch, so instead of
git commit /
git stashing our work and then checking out the other branch, we'll utilise
git worktree to check out the branch in a new folder
repo $ git worktree add .worktrees/article-git-worktree-multiple-branches article/git-worktree-multiple-branches Preparing worktree (checking out 'article/git-worktree-multiple-branches') HEAD is now at 4bc7724 Add article
There are a couple of things to note here that are personal choices:
- I stick all my worktrees in a
.worktreesfolder, so it doesn't clog up my root level view of the project, as well as making it easier to ignore in i.e. Vim, IntelliJ
- I convert branch names to slugs (i.e. remove the
/s) so it's easier to
Now this is done, we can now see our branch checked out in the folder:
repo $ ls .worktrees article-git-worktree-multiple-branches repo/.worktrees/article-git-worktree-multiple-branches $ cd .worktrees/article-git-worktree-multiple-branches repo/.worktrees/article-git-worktree-multiple-branches $ git log commit 4bc7724a559e966675619b1fe7ad8bc70856640e Author: Jamie Tanna <firstname.lastname@example.org> Date: Tue Jan 29 20:45:05 2019 +0000 Add article commit 99e99f47f2a81d4d6823349f40d1420e61c2b9b5 Author: Jamie Tanna <email@example.com> Date: Tue Jan 29 20:23:25 2019 +0000 New Hugo site
In the case that we want to check which branches are currently being tracked by
git worktree, we can use the
repo $ git worktree list /path/to/repo c8340c9 [feature/hcard-entry] /path/to/repo/.worktrees/article-git-worktree-multiple-branches 4bc7724 [article/git-worktree-multiple-branches]
This makes it easy to see at-a-glance which branches have been checked out where.
Making changes to these branches
These branches can be interacted with just as if we'd only got one branch checked out - we can
git push and
git pull /
git fetch to our heart's content!
One great thing about worktrees is that we don't need to worry about
git fetching everywhere - because the Git repo root is shared across all worktrees, a fetch in any worktree can be seen everywhere else!
Cleaning up branches
But what about when it gets to the point that we need to remove some of our worktrees, for instance if
article/git-worktree-multiple-branches has been merged?
repo $ git status repo $ git log master commit 4bc7724a559e966675619b1fe7ad8bc70856640e Author: Jamie Tanna <firstname.lastname@example.org> Date: Tue Jan 29 20:45:05 2019 +0000 Add article commit 99e99f47f2a81d4d6823349f40d1420e61c2b9b5 Author: Jamie Tanna <email@example.com> Date: Tue Jan 29 20:23:25 2019 +0000 New Hugo site
If we say tried to clean up our Git branches, we would see the below error:
repo $ git branch --all --merged | egrep -v "(^\*|master|develop)" | xargs git branch -d error: Cannot delete branch 'article/git-worktree-multiple-branches' checked out at '/path/to/repo/.worktrees/article-git-worktree-multiple-branches'
This is annoying, but fair enough - the same would be true if we only had one branch checked out and we'd tried to remove it. Instead, we need to
rm the directory and its contents:
repo $ rm -r worktree/feature-1 repo $ git worktree list repo $ ls -al worktree total 0 drwxr-xr-x 1 jamie jamie 0 Jan 29 20:51 . drwxr-xr-x 1 jamie jamie 18 Jan 29 20:51 ..
So now the worktree is no longer on disk, why is it still in our list of worktrees? This is because Git is clever and tracks the worktree information internally instead of relying on files on disk (this is largely due to the usecase of worktrees potentially being on network attached storage):
$ ls -al .git/worktrees/
So to clean up our branches, we'll need to run
git worktree prune:
$ git worktree prune $ git worktree list /path/to/repo c8340c9 [feature/hcard-entry]
This then shows that we've only got our
feature/hcard-entry branch checked out - great success!