Using Git Worktrees
March 19, 2026What are Git worktrees?
Git worktrees allow you to have multiple working directories associated with a single Git repository.
Previous workflow
Picture this.
- You are working on a branch, say
feature-aand it involves a lot of changes, maybe a couple of dependencies being added to the project, and a couple of major directories containing many files moved. - Something came up and now you have to create a new branch, say,
feature-b, and work on it.
Normally, I’d:
- Commit a
WIP: <message>commit for the current progress infeature-a - Create and check out
feature-b, and start working there.
However, with this approach, after finishing feature-b and checking back out to feature-a, I’d usually have trouble recalling what was changed since I’d already bundled everything into one commit. So I’d run git reset --mixed HEAD~1 to unstage those changes and pick up where I left off.
This gets old fast when you’re doing it multiple times a day.
Workflow with Git worktrees
With Git worktrees:
- I’d create a worktree for
feature-b, in a directory calledfeature-binside the current repository usinggit worktree add -b feature-b ./feature-b main - Change directory into
./feature-b, and work there.
Once you cd into ./feature-b, you’re automatically on the feature-b branch. When you’re done, just run git worktree remove ./feature-b and you’re back to feature-a exactly as you left it, no stash juggling required.
Flaws with the above workflow
While this workflow is already good, one flaw is that the ./feature-b directory shows up as an unstaged change in feature-a, meaning you could accidentally include it in a commit.
A solution to this is to create the worktree outside the current working directory. So, one would do something like:
git worktree add -b feature-b ../feature-b main
And now I can just cd ../feature-b and work from there.
More improvements
But let’s take it one step further. Let’s say you keep your projects at ~/projects, and your project directory looks something like this:
projects
├── project-1
├── project-2
└── project-3
and let’s say you were working on project-1. Creating the worktree outside of it results in your projects directory looking like this:
projects
├── project-1
├── project-2
└── project-3
└── feature-b
Which is quite ugly. If you’re like me, you’d want everything related to project-1 to live inside that directory.
Which brings us to the final improvement to this workflow:
Going even further
Run the following command in your repository (make sure you have no unstaged changes)
git checkout $(git commit-tree $(git hash-object -t tree /dev/null) </dev/null)
Here’s what it does:
-
git hash-object -t tree /dev/nullCreates an empty tree object in git’s object store.-t treespecifies the object type as a tree/dev/nullprovides no content (empty)- Always returns the same SHA: 4b825dc642cb6eb9a060e54bf8d69288fbee4904
-
git commit-tree <tree-sha> </dev/nullCreates a commit object pointing to that empty tree.- Takes the SHA from step 1 as the tree
</dev/nullprovides an empty commit message via stdin- No -p parent flag = orphan commit (no history)
- Returns a new commit SHA
-
git checkout <commit-sha>Checks out that newly created orphan commit, leaving you in detached HEAD with a completely empty working tree.
Now that the repository is empty, you can create multiple worktrees inside it and simply switch directories whenever you need to context-switch.