Git Worktrees

In the recent weeks I am working on a big feature of our system, with a lot of changes, and a decent development time. But since life doesn't stop, I still have to respond to maintenance requests and bug fixes, which means I frequently have to switch between branches. The initial method I learnt many years ago was to commit or stash my changes, checkout the other branch, do the fix, commit, push, and then come back to the original code.

Needless to say, this is a lot of switching, stashing, committing - a lot of room for errors and making a mess in the repository.

Couple of weeks ago I came across an article, which introduced a very interesting concept to me, Git Worktrees.

This feature basically allows me to checkout multiple branches of the same repository, but without the overhead of checking out the whole project again. The worktree points to a folder in your file system, and references a branch, but working from the same clone.

Listing worktrees

To see all available worktrees, you can use the git worktree list command:

git worktree list
/Users/balazssebesteny/Sites/balazs.sebesteny.com  53b470d [main]

Creating a new worktree

Let's assume you are working on a feature, but an urgent bugfix request came in. To create a worktree for an existing branch, you can use the following :

git worktree add ../balazs.sebesteny.com-bugfix-01 bugfix-01
Preparing worktree (new branch 'bugfix-01')
branch 'bugfix-01' set up to track 'origin/bugfix-01'.
HEAD is now at 53b470d SEO

If we take a look into the new folder created, we can see that there is no .git folder, but only a single .git file:

ls -la ./
total 1496
drwxr-xr-x@ 18 balazssebesteny  staff     576 25 Jul 13:40 .
drwxr-xr-x  40 balazssebesteny  staff    1280 25 Jul 13:40 ..
-rw-r--r--@  1 balazssebesteny  staff     104 25 Jul 13:40 .git
-rwxr-xr-x@  1 balazssebesteny  staff      88 25 Jul 13:40 .gitignore
-rw-r--r--@  1 balazssebesteny  staff      53 25 Jul 13:40 .npmrc
-rwxr-xr-x@  1 balazssebesteny  staff     952 25 Jul 13:40 README.md
...

This contains the reference to the original clone's .git folder, and ensures that our usual Git commands are working:

cat ..git
gitdir: /Users/balazssebesteny/Sites/balazs.sebesteny.com/.git/worktrees/balazs.sebesteny.com-bugfix-01

And we can see our bugfix-01 branch checked out:

git status
On branch bugfix-01
Your branch is up to date with 'origin/bugfix-01'.

nothing to commit, working tree clean

At the end of the day we can implement our fix in this folder, test it, commit and push it, and done.

Creating a new worktree along with a new branch

If we didn't create out bugfix branch in our repository provider UI, we can always do it like this:

git worktree add ../balazs.sebesteny.com-bugfix-02 origin/main -b bugfix-02
Preparing worktree (new branch 'bugfix-02')
branch 'bugfix-02' set up to track 'origin/main'.
HEAD is now at 53b470d SEO

Deleting worktrees

Once we finished our work in the extra worktrees, we can simply remove them:

git worktree list
/Users/balazssebesteny/Sites/balazs.sebesteny.com            53b470d [main]
/Users/balazssebesteny/Sites/balazs.sebesteny.com-bugfix-01  53b470d [bugfix-01]
/Users/balazssebesteny/Sites/balazs.sebesteny.com-bugfix-02  53b470d [bugfix-02]

git worktree remove ../balazs.sebesteny.com-bugfix-01
git worktree remove ../balazs.sebesteny.com-bugfix-02

git worktree list
/Users/balazssebesteny/Sites/balazs.sebesteny.com  53b470d [main]

Pros and cons

The big advantage is that we don't have to clone the repository multiple times, the .git folder is shared, our worktrees will use the same git config, if you fetch in any of the worktrees it will fetch in all, etc.

One arguable disadvantage is that you will end up multiple top level directories, which can be inconvenient from an organising point of view.

And one more sidenote, one branch can only have one worktree.