Developer Productivity

Use Git worktrees to review PRs without stashing your work

A practical guide to using Git worktrees for isolated pull request reviews without disrupting active work, with setup commands and real-world trade-offs.

Mohammed Saqib8 min read
A clean and stylish workspace featuring dual monitors, a lamp, and office supplies.
Photo by Lee Campbell on Pexels · Pexels License

You're in the middle of debugging a flaky integration test, your terminal has four panes open, and a teammate pings you: "Can you review PR #237?" The old reflex is to git stash, switch to their branch, poke around, switch back, and hope git stash pop doesn't blow up. That reflex is costing you context switches, merge conflicts, and a brittle mental model of where your work actually is.

Git worktrees solve this by letting you check out multiple branches simultaneously in separate directories, all sharing a single repository's object store. No network round-trips, no stashing, no "did I commit that debug log or not?" anxiety.

Why stash-and-switch fails at scale

Stashing is fine for a one-line fix on a hot branch. For a PR review that spans 15 files and requires running the test suite, it breaks down in three specific ways.

First, stashing uncommitted work means you lose your working state. That half-finished refactor, those temporary console.log statements, the experimental dependency upgrade—they all go into a blob. When you pop the stash, you get a single diff applied to whatever commit you're on. If the branch has moved, or if you've changed files that the stash touches, you get merge conflicts in your stash. Resolving those is tedious and error-prone.

Second, comparing the PR branch against your working branch becomes a chore. You want to see "what did this PR actually change?" without the noise of your own uncommitted edits. You either stash, switch, diff, switch back, pop—or you run git diff with explicit branch names while praying your working tree doesn't interfere. Neither is ergonomic.

Third, if the PR needs you to run the test suite, start a dev server, or inspect rendered output, you're doing all of that in the same working directory you just disrupted. Any editor or tool that auto-reloads on file changes will pick up the branch switch and potentially corrupt your session.

The pattern doesn't scale beyond one or two reviews per day. Once you're juggling a feature branch, a bugfix review, and a spike you're exploring, stash-and-switch becomes a bottleneck.

Git worktrees: one repo, many working directories

A Git worktree is an additional working directory linked to the same repository. The original clone is your "main" worktree; every git worktree add creates another one pointing to a different branch. They share the .git objects and refs, so there's zero duplication of repository metadata. Each worktree has its own index, HEAD, staging area, and config (though most config is shared unless you use --no-checkout).

The command is straightforward:

git worktree add ../my-project-review-branch feature/foo

This creates a directory ../my-project-review-branch, checks out feature/foo into it, and registers the link. You can cd into it, run tests, edit files, commit—everything works as if it were a separate clone, but without the network cost of fetching objects again.

If the branch doesn't exist yet, you can create it from a commit:

git worktree add -b new-branch ../new-branch HEAD~3

The object store is shared, so git gc in one worktree affects all of them. This is almost always a good thing—lower disk usage, no dangling objects.

Setting up a worktree for PR review

For a typical GitHub/GitLab PR workflow, the remote branch isn't automatically fetched. You need to pull it down first. Here's the full sequence:

# Fetch the PR branch from the remote
git fetch origin pull/237/head:pr-237
 
# Create a worktree for it
git worktree add ../project-pr-237 pr-237
 
# Navigate to the new worktree
cd ../project-pr-237

Now you have a pristine checkout of the PR branch in ../project-pr-237. Your original working directory is untouched. You can:

  • Run the full test suite without worrying about your half-finished changes.
  • Open the directory in a separate editor window or terminal tab.
  • Make suggested edits, commit them, and push back to the PR branch.
  • Compare the PR against its base branch using git diff main...HEAD—clean, no interference.

When you're done:

# Clean up
cd /path/to/original/repo
git worktree remove ../project-pr-237
git branch -D pr-237  # optional, removes the local ref

The git worktree remove command cleans up both the directory and the metadata. If you accidentally delete the directory with rm -rf, the worktree metadata lingers—you'll need git worktree prune to sweep it.

Worktree management and housekeeping

As you accumulate worktrees, keeping track becomes important. git worktree list prints every linked worktree, its path, the checked-out branch, and whether it's bare or locked:

/path/to/main-repo  abc123 [main]
/path/to/project-pr-237  def456 [pr-237]
/path/to/spike  ghi789 [experiment]

If you have worktrees you want to keep around for a while—say, a long-running release branch—lock them with git worktree lock. This prevents git worktree prune from removing them even if the directory is temporarily unavailable (e.g., on a removable drive).

git worktree lock ../release-v2

Unlock with git worktree unlock.

A common mistake is to delete the worktree directory with the file manager and forget about the metadata. Later, git worktree list shows stale entries, and operations like git gc might complain. Always use git worktree remove when possible. If you can't (directory already gone), run git worktree prune to clean up dead links.

Gotchas and limits of worktrees

Worktrees are not magic. They have sharp edges.

No shared branch checkout. You cannot check out the same branch in two worktrees simultaneously. Git enforces this at the ref level. If you try, you get:

fatal: 'feature/foo' is already checked out at '/path/to/other-worktree'

If you need to work on the same branch from two places, use git worktree add --detach and manually reset the detached HEAD—but this is fragile and not recommended for normal use.

Nested git repositories cause confusion. If your project contains a submodule or a nested .git directory, creating a worktree can fail or produce unexpected behavior. Git's official worktree documentation warns against running git init inside a worktree. Submodules are generally safe if they use relative paths, but test your setup before relying on it.

Relative paths break on move. Worktrees store the path to the main repository. If you move the main repo or the worktree directory, the link breaks. You can fix it with git worktree repair, but it's easier to use absolute paths from the start, or avoid moving things once they're set up.

IDE integration is inconsistent. Visual Studio Code and JetBrains IDEs do not automatically detect worktrees as part of the same project. You'll likely need to open the worktree directory as a separate project folder. Some editors have extensions for this (e.g., VS Code's "Git Worktrees" extension), but the default experience is manual. This is a minor annoyance—you get used to it.

Worktrees vs alternatives: bare clones and sparse checkout

If worktrees aren't your style, you have other options. None are as ergonomic for ephemeral PR reviews.

Approach Setup cost Disk usage Branch switching Cleanup
Worktree One command Shared objects, separate workdir No switch needed git worktree remove
Bare clone + separate workdir Clone + checkout Duplicated objects (unless alternates) No switch needed rm -rf
Sparse checkout Config + clone Single workdir Must switch branches git checkout back
Fresh clone each time Full clone Full clone per review N/A rm -rf

A bare clone (git clone --bare) with separate working directories avoids the "can't check out same branch twice" problem, but you duplicate repository objects unless you configure Git alternates manually. That's more moving parts than most teams need.

Sparse checkout keeps a single working directory but limits which files are materialized. You still have to switch branches, which disrupts your working state. It's useful for monorepos where you only need a subset of files, not for parallel branch work.

For the PR review use case—ephemeral, isolated, zero overhead—worktrees are the clear winner. They're built into Git, require no configuration beyond the initial git worktree add, and clean up trivially.

If you're already using Reproducible Dev Environments with Dev Containers and a Single Script, worktrees complement that setup nicely: the Dev Container ensures consistent tooling, and worktrees let you context-switch between branches without rebuilding the container. Similarly, if you're managing Expo EAS Build Profiles That Keep CI Reproducible, worktrees give you a way to test build profiles against different branches locally without polluting your main working tree.

For deeper understanding of the underlying mechanics, the Git worktree documentation is authoritative and well-maintained. The Pro Git book's chapter on worktrees provides additional context on use cases like hotfix isolation.

Key takeaways

  • Git worktrees let you check out multiple branches simultaneously in separate directories, sharing repository objects with zero duplication.
  • For PR reviews, the workflow is: fetch the remote branch, git worktree add, review in isolation, git worktree remove—no stashing, no context switch.
  • Always use git worktree remove instead of deleting the directory manually to avoid stale metadata.
  • You cannot check out the same branch in two worktrees; use --detach only if you understand the risks.
  • Worktrees beat bare clones, sparse checkouts, and fresh clones for ephemeral, isolated branch work.

Frequently asked questions

What exactly is a Git worktree and how does it differ from a regular clone?
Git worktrees allow you to checkout multiple branches simultaneously in separate directories on the same repository, sharing objects but not the working tree or index. This avoids stashing or committing half-finished code when switching contexts.
Are there any known issues with using worktrees for long-running feature branches?
Yes, but you cannot check out the same branch in two worktrees. Nested worktrees cause confusion; always keep them as siblings under a common directory. Deleting a worktree only removes its working files, not the references.
How do I actually set up a worktree for a pull request without messing up my current branch?
Use `git worktree add ../pr-review origin/pr-branch` to check out a PR branch in a new directory, review it there, then `git worktree remove ../pr-review` when done. No stash or commit required.
#git#workflow#cli#productivity#pull-requests
Share

Keep reading