Git Worktrees: Work on Multiple Branches Simultaneously
Git Worktrees: Work on Multiple Branches Simultaneously

Every developer has been in this situation: you are deep in a feature branch, you have uncommitted changes across several files, and someone asks you to review a pull request or fix an urgent bug on main. Your options are bad. You can stash your work (and hope the stash applies cleanly later), commit half-finished work with a "WIP" message, or just say "give me 20 minutes" while you save and switch context.
Git worktrees eliminate this problem. A worktree is a separate working directory linked to the same repository. You can have your feature branch checked out in one directory and main in another, simultaneously. Each directory has its own working tree and index, but they share the same .git objects, refs, and history. No cloning. No stashing. No context switching.
How Worktrees Work
A standard Git repository has one working directory associated with it. When you run git checkout main, your entire working directory changes to reflect the main branch. Worktrees let you check out additional branches in separate directories, all linked to the same repository.
The key insight is that the .git directory (the object store, refs, hooks, and config) is shared. Each worktree gets its own HEAD, index, and working tree, but they all reference the same underlying data. This means:
- Creating a worktree is nearly instant (no data copying)
- Disk usage is minimal (only the checked-out files, not duplicated history)
- Commits made in any worktree are visible to all worktrees
- You cannot have the same branch checked out in two worktrees simultaneously
Creating Worktrees
Check out an existing branch
# From your main project directory
git worktree add ../project-feature feature-branch
This creates a new directory ../project-feature with feature-branch checked out. The original directory remains on whatever branch it was on.
Create a new branch in a worktree
# Create a new branch and check it out in a worktree
git worktree add -b hotfix/login-bug ../project-hotfix main
This creates a new branch hotfix/login-bug based on main and checks it out in ../project-hotfix.
Check out a detached HEAD
# Useful for reviewing a specific commit or tag
git worktree add --detach ../project-review v2.1.0
Managing Worktrees
List active worktrees
git worktree list
Output:
/home/dev/project abc1234 [main]
/home/dev/project-feature def5678 [feature-branch]
/home/dev/project-hotfix ghi9012 [hotfix/login-bug]
Remove a worktree
# Remove the worktree (the branch remains intact)
git worktree remove ../project-hotfix
# Force removal if there are untracked or modified files
git worktree remove --force ../project-hotfix
Clean up stale references
If you manually delete a worktree directory instead of using git worktree remove, the reference remains. Clean it up with:
git worktree prune
Lock a worktree
Prevent a worktree from being pruned (useful for worktrees on removable media):
git worktree lock ../project-feature --reason "Active development"
git worktree unlock ../project-feature
Practical Workflows
Workflow 1: PR Review Without Context Switching
You are working on a feature. A teammate asks you to review their PR.
# You're in ~/project on feature/new-dashboard
# Create a worktree for the PR branch
git fetch origin
git worktree add ../project-review origin/fix/user-auth
# Open the review worktree in your editor
code ../project-review
# Run tests in the review worktree
cd ../project-review && npm test
# After the review, clean up
git worktree remove ../project-review
Your feature branch work is completely untouched. No stashing, no WIP commits.
Workflow 2: Hotfix While Developing
Production is broken. You need to ship a fix from main, but your feature branch has hours of uncommitted work.
# Create a worktree for the hotfix off main
git worktree add -b hotfix/fix-payment ../project-hotfix main
# Work on the fix
cd ../project-hotfix
# ... make changes ...
git add -A && git commit -m "fix: resolve payment processing timeout"
git push origin hotfix/fix-payment
# Clean up after the hotfix is merged
cd ~/project
git worktree remove ../project-hotfix
Workflow 3: Comparing Implementations
You want to try two different approaches to the same problem:
# Approach A
git worktree add -b experiment/approach-a ../project-a main
# Approach B
git worktree add -b experiment/approach-b ../project-b main
# Work on both, benchmark, compare
# Keep the winner, remove the loser
git worktree remove ../project-a
git worktree remove ../project-b
Workflow 4: Running Tests on a Different Branch
You want to run the test suite against main while continuing to develop:
git worktree add ../project-main main
# In a separate terminal
cd ../project-main && npm test
# Your development continues uninterrupted in ./project
Directory Layout Conventions
A consistent naming convention makes worktrees easier to manage. Here are two common approaches:
Sibling directories
~/code/
project/ # main worktree (main branch)
project-feature/ # feature branch worktree
project-hotfix/ # hotfix worktree
Bare repository with worktree subdirectories
# Clone as bare repo
git clone --bare [email protected]:user/project.git project.git
# Create worktrees inside a containing directory
cd project.git
git worktree add ../project/main main
git worktree add ../project/feature feature-branch
This layout:
~/code/
project.git/ # bare repo (no working tree)
project/
main/ # main branch worktree
feature/ # feature branch worktree
The bare repository approach is cleaner when you use worktrees as your primary workflow rather than an occasional tool.
Editor Integration
VS Code
VS Code works well with worktrees. Open each worktree as a separate window:
# Open worktrees in separate VS Code windows
code ~/project
code ~/project-feature
Each window has its own Git state, terminal, and file tree. VS Code detects the branch automatically.
For a smoother workflow, use the Git Worktrees extension, which adds commands to create, switch, and remove worktrees from within VS Code.
Neovim
If you use telescope.nvim, the telescope-git-worktree plugin provides fuzzy finding across worktrees:
-- Install via lazy.nvim or your plugin manager
{ "ThePrimeagen/git-worktree.nvim" }
-- Keybindings
vim.keymap.set("n", "<leader>gw", function()
require("telescope").extensions.git_worktree.git_worktrees()
end)
vim.keymap.set("n", "<leader>gW", function()
require("telescope").extensions.git_worktree.create_git_worktree()
end)
JetBrains IDEs
IntelliJ, WebStorm, and other JetBrains IDEs support worktrees natively. Go to Git > Manage Worktrees to create and switch between them. Each worktree opens as a separate project with its own run configurations.
Shell Aliases
Add these aliases to your shell configuration to streamline worktree management:
# ~/.bashrc or ~/.zshrc
alias gwl="git worktree list"
alias gwa="git worktree add"
alias gwr="git worktree remove"
alias gwp="git worktree prune"
# Quick worktree for PR review
gw-review() {
local branch="$1"
local dir="../$(basename $(pwd))-review"
git fetch origin
git worktree add "$dir" "origin/$branch"
echo "Worktree created at $dir"
}
# Quick cleanup of all non-main worktrees
gw-clean() {
git worktree list --porcelain | grep "^worktree" | tail -n +2 | \
awk '{print $2}' | while read wt; do
echo "Removing $wt"
git worktree remove "$wt"
done
}
Gotchas and Limitations
Cannot check out the same branch twice: Git prevents this to avoid conflicting changes. If you need the same branch content in two places, use --detach for the second worktree.
Submodules require extra steps: If your repository uses submodules, you need to run git submodule update --init in each new worktree.
Node modules and build artifacts: Each worktree has its own node_modules directory. You need to run npm install (or your package manager of choice) in each worktree independently. The same applies to build artifacts, virtual environments, and other generated files.
Hooks are shared: Git hooks live in .git/hooks, which is shared across all worktrees. A pre-commit hook runs the same way in every worktree.
Branch deletion: You cannot delete a branch that is checked out in any worktree. Remove the worktree first, then delete the branch.
When to Use Worktrees
Worktrees are most valuable when you frequently switch contexts. If you only work on one branch at a time and rarely need to interrupt your work, stashing or WIP commits are fine. But if any of these apply to you, worktrees will save time:
- You review PRs regularly and want to test them locally
- You are on-call and need to ship hotfixes at any time
- You run long test suites and want to keep developing while they run
- You compare different implementations side by side
- You maintain multiple release branches simultaneously
The cost is minimal -- a few extra megabytes of disk space and one extra command to set up. The benefit is never losing your working context again.