Skip to content

Web Development · Developer Tooling

Git Worktrees: Check Out Multiple Branches at Once Without the Stash Dance

Git worktrees let you have multiple branches checked out simultaneously in separate directories. No stashing, no context switching, no 'just a second while I save my work.'

Anurag Verma

Anurag Verma

6 min read

Git Worktrees: Check Out Multiple Branches at Once Without the Stash Dance

Sponsored

Share

The pattern is familiar: you’re deep in a feature branch, tests aren’t passing yet, and a Slack message arrives asking you to quickly check something on main or fix a bug on a release branch. You stash your work, switch branches, do the thing, switch back, pop the stash, and try to remember where your head was.

Git worktrees eliminate this entirely. A worktree is a second (or third, or fourth) checkout of the same repository in a separate directory. Each worktree has its own branch, its own working tree state, and its own HEAD. You switch between them by switching directories, not by switching branches.

The Basic Setup

# You're on feature/auth-rewrite in your main checkout
# You need to check something on main without disrupting your work

git worktree add ../project-main main
# Creates a new directory ../project-main checked out to main

# Work in the new directory
cd ../project-main
npm install  # each worktree has its own node_modules
git log --oneline -5

# Come back to your feature work
cd ../project
# feature/auth-rewrite is still exactly where you left it

The ../project-main directory is a full checkout. You can run your dev server, run tests, make commits. It’s all linked to the same .git database, so you’re not duplicating the git history, just the working files.

Common Patterns

Reviewing a PR Without Touching Your Current Work

This is the most immediate use case. A colleague opens a PR and you want to run it locally:

# Fetch the branch
git fetch origin pr-branch-name

# Create a worktree for the review
git worktree add ../project-review origin/pr-branch-name

# Run it
cd ../project-review && npm install && npm run dev

When you’re done reviewing:

git worktree remove ../project-review

Parallel Feature Development

AI-assisted development makes this pattern especially useful. You’re generating and testing one feature while another generates. Each feature lives in its own worktree so tests can run independently:

git worktree add ../project-auth feature/new-auth
git worktree add ../project-payments feature/payment-rework

# Terminal 1
cd ../project-auth && npm test -- --watch

# Terminal 2  
cd ../project-payments && npm test -- --watch

# Terminal 3
cd ../project && git log --all --oneline

No context switching. Each test suite runs against its own branch. Changes in one don’t bleed into the other.

Running the Previous Version While Working on the Next

Useful for debugging regressions: run the last stable release in one worktree while editing the current branch in another.

git worktree add ../project-stable v2.4.1

# The stable version runs at localhost:3001
cd ../project-stable && PORT=3001 npm run dev

# The development version runs at localhost:3000
cd ../project && npm run dev

# Compare behavior directly

Hotfix While Mid-Feature

The original problem the stash dance solves:

# You're mid-feature
git worktree add ../project-hotfix main

cd ../project-hotfix
git checkout -b hotfix/login-crash
# fix the bug
git commit -m "fix: null check on login response"
git push origin hotfix/login-crash
# open PR, merge, done

git worktree remove ../project-hotfix

# Back to your feature, undisturbed
cd ../project

Listing and Managing Worktrees

# See all worktrees
git worktree list
/home/user/project                  abc1234 [feature/auth-rewrite]
/home/user/project-main             def5678 [main]
/home/user/project-review           ghi9012 [pr-branch]
# Remove a worktree (the directory must be clean)
git worktree remove ../project-review

# Remove even if there are untracked files
git worktree remove --force ../project-review

# Prune stale worktree references (after manually deleting a directory)
git worktree prune

One constraint: the same branch cannot be checked out in two worktrees simultaneously. If you try, git rejects it. This prevents the confusing situation where changes in one worktree conflict with changes in another on the same branch.

Setting Up Node.js Projects in Worktrees

Each worktree has its own working directory, which means node_modules is independent. You need to run npm install (or pnpm install or bun install) in each worktree separately.

For large projects where npm install takes a while, this is the main overhead of worktrees. A few strategies:

Use pnpm with a shared store. pnpm’s content-addressed store is global, so pnpm install in a worktree re-uses cached packages rather than re-downloading them. The install is fast even for large dependency trees.

# In each worktree
pnpm install  # fast: links from the global store

Skip the install if the branch has the same package.json. If you’re creating a worktree from a branch that hasn’t changed package.json relative to main, you can symlink node_modules:

git worktree add ../project-hotfix main
ln -s $(pwd)/node_modules ../project-hotfix/node_modules

This works as long as you don’t need different packages. If the branches diverge in dependencies, symlink becomes a problem.

Use direnv with per-worktree .envrc. If each worktree needs different environment variables (different ports, different DATABASE_URL), .envrc files that are gitignored make this easy:

# ../project-hotfix/.envrc
export PORT=3001
export DATABASE_URL=postgres://localhost/myapp_hotfix

Worktrees and Your Editor

Most editors handle worktrees well because they work with directories, not git checkouts specifically.

VS Code: Open a worktree directory with code /path/to/worktree. It opens as a separate window with its own workspace. The Source Control panel shows the branch and changes for that worktree. You can have four VS Code windows open, each on a different branch.

JetBrains IDEs: Open the worktree directory as a new project. Git operations work correctly within each window.

Neovim/vim: No special handling needed. Open files from the worktree directory normally.

The one case that gets awkward is if your editor opens the project root by looking for .git. Since all worktrees link back to the same .git directory, some tooling can get confused about which branch it’s on. This is rare in practice.

What Worktrees Don’t Do

Worktrees solve the “multiple branches at once” problem. They don’t replace:

  • Feature branches for code isolation. Worktrees are a checkout mechanism, not a branching strategy. You still need separate branches for separate features.
  • CI/CD. Running tests locally across worktrees is useful for quick feedback. Real validation still happens in CI.
  • stash for quick temporary saves. If you just want to temporarily shelve two lines of debug code while you look at something, git stash is faster than a worktree.

The worktree mental model is: each worktree is a separate concern that’s going to live long enough to warrant its own directory. For anything that takes more than a few minutes, a worktree is usually cleaner than a stash.

The Setup That Pays Off

For a team where everyone uses AI coding assistants to work on multiple things in parallel, worktrees become a natural part of the workflow. Set up aliases to make the common operations fast:

# ~/.gitconfig
[alias]
  wt-add = "!f() { git worktree add \"../${PWD##*/}-$1\" $2; }; f"
  wt-list = worktree list
  wt-rm = worktree remove
# Usage
git wt-add hotfix main          # creates ../project-hotfix on main
git wt-add review origin/pr-42  # creates ../project-review on a PR branch
git wt-list                     # see all active worktrees
git wt-rm ../project-hotfix     # clean up when done

The stash dance is worth skipping. Worktrees are the cleaner option for anything that will take more than a few minutes.

Sponsored

Sponsored

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored