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.