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
# 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
~/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/.gitAdding a worktree
# 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
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
git worktree list
Example output
/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]
# Porcelain format — easier to parse in scripts git worktree list --porcelain
Porcelain output
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
# 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
Pruning stale worktrees
# 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
Removing worktrees/myapp-hotfix: gitdir file points to non-existent location
Moving a worktree
# Rename or relocate an existing linked worktree git worktree move ../myapp-hotfix ../patches/hotfix-1.2.1
Locking a worktree (for shared machines)
# 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 |
|
Reviewing a colleague's PR |
|
Running tests on two branches simultaneously | Two terminal windows, two worktree directories, two test runners in parallel. |
Building different versions for comparison |
|
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 --barehas no working tree; add one withgit 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.
.gitis a file, not a directory. In a linked worktree,.gitis a text file (a gitfile) pointing back to the main.git/worktrees/<name>/directory.
.git file in a linked worktree
$ 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
# 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 |
|---|---|
| Create a new linked worktree at <path> with <branch> checked out. |
| Create worktree and a new branch simultaneously. |
| List all worktrees with their paths and current branches. |
| Safely remove a linked worktree and its metadata. |
| Remove even if there are uncommitted changes. |
| Move a linked worktree to a new path. |
| Prevent pruning of a worktree (for CI or shared machines). |
| Remove the lock on a worktree. |
| Remove metadata for worktrees whose directories have been deleted. |