GitWorktrees

Git Worktree

git worktree lets you check out multiple branches simultaneously in separate directories — all sharing the same underlying .git database. You can switch between them instantly (no stashing, no switching branches) and work on a hotfix and a feature in parallel without any juggling.

The problem worktrees solve

Without worktrees, context-switching in Git looks like this:

The painful old way

Bash
# Mid-feature, urgent hotfix needed
git stash push -m "WIP: auth refactor"
git checkout hotfix/1.2.1
# ... fix the bug, commit, push ...
git checkout feature/auth-refactor
git stash pop
# Hope nothing conflicted

Worktrees replace that dance with separate directories. Each branch lives in its own folder, with its own working tree and index, but they all share a single .git object store — so no disk space is wasted duplicating history.

Worktree layout on disk

Text
~/projects/
├── myapp/                  ← main (primary) worktree — has .git/
│   ├── .git/
│   └── src/
├── myapp-hotfix/           ← linked worktree for hotfix/1.2.1
│   └── src/
└── myapp-review/           ← linked worktree for review/pr-456
    └── src/

All three directories share ~/projects/myapp/.git
Adding a worktree

Bash
# Create a new directory "../myapp-hotfix" and check out "hotfix/1.2.1" there
git worktree add ../myapp-hotfix hotfix/1.2.1

# Create the directory AND a new branch at the same time
git worktree add -b hotfix/1.2.2 ../myapp-hotfix-2 main

# Check out a remote branch in a new worktree
git fetch origin
git worktree add ../review-pr origin/feature/new-checkout

Output

Text
Preparing worktree (checking out 'hotfix/1.2.1')
HEAD is now at d3c2b1a Bump version to 1.2.1

After this command, ../myapp-hotfix is a normal directory you can cd into and work in just like the main repo directory. Your editor can open it independently.

Listing worktrees

Bash
git worktree list

Example output

Text
/Users/alice/projects/myapp          a1b2c3d [main]
/Users/alice/projects/myapp-hotfix   d3c2b1a [hotfix/1.2.1]
/Users/alice/projects/myapp-review   f6e5d4c [feature/new-checkout]

Bash
# Porcelain format — easier to parse in scripts
git worktree list --porcelain

Porcelain output

Text
worktree /Users/alice/projects/myapp
HEAD a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
branch refs/heads/main

worktree /Users/alice/projects/myapp-hotfix
HEAD d3c2b1a4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0
branch refs/heads/hotfix/1.2.1
Removing a worktree

Bash
# Clean removal — Git deletes the directory and unregisters the worktree
git worktree remove ../myapp-hotfix

# If the worktree has uncommitted changes, force-remove it
git worktree remove --force ../myapp-hotfix

# After manually deleting a worktree directory, clean up stale refs
git worktree prune
Always remove properly
If you manually delete a linked worktree directory with `rm -rf`, the `.git/worktrees/` metadata is left behind. Run `git worktree prune` to clean it up, or Git will keep reporting stale worktrees.
Pruning stale worktrees

Bash
# Remove metadata for worktrees whose directories no longer exist
git worktree prune

# Preview what would be pruned without doing it
git worktree prune --dry-run -v

Prune output

Text
Removing worktrees/myapp-hotfix: gitdir file points to non-existent location
Moving a worktree

Bash
# Rename or relocate an existing linked worktree
git worktree move ../myapp-hotfix ../patches/hotfix-1.2.1
Locking a worktree (for shared machines)

Bash
# Prevent git worktree prune from removing this worktree
git worktree lock ../myapp-hotfix --reason "active CI build in progress"

# Unlock it when done
git worktree unlock ../myapp-hotfix
Common use cases

Scenario

Worktree approach

Urgent hotfix while feature work is in progress

git worktree add ../hotfix hotfix/1.x — fix in that dir, push, done. No stashing your feature work.

Reviewing a colleague's PR

git worktree add ../pr-review origin/feature/their-branch — test it without disturbing your branch.

Running tests on two branches simultaneously

Two terminal windows, two worktree directories, two test runners in parallel.

Building different versions for comparison

git worktree add ../build-old v1.0 and git worktree add ../build-new v2.0 — build and diff the artifacts side by side.

Long-running scripts on one branch while editing another

Start the script in one worktree directory; write code in the main worktree simultaneously.

Constraints and limitations
  • Same branch in two worktrees is forbidden. Git prevents checking out a branch that is already checked out in another worktree. You'll see: fatal: 'main' is already checked out at '...'. Create a new branch instead.

  • Bare repos need a worktree. git init --bare has no working tree; add one with git worktree add.

  • Hooks run relative to the worktree. Each worktree runs hooks, but the hooks all live in .git/hooks/ of the main worktree.

  • Stashes are shared. The stash stack is repo-wide, not per-worktree.

  • .git is a file, not a directory. In a linked worktree, .git is a text file (a gitfile) pointing back to the main .git/worktrees/<name>/ directory.

.git file in a linked worktree

Text
$ cat /Users/alice/projects/myapp-hotfix/.git
gitdir: /Users/alice/projects/myapp/.git/worktrees/myapp-hotfix
Worktrees in CI/CD

Worktrees are popular in CI systems to run multiple builds from a single clone, saving fetch time on large repos:

CI script: parallel builds from one clone

Bash
# Clone once
git clone https://github.com/example/myapp.git ci-root
cd ci-root

# Spin up two worktrees
git worktree add ../build-a feature/checkout-v2
git worktree add ../build-b feature/payment-refactor

# Build in parallel
(cd ../build-a && npm ci && npm run build) &
(cd ../build-b && npm ci && npm run build) &
wait

# Clean up
git worktree remove ../build-a
git worktree remove ../build-b
Worktree command reference

Command

What it does

git worktree add <path> <branch>

Create a new linked worktree at <path> with <branch> checked out.

git worktree add -b <new-branch> <path> <start>

Create worktree and a new branch simultaneously.

git worktree list

List all worktrees with their paths and current branches.

git worktree remove <path>

Safely remove a linked worktree and its metadata.

git worktree remove --force <path>

Remove even if there are uncommitted changes.

git worktree move <from> <to>

Move a linked worktree to a new path.

git worktree lock <path>

Prevent pruning of a worktree (for CI or shared machines).

git worktree unlock <path>

Remove the lock on a worktree.

git worktree prune

Remove metadata for worktrees whose directories have been deleted.

Warning
Never delete a linked worktree directory with `rm -rf` without running `git worktree remove` first. You will leave orphaned metadata in `.git/worktrees/` that can confuse Git commands. Always use `git worktree remove` (or `git worktree prune` after a manual deletion).
Tip
Add shell aliases for your most common worktree patterns. For example: `alias gwta='git worktree add'` and `alias gwtl='git worktree list'` turn a verbose workflow into a two-keystroke operation. Pair with tab-completion for branch names and switching between worktrees becomes nearly instant.