I often work on several features simultaneously, which leads me to stash changes and forget about them while switching to other tasks. I tried using git hooks and terminal aliases as reminders, but they were either too much hassle or easy to ignore. So, I had to find a better solution.
This article was originally posted on my blog over a year ago but I keep coming back to it. Re-sharing it to the world :)
Git in a nutshell
Git stores information as a list of snapshots. A snapshot is a stored version of the repository at a given point in time. Each commit represents a snapshot in the git world.
The working tree is a single checkout of one version of the project. These files are pulled out of the compressed database in the Git directory and placed on disk for you to use or modify. This is the place in which you do your work before staging and committing.
Git Work Trees
Git Worktrees are a way to manage multiple git working trees at the same time without the hassle of git stash. They allow us to work on branches as sub-directories to a repository, completely alleviating the pain of stashing changes when an urgent, unrelated change is required.
The worktree module allows you to checkout multiple versions of the project in separate sub-directories in the same root directory of the repository. Take the following diagram for example on the traditional approach:
In this example I have two stashed changes (which could be hundreds of lines of code) and 3 branches, feature-1, feature-2, and fix-1. By the time I finish working on the fix-1 branch and push it my brain would've jumped to the next task and completely forgot about the previous features until I'm reminded of them again.
Instead, with worktrees, it looks like this:
With worktrees the directory structure contains each worktree (branch) in a separate directory. This allows me to seamlessly switch from a branch to another simply by changing the directory I'm currently working in. My usual workflow with this approach consists of the following:
- Open a terminal in the project's directory
- Create a worktree with a branch name
-
code .
to open VSCode in the worktree directory
When I want to switch from a worktree to another all I have to do is either create a different worktree using the same steps if I don't have it created already, or simply open a different directory with VSCode and start hacking away immediately.
Creating a worktree
Creating a worktree is as simple as running git worktree add directory-name branch-name
for existing branches or git worktree add directory-name -b branch-name
to create a new branch.
Deleting a worktree
After you're done working on a branch you can safely remove the worktree to stop polluting your directory structure. Simply run git worktree remove directory-name
. This doesn't delete the underlying branches so you can safely check them out again later.
Gotchas
Worktrees are checkouts of repository branches, therefore untracked files are not copied. Files like .env
won't be copied, so make sure to copy them after creating a worktree and install dependencies if any exist.
Also note that the directories created for the worktrees will show up in git status
logs when executed in the root repository directory. These gotchas are nothing to me compared to forgetting hours of work though.
Thank you for reading! You can read more on my blog and support my work on GitHub Sponsors!