Published 12-27-2023
# Start a repository using Git Worktrees
$ git clone REPOSITORY_NAME --bare
# Add a worktree (worktree name matches branch name)
$ git worktree add WORKTREE_NAME
# Navigate to a worktree
$ cd WORKTREE_NAME
# Remove a worktree
$ git worktree remove WORKTREE_NAME
# List all worktrees
$ git worktree list
# Create a worktree with better-commits
$ npm install -g better-commits
$ better-branch
Manage multiple working trees attached to the same repository
In other words, they allow you have multiple commits checked out at the same time in the same repository.
This is best explained with a common scenario.
You’re working on a web project that has dependencies like node_modules
. As you work on feature_a, an urgent bug ticket comes in. You need to switch to branch bugfix_b.
When switching branches and serving locally, you often have to do this dependency dance:
Checkout new branch BUGFIX_B
install dependencies
fix the bug
Checkout previous branch FEATURE_A
install dependencies
resume working on feature
Worktrees allow you to have multiple working trees that each have their own state. I use the term state broadly because a worktree is essentially just a folder on your machine. Thus, even editor state (such as marks, recent files, harpoon, etc…) can be maintained per branch via worktrees.
This is ideal when working on multiple branches at once, having multiple PRs open at the same time, or being able to pivot between tasks quickly.
To use worktrees, it’s recommended to use a bare repository
# --> Clone repository ✅
$ git clone YOUR_REPOSITORY --bare
# --> Create worktree 🌳
$ git worktree add main
This will checkout a new worktree (named main) at main’s HEAD.
This is a little confusing, because the worktree name and the branch name will match. — If the branch exists, it will checkout that branch. If it doesn’t exist, it will create a new branch that starts at the HEAD of main/master.
# main branch
$ git worktree add main
Preparing worktree (checking out 'main')
HEAD is now at c69d66d fix: improve docs (#9)
# existing feature branch
$ git worktree add about-me
Preparing worktree (checking out 'about-me')
HEAD is now at 7d6a74b Fix paths in prod
# new feature branch -- notice commit is same as main
$ git worktree add does-not-exist
Preparing worktree (new branch 'does-not-exist')
HEAD is now at c69d66d fix: improve docs (#9)
Running ls
you can see each worktree is represented by a folder, which are essentially separate checkouts with their own state.
Concrete example of state. If you run npm install
in each folder. Each worktree will have it’s own node_modules
.
There’s a few things that come to mind that are somewhat inconvenient when using worktrees.
everduin94/feat/X-123-example
)main
branch up to date is not as intuitive as its branch counterpart.To alleviate some of these pain points, I wrote a CLI that optimizes a few operations around working with git. (Originally, it was just for formatting commits, hence the name, better-commits).
# --> Install ✅
$ npm install -g better-commits
# --> Create worktree 🌳
$ better-branch
This runs through a list of prompts to create a common & explicit branch naming convention. If you want to use a branch naming convention like this without better-commits, the command would translate to: git worktree add WORKTREE_NAME BRANCH_NAME
. This is because worktrees will create a new folder for each slash in the worktree name (which is probably not what you want).
However, we still have a couple inconveniences. Our dependencies aren’t automatically installed, and our main
HEAD commit we create worktrees from may be out of sync with the remote. To resolve these issues we can update our .better-commits.json
.
If you’ve already ran the tool once, the file should live in your $HOME
directory. Otherwise, create the file there.
We need these two lines of configuration (see all of the options here). This will run git fetch origin main:main
, which will update the commit that our local main is pointing to with the latest commit on the remote, before creating the worktree.
{
"worktree_pre_commands": ["git fetch origin main:main"],
"worktree_post_commands": ["npm install"]
}
In the post commands, we’ll run any necessary commands after the worktree is created. npm install
is specific to certain web projects. You can add whatever is appropriate for building / serving your project locally. Any valid shell command works.
Worktrees can be a fantastic tool to work with when setup properly. Another lib/plugin you may consider using to improve your experience is something like git-worktree.nvim (or it’s equivalent in vscode, intellij, etc). This allows you to list, fuzzy find, and switch worktrees easily.
And if you like better-commits consider giving it a star on Github ⭐! Thanks for reading!