Git Worktree: A Practical Guide to Working in Multiple Places at Once

The Problem It Solves#
If you've used Git for any length of time, you've almost certainly run into this situation: you're deep in the middle of something, maybe a refactor, a feature, or a stubborn bug, and suddenly you need to switch gears. A colleague needs you to review their branch. A bug report comes in that needs a hotfix. You need to compare the current behavior on main with what you're building.
The classic solution is git stash followed by git checkout, do your thing, then git checkout back and git stash pop. It works, but it's disruptive. You lose your place, your editor reloads, your build cache gets invalidated, and you have to mentally context-switch twice.
The other classic solution is cloning the repository a second time. That works too, but it's wasteful. You now have two full copies of every file, two copies of the .git directory with all its objects, and they have no awareness of each other.
git worktree solves both problems. It lets you check out multiple branches simultaneously, each in its own directory, all sharing a single .git object store. You can have main open in one terminal window, your feature branch in another, and a hotfix in a third, all at once and all independent.
And recently there's a new dimension to this: AI coding agents have made worktrees not just useful but practically essential. We'll get to that in detail. First, the fundamentals.
The Core Concept: One Repository, Many Working Trees#
To understand worktrees, it helps to think about what Git actually is under the hood. Your repository has two distinct parts:
| Part | Meaning |
|---|---|
| Object store | The .git folder. This is where Git stores commits, file contents across branches, refs, and history. Think of it as the database. |
| Working tree | The directory you actually work in: the files you edit, compile, and run. It is a view into the object store at a particular point in time. |
Normally, one .git folder maps to exactly one working tree. Git worktree breaks that assumption. With worktrees, one .git folder can power multiple working trees simultaneously, each checked out to a different branch.
The original working tree, the one in the same directory as .git, is the main worktree. Any additional directories you create are linked worktrees.
Getting Started: Basic Commands#
Adding a New Worktree#
The fundamental command is git worktree add:
git worktree add <path> [<branch>]
Let's say you're on a feature branch and need to quickly check something on main:
# Creates a new directory ../project-main and checks out the main branch there
git worktree add ../project-main main
Now you have two working directories:
~/dev/project/: your feature branch, exactly as you left it~/dev/project-main/: themainbranch, ready to use
You can cd into either one independently. They share history, refs, and the object store, but their working trees are completely separate.
Listing Your Worktrees#
git worktree list
This gives you a clear picture of what's open:
/home/you/dev/project abc1234 [feature/my-feature]
/home/you/dev/project-main def5678 [main]
Removing a Worktree#
When you're done with a linked worktree, you can remove it:
git worktree remove ../project-main
This deletes the directory and cleans up the internal tracking data. If the worktree has uncommitted changes, Git will refuse and tell you, which is a useful safety net. You can force it with --force if you're sure.
You can also just manually delete the directory, then run:
git worktree prune
This cleans up any stale worktree references that point to directories that no longer exist.
Creating a Worktree for a New Branch#
Often you don't want to check out an existing branch in a new worktree. You want to create a new branch and start working there. The -b flag does exactly that:
# Create a new branch called hotfix/login-crash and check it out in a new directory
git worktree add -b hotfix/login-crash ../project-hotfix main
Here, main is the starting point. Git creates the new branch at that commit and checks it out. This is the worktree equivalent of git checkout -b new-branch.
The Detached HEAD Case#
You can also check out a specific commit without a branch name. This is useful for things like reviewing an old release or running a bisect:
git worktree add --detach ../project-v1.2 v1.2.0
The --detach flag is technically optional if you're passing a commit hash rather than a branch name.
Other Useful Options#
A few other git worktree options are worth knowing once the basic flow is comfortable:
-B <branch>is like-b, but resets the branch to the starting point if it already exists. Useful when you want to recreate a throwaway worktree from a known base.--no-checkoutcreates the worktree directory and wires it up without populating the files. This is handy if you want to configure sparse checkout before materializing a large repository.--orphan <branch>creates a new branch with no history, checked out in the new worktree. This is useful for branches such asgh-pagesthat intentionally have no relationship to your main history.--lockmarks the worktree as locked immediately after creation, so it can't be accidentally removed withgit worktree remove. You can also usegit worktree lock <path>andgit worktree unlock <path>later.git worktree move <worktree> <new-path>moves a worktree to a different location on disk and updates Git's internal bookkeeping.
Real-World Use Cases#
Hotfix While Mid-Feature
This is the classic scenario. You're working on a long-running feature branch when a critical bug is reported in production.
# You're currently in ~/dev/myapp, on feature/new-dashboard
# Create a worktree for the hotfix, branching off main
git worktree add -b hotfix/payment-null-error ../myapp-hotfix main
# Switch to the hotfix directory
cd ../myapp-hotfix
# Fix the bug, commit, open a PR
# ... fix, fix, fix ...
git add .
git commit -m "fix: handle null payment method in checkout"
# When done, remove the worktree
cd ../myapp
git worktree remove ../myapp-hotfix
Your feature branch in ~/dev/myapp was never touched. Your editor, your build cache, and your mental state all stay intact.
Running Two Environments Side by Side
Sometimes you need to compare behavior between branches: a performance regression, a visual change, or a behavior difference you can't easily unit-test. With worktrees, you can run both at the same time:
git worktree add ../myapp-main main
# Terminal 1: run the current feature
cd ~/dev/myapp && npm run dev -- --port 3000
# Terminal 2: run main for comparison
cd ~/dev/myapp-main && npm run dev -- --port 3001
Now you can open both at localhost:3000 and localhost:3001 simultaneously. This is dramatically cleaner than stashing, switching, and trying to remember what you were seeing.
Long-Running CI or Build
If you need to trigger a long build or test suite on a branch, but don't want to sit around waiting before you can keep working, worktrees are perfect:
git worktree add ../myapp-release release/2.0
# Terminal 1: run the release build (takes 10 minutes)
cd ../myapp-release && make build-production
# Terminal 2: keep developing in your main worktree
cd ~/dev/myapp && # carry on with your day
Code Review Without Context-Switching
When reviewing a colleague's PR, you often want to actually run their code, not just read it on GitHub. With worktrees, you can do this without abandoning your current work:
git fetch origin
git worktree add ../review-pr-142 origin/feature/teammate-feature
cd ../review-pr-142
npm install && npm start
# Review, leave comments, done
git worktree remove ../review-pr-142
Git Bisect in a Worktree
Running git bisect in your main worktree is annoying because it keeps changing your checked-out code. Put the bisect in a dedicated worktree instead:
git worktree add --detach ../bisect-run main
cd ../bisect-run
git bisect start
git bisect bad HEAD
git bisect good v1.8.0
# Git will check out commits for you to test
# Run your tests, mark each commit good or bad
git bisect good # or: git bisect bad
# When bisect identifies the culprit, clean up
git bisect reset
cd ../myapp
git worktree remove ../bisect-run
Worktrees in the AI Coding Era#
Up to this point, everything above is the same advice you'd have read in 2018. But the most consequential reason to learn worktrees today is one that didn't exist back then: you're probably going to be running AI coding agents alongside, or instead of, writing code yourself. Worktrees are the cleanest way to do that without your agents tripping over each other.
Why AI Agents Need Isolation#
Most AI coding agents, from Claude Code and GitHub Copilot CLI to Codex, Cursor's background agents, and Gemini CLI, work directly against your filesystem. They read your files, edit them in place, run your tests, and execute commands in your working directory, usually with the implicit assumption that nothing else is changing those files at the same time.
That assumption is fine when you run one agent. It falls apart the moment you want to run two. Picture an agent rewriting your auth module while a second agent, running in another terminal, is mid-refactor of the same module. The result is a smear of half-applied changes, the kind of corrupted state that's painful to diff and harder to undo.
This comes up quickly once agents become part of your normal workflow. You might ask one session to fix a flaky test while another explores a UI change, then review both when they are done. Worktrees give each task its own branch and directory, so the agents are not editing the same files out from under each other.
The pattern is simple:
my-app/ ← you live here, reviewing and directing
my-app-feature-auth/ ← agent 1: implementing auth
my-app-bugfix-api/ ← agent 2: fixing an API regression
my-app-refactor-db/ ← agent 3: refactoring the data layer
Three agents, three branches, three working trees, one repo. They share history. They don't share files in flight.
Claude Code#
Anthropic's Claude Code ships first-class, built-in worktree support in the CLI. The desktop app goes a step further: every new session there gets its own worktree automatically, with no flag required.
The core CLI command is straightforward:
claude --worktree feature-auth
That single invocation creates an isolated worktree at .claude/worktrees/feature-auth/ on a new branch called worktree-feature-auth, then launches a Claude session scoped to that directory. If you omit the name, Claude generates one such as bright-running-fox. You can also tell Claude in the middle of a session to "work in a worktree" and it will create one on the fly via its built-in EnterWorktree tool.
For multiple parallel sessions, you just run the command in different terminals with different names:
# Terminal 1
claude -w feature-auth
# Terminal 2
claude -w bugfix-api
# Terminal 3
claude -w refactor-db
Three independent agents, each on its own branch, each in its own working directory. No stash juggling, no checkout chaos.
Add .claude/worktrees/ to your .gitignore so the worktree directories don't show up as untracked files in your main checkout.
Gitignored Files#
A fresh worktree is a clean checkout, which means none of your gitignored files come with it. No .env, no .env.local, no config/secrets.json. For most projects that means the worktree won't actually run until you copy those files over.
Claude Code's answer is the .worktreeinclude file. Drop it in your project root, fill it with .gitignore-syntax patterns, and any matching files that are also gitignored will be copied into every new worktree automatically:
# .worktreeinclude
.env
.env.local
config/secrets.json
This applies to both --worktree sessions and Claude Code's subagent worktrees.
Subagent Isolation#
Claude Code's subagents, the lighter-weight delegated agents a main session can spawn, can also each run in their own worktree. You can ask the main session to "use worktrees for your agents" ad hoc, or make it permanent for a particular subagent by adding isolation: worktree to its frontmatter. This is especially valuable for large batched changes: imagine a codemod that needs to touch 200 files across 12 modules. Splitting that across subagents each in their own worktree means they can work in parallel without overwriting each other's edits. Subagent worktrees are temporary by default; they're cleaned up automatically when the subagent finishes if it made no changes.
Cleanup#
When you exit a --worktree session, Claude Code does the right thing by default: if you made no changes, the worktree and its branch disappear automatically; if there are uncommitted changes or commits, it prompts you to keep or discard them. One gotcha: non-interactive runs that combine --worktree with -p for one-shot prompts skip the cleanup prompt entirely, so you'll need to remove those worktrees manually with git worktree remove.
GitHub Copilot CLI#
Copilot CLI has a slightly different relationship with worktrees than Claude Code does. The standalone CLI itself doesn't have a --worktree flag. There's a tracked feature request #1613 asking for built-in worktree lifecycle management, but as of now you do worktree creation yourself using plain git worktree. Worktrees become first-class in VS Code's Copilot CLI integration, which wraps the standalone CLI with managed isolation modes.
Isolation Modes#
When you launch a Copilot CLI session from VS Code, it asks you to pick one of two modes:
- Worktree isolation: VS Code creates a fresh git worktree for the session, in its own folder, and the agent operates entirely inside that worktree. Your main workspace stays clean until you explicitly choose to merge.
- Workspace isolation: The agent works directly in your current workspace. Faster for small tasks, but exposes you to the cross-talk problem if you run more than one session.
VS Code also auto-commits at the end of each turn in worktree mode, which keeps the session history aligned with the git history and gives you clean checkpoints to roll back to. You can right-click any session in the chat panel and pick "Open Worktree in New Window" to inspect what the agent is doing in real time.
Running Multiple Copilot CLI Sessions#
Inside VS Code, you just start more sessions. Each gets its own worktree if you pick worktree isolation. From the bare terminal, the workflow is manual but identical to what you'd use for any agent:
git worktree add ../app-feature-search -b feature/search main
git worktree add ../app-feature-export -b feature/export main
# Terminal 1
cd ../app-feature-search && copilot
# Terminal 2
cd ../app-feature-export && copilot
Multi-Repo Workspaces#
If your VS Code workspace contains multiple Git repos, Copilot CLI shows you a repo picker on session start so you can choose which repo the worktree should live in. Once a session is running, that selection is locked in.
Model Choice#
A subtle but useful difference: Copilot CLI lets you pick between models from multiple providers, including Claude, GPT, and Gemini variants, from within the same session via /model. Claude Code is, predictably, Claude-only. If your team uses Copilot CLI and wants to compare how different frontier models tackle the same task, the multi-worktree fanout pattern below lets you run them side by side from one harness.
Patterns That Work Well in Practice#
A few workflows that have emerged as people have spent time running multiple agents:
Reviewer as Conductor#
This is the dominant pattern. You stop writing code as the bottleneck and become a reviewer of agent output. Fire off three or four tasks into worktrees, then cycle through reviewing PRs as agents finish. The model fits the strengths of current frontier models well: they're good at implementation when the scope is clear, less reliable at deciding what to build.
Fanout for Comparison#
Run the same prompt across several worktrees with different models, different prompts, or different tools enabled. This is especially valuable for design-heavy work where the "right" answer isn't obvious. You get N independent attempts and pick the best, or merge ideas from several. It's compute-cheap and surprisingly effective for things like UI components, API designs, and architectural choices.
git worktree add ../app-attempt-1 -b try/dashboard-1 main
git worktree add ../app-attempt-2 -b try/dashboard-2 main
git worktree add ../app-attempt-3 -b try/dashboard-3 main
# Same prompt, three workspaces, three agents
# Compare results, keep the best, discard the rest
Background Delegation#
Both harnesses now support handing a task off to run in the background while you keep working. Copilot CLI has a & prefix to delegate prompts to cloud-side execution, and Claude Code has agent teams and background sessions. Worktrees are what makes "background" actually safe: the background agent works in its own checkout, so you can't accidentally clobber its files, or vice versa, while it's running.
Plan, Then Execute#
A growing pattern is to use one agent in interactive mode to draft a plan, then hand the plan off to a worktree-isolated agent to execute. Copilot CLI's Plan agent has a built-in "Continue in Copilot CLI" handoff for exactly this; Claude Code supports the same flow via session hand-offs. The interactive session is for thinking; the worktree session is for typing.
AI-Specific Gotchas#
Most of these are the same gotchas in the next section, but they hit harder when an agent is the one making the mistake:
Dependency Reinstallation#
Every new worktree means another npm install, pip install, bundle install, or equivalent. For large JS monorepos this can be minutes per worktree. Some teams solve this with shared node_modules symlinks, with caution because package managers don't always love this. Others accept the cost. Tools like pnpm with shared content-addressed stores work very well with worktree-heavy workflows.
The Perfect Parallel Universe Trap#
A real anti-pattern that comes up: an agent in one worktree decides to create *-enhanced.ts variants of existing files rather than modifying the originals, because it sees the originals as "still in use" by other parallel work. You end up with parallel implementations across worktrees that look fine in isolation but are nightmares to merge. Be explicit in your prompts about edit-in-place vs. additive changes, and review the file lists, not just the diffs.
Keep the Review Queue Human-Sized#
It's tempting to fire off six worktrees and let the agents go. But if you can't actually read six PRs in a row, you're not parallelizing your work. You're parallelizing your backlog of unreviewed code. Three is a common practical ceiling for solo developers; experienced operators sometimes push to five or six with heavy tmux/window automation. Past that, you spend more time triaging than shipping.
Conflicts Are Deferred, Not Eliminated#
Worktrees mean agents don't trip over each other during their work, but their branches still have to merge eventually. If two agents touch the same files, you'll have a real conflict at merge time. Plan task boundaries the way you'd plan branch boundaries on a team: by file, not by feature. And when an agent's task has touched something that's drifted from main, rebase the worktree's branch onto current main before merging.
Authentication and Credentials#
Worktrees share the .git config, so your git identity carries across. But agent-side credentials, such as API keys and model tokens, generally don't. If your .env holds API keys, your .worktreeinclude (or its Copilot equivalent) needs to copy them, or your agents will fail to start.
The Shared Stash Trap#
Worth repeating: git stash is repo-wide, not worktree-wide. If your agent harness or your custom hooks use git stash for any "temporarily set aside" operation, parallel sessions in different worktrees can step on each other's stashes silently. Watch for it.
Tooling Around the Pattern#
A few tools and tricks worth knowing about:
tmux Multiplexers#
The single most useful tool for managing N agent sessions is tmux. A pre-built layout with four panes, one terminal per worktree, lets you glance across agents and switch between them with a keystroke. Claude Code has a --tmux flag that launches it inside a fresh tmux session automatically.
VS Code Multi-Folder Workspaces#
Add several worktrees to one VS Code workspace and you can see all of them in the explorer at once, with one Source Control panel per worktree.
Devcontainers per Worktree#
For teams running serious parallel-agent setups, the next step is devcontainers. Each worktree gets its own container with its own dependency state. This costs more disk and memory but completely eliminates dependency-step-on issues. There are open-source scaffolds for this for both Claude Code and Copilot CLI; search for "multi-copilot" or "claude-worktrees devcontainer" to find a starting point.
Cleanup Discipline#
AI-driven workflows generate worktrees faster than human workflows do. Get in the habit of running git worktree list daily and pruning anything that's done. A stale worktree directory takes disk space and clutters your project root, and abandoned branches accumulate fast.
Important Rules and Gotchas#
- One branch, one worktree: You cannot check out the same branch in two worktrees at the same time. Git will refuse with errors like
fatal: 'main' is already checked out at '/home/you/dev/project-main'. The fix is simple: create a new branch for each worktree. This matters even more with agents, because an instruction like "fix the bug on main" will fail ifmainis already open somewhere else. - Linked worktrees use a
.gitfile: A linked worktree does not have a full.gitdirectory. It has a.gitfile that points back to the main repository's worktree metadata, such asgitdir: /home/you/dev/project/.git/worktrees/project-main. Don't delete it; that's how Git finds the shared object store. git fetchupdates all worktrees: Because worktrees share the same object store and ref list, runninggit fetchin any worktree updates remote-tracking branches for all of them.- Merges and rebases stay local to the worktree: You can merge or rebase independently in any worktree. Commits you create in one worktree are immediately visible to the others via
git logorgit merge, because the object store is shared. - Stash is shared:
git stashis global to the repository, not scoped to a worktree. If you stash in one worktree, you'll see the same entry from another. This is usually manageable for human workflows, but it can become a problem when multiple agents are running. - Ignored files and build artifacts are separate: If your
.gitignoreignores directories such asdist/,node_modules/, or.next/, each worktree gets its own copy. Installing dependencies in your main worktree does not install them in a new one, which is one reason worktree-heavy workflows can spend time on setup.
A Suggested Directory Convention#
One thing that trips people up is where to put worktrees. You have options:
Sibling Directories
Put worktrees next to the main repository.
~/dev/
myapp/ ← main worktree
myapp-main/ ← worktree for main branch
myapp-hotfix/ ← worktree for a hotfix
This is clean and easy to navigate. The downside is it can clutter your dev directory if you have many projects.
A Subdirectory of the Repo
Some people like to keep worktrees inside the repo under a folder like .worktrees/. Just make sure to add it to .gitignore.
~/dev/myapp/
.git/
src/
.worktrees/
main/
hotfix/
# Add to .gitignore
echo ".worktrees/" >> .gitignore
# Create worktree
git worktree add .worktrees/main main
This keeps everything self-contained, which is especially nice on teams where you might share a .env or tooling setup.
A Bare Repo With Worktrees as Siblings
Treat the repository purely as a database and make every branch a worktree, with no privileged "main worktree." The clone is --bare and a .git file at the project root points tools at it.
~/dev/myapp/
.bare/ ← the actual repo (object store, refs, config)
.git ← one-line file: "gitdir: ./.bare"
main/ ← worktree for main
feature-auth/ ← worktree for a feature
hotfix-login/ ← worktree for a hotfix
# Initial setup
git clone --bare git@github.com:org/myapp.git myapp/.bare
cd myapp
echo "gitdir: ./.bare" > .git
# IMPORTANT: a bare clone tracks only the default branch out of the box.
# Reconfigure the fetch refspec to track all remote branches.
git --git-dir=.bare config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git --git-dir=.bare fetch
# Now every branch is just a worktree
git worktree add main main
git worktree add feature-auth -b feature/auth main
The win here is symmetry. With a normal clone, the original directory is a privileged "main worktree": structurally different from any worktree you add later, and an attractive nuisance for accidental commits. With the bare layout, every branch is just a subdirectory and the repository becomes purely a database. Tools like shell prompts, gh, and IDE Git panels follow the .git file to .bare and behave normally, so from the project root almost everything works as expected.
The fetch-config line above is essential and easy to miss. Without it, only the default branch is tracked, and commands like git worktree add feature-x origin/feature-x will fail with "no such ref" because the remote-tracking branches simply aren't there.
One caveat for AI agents: Claude Code's --worktree flag creates new worktrees relative to wherever it's launched, which in this layout can produce worktrees nested inside other worktrees if you start Claude from main/ instead of myapp/. Launch from the project root (where the .git file lives) so new worktrees land as siblings of the others, or use plain git worktree add ../feature-x -b feature/x main followed by cd ../feature-x && claude if you want full control. GitHub Copilot CLI has no opinion either way; it just runs wherever you put it.
The AI Harness Convention
Claude Code uses .claude/worktrees/ by default for sessions launched with --worktree. VS Code's Copilot CLI integration uses its own managed location. If you're mixing manual and agent worktrees, putting your own under .worktrees/ (or using the bare layout above) keeps them visually separate from harness-managed ones.
Checking If Your Tooling Understands Worktrees#
One last practical note: most modern tools handle worktrees gracefully, but not all.
- VS Code handles worktrees well. Open a linked worktree folder just like any other folder, and the Git panel works correctly. If you use the "Add Folder to Workspace" feature, you can even have multiple worktrees visible in a single VS Code window. The Source Control view in modern VS Code has a dedicated "Worktrees" node for navigating between them.
- Terminal-based Git prompts, like Oh My Zsh's git plugin or Starship, generally work fine in linked worktrees because they read the
.gitfile and follow it back to the real repo. - Some GUI clients may get confused by linked worktrees, particularly older ones. If your Git GUI shows a blank repository when you open a linked worktree path, that's why: it doesn't follow the
.gitfile. Check your tool's documentation or open the main worktree instead. - AI coding tools vary. Claude Code has native worktree support including in-session creation. GitHub Copilot CLI works inside any worktree you put it in, and VS Code's Copilot CLI integration manages worktrees for you. Cursor, Codex, Gemini CLI, and similar tools generally work fine inside a worktree because they treat it like any other repo, but may not have built-in lifecycle commands for creating or cleaning up worktrees. When in doubt, create the worktree manually with
git worktree addandcdinto it before launching the agent.
Quick Reference Cheat Sheet#
# Add a worktree for an existing branch
git worktree add <path> <branch>
# Add a worktree and create a new branch
git worktree add -b <new-branch> <path> <start-point>
# Add a worktree in detached HEAD state
git worktree add --detach <path> <commit>
# List all worktrees
git worktree list
# Remove a worktree (deletes directory + metadata)
git worktree remove <path>
# Clean up stale worktree references
git worktree prune
# Move a worktree to a new path
git worktree move <worktree> <new-path>
# Lock a worktree against accidental removal
git worktree lock <path>
git worktree unlock <path>
# Claude Code: launch in an isolated worktree
claude --worktree <name> # or: claude -w <name>
# GitHub Copilot CLI in VS Code: pick "Worktree isolation"
# when creating a new Copilot CLI session
Worktrees are a small Git feature with a quick payoff. They make context-switching less disruptive, give parallel work a clean shape, and keep AI agents from competing for the same files. Once you get used to reaching for them, they become one of those tools that quietly removes a lot of friction from everyday development.
Originally published at https://iuriio.com/blog/posts/2026/07/git-worktrees-guide



