backend / git / 09_worktrees.md

Worktrees — Multiple Checkouts of One Repo

6 interview angles 4 min read source

Worktrees — Multiple Checkouts of One Repo

git worktree lets you have multiple branches checked out at the same time, in different directories, sharing one .git directory. No need to clone twice.

The problem worktrees solve

You’re deep in a feature branch with uncommitted changes. A urgent bug arrives on main. Without worktrees:

  • Stash → switch → fix → commit → switch back → unstash → context lost.
  • Or: clone the repo a second time, fix in the clone.

With worktrees:

git worktree add ../hotfix main
# now ../hotfix is a checkout of main
cd ../hotfix
# ... fix and commit ...
cd -
git worktree remove ../hotfix

Your original directory stays exactly as it was.

Basic commands

git worktree add <path> <branch>          # check out <branch> at <path>
git worktree add <path>                   # create branch named after the path
git worktree add -b new-feature <path>    # create a new branch and check it out at path
git worktree list                         # show all worktrees
git worktree remove <path>                # remove a worktree (must be clean)
git worktree prune                        # clean up administrative records of removed dirs

What gets shared, what doesn’t

All worktrees share the same .git/ directory:

Shared Per-worktree
object store (commits, blobs, packfiles) working tree files
refs (branches, tags) HEAD pointer
reflog index (staging area)
config (mostly) submodules state
hooks

This means:

  • A commit in worktree A is immediately visible from worktree B’s git log.
  • A new branch in A is visible in B’s git branch.
  • But each worktree has its own checked-out state.

Constraint: a branch is checked out in only one place

git worktree add ../second main
# fatal: 'main' is already checked out at '/path/to/original'

Two worktrees can’t have the same branch checked out at once. Use a different branch or a detached HEAD:

git worktree add --detach ../inspect main    # checkout main as detached HEAD

Common workflows

Hotfix without disturbing your feature

git worktree add ../hotfix -b hotfix/critical main
cd ../hotfix
# fix, commit, push, PR
cd -                                          # back to your feature work, untouched
git worktree remove ../hotfix

Code review someone else’s PR

git fetch origin pull/123/head:pr-123
git worktree add ../pr-123 pr-123
cd ../pr-123
# poke around, run tests, leave it

When done: git worktree remove ../pr-123 && git branch -D pr-123.

Run two versions side by side

git worktree add ../app-v1 v1.4.0
git worktree add ../app-v2 v2.0.0
# start both, compare behavior

Long-running CI / build in one worktree, develop in another

The build worktree never has uncommitted changes; you commit and push from your dev worktree, the build worktree pulls and runs.

Bare repo + worktrees pattern

For “I always want to work this way”:

git clone --bare git@github.com:org/repo.git repo.git
cd repo.git
git worktree add ../main main
git worktree add ../feature -b feature

Now you have a bare repo.git/ (no working tree, just .git content) and two sibling directories with checkouts. Some teams prefer this over the conventional clone-with-default-checkout layout.

Pitfalls

  • git worktree remove refuses on dirty worktrees. Clean up first or --force.
  • Stashing is global per worktree? No — stash is repo-wide, accessible from any worktree. Easy to confuse “where did my stash go.”
  • Submodules and worktrees mix awkwardly. Modern git handles it but check .gitmodules configuration if things misbehave.
  • prune is needed when you rm -rf a worktree directory directly. Git keeps administrative metadata; git worktree prune cleans up.

git worktree list

git worktree list
/home/me/myrepo            a1b2c3d [main]
/home/me/myrepo-hotfix     e4f5g6h [hotfix/critical]
/home/me/myrepo-pr-123     h7i8j9k (detached HEAD)

git worktree list --porcelain for a stable, parseable form.

Worktrees vs alternatives

Approach Pro Con
Stash + switch one directory loses context, slow with large stashes
Worktree parallel checkouts share .git extra disk for files (not history), one branch per dir
Second clone totally independent duplicates .git history (large), separate fetches

For occasional context switches: stash. For frequent multi-context work (hotfixes during feature work, reviewing many PRs): worktrees. Avoid second clones unless you need true isolation.

Common interview confusions

  • “Each worktree has its own history.” — they share the .git history. Only the working tree files differ.
  • “Worktrees are like git submodules.” — unrelated. Submodules are external repos pinned to a SHA. Worktrees are extra checkouts of the same repo.
  • “You can have main checked out in two worktrees.” — no, branch is exclusive. Use --detach if you need to.

Interview angle

  • “What’s git worktree for?” — multiple branches checked out simultaneously in separate directories, sharing one .git. Lets you context-switch (hotfix during a feature) without stash/branch dance.
  • “What’s shared between worktrees?” — object store, refs, reflog, hooks, config. Each worktree has its own working tree, index, HEAD.
  • “Can two worktrees have the same branch checked out?” — no. Use --detach for read-only inspection.
  • “How does worktree compare to cloning twice?” — worktree shares history (smaller, faster fetch); two clones are fully independent (more disk, separate fetches).
  • “When would you prefer stashing over a worktree?” — short context switches where setting up a directory is overkill. Worktrees pay off when you switch contexts often.
  • “How do you get rid of a worktree?”git worktree remove <path>. If you rm -rf’d it directly, git worktree prune cleans up the metadata.