Dan Varela's profile picture

Using Git Worktrees

March 19, 2026

What are Git worktrees?

Git worktrees allow you to have multiple working directories associated with a single Git repository.

Previous workflow

Picture this.

Normally, I’d:

  1. Commit a WIP: <message> commit for the current progress in feature-a
  2. 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:

  1. I’d create a worktree for feature-b, in a directory called feature-b inside the current repository using git worktree add -b feature-b ./feature-b main
  2. 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:

  1. git hash-object -t tree /dev/null Creates an empty tree object in git’s object store.

    • -t tree specifies the object type as a tree
    • /dev/null provides no content (empty)
    • Always returns the same SHA: 4b825dc642cb6eb9a060e54bf8d69288fbee4904
  2. git commit-tree <tree-sha> </dev/null Creates a commit object pointing to that empty tree.

    • Takes the SHA from step 1 as the tree
    • </dev/null provides an empty commit message via stdin
    • No -p parent flag = orphan commit (no history)
    • Returns a new commit SHA
  3. 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.

References