Skip to content

Worktrees

git worktree allows you to have multiple working directories from the same repository, each checked out to a different branch. Unlike git stash (which temporarily shelves changes) or switching branches (which requires a clean working directory), worktrees let you work on multiple branches simultaneously.

Without worktrees, switching branches requires a clean working directory:

Terminal window
$ git switch feature-auth
## "error: Your local changes would be overwritten"
$ git stash
$ git switch feature-auth
## ... work on feature ...
$ git switch main
$ git stash pop
# ... work on main ...

With worktrees, both branches are available simultaneously:

Terminal window
$ git worktree add ../repo-auth feature-auth
$ cd ../repo-auth
# ... work on feature-auth ...
$ cd ../repo-main
# ... work on main simultaneously ...

A worktree is a linked working directory that shares the same .git object database and refs as the main repository:

repo/ # Main worktree
├── .git/ # Full .git directory (object store, refs, etc.)
├── src/
│ └── main.c
└── README.md
repo-auth/ # Linked worktree
├── .git # FILE (not directory!) containing path to main repo
├── src/
│ └── auth.c
└── README.md

The .git file in the linked worktree contains:

gitdir: /path/to/repo/.git/worktrees/repo-auth

And the main repository records the worktree:

repo/.git/
├── worktrees/
│ └── repo-auth/
│ ├── HEAD
│ ├── index
│ ├── commondir
│ └── gitdir
└── ...

Each worktree has its own:

  • HEAD (pointing to its branch)
  • Index (staging area)
  • Working directory

But they share:

  • Object store (.git/objects/)
  • References (branches, tags)
  • Configuration
flowchart TD
    subgraph "Shared"
        OBJ["Object Store<br/>(.git/objects/)"]
        REF["References<br/>(.git/refs/)"]
        CFG["Configuration<br/>(.git/config)"]
    end

    subgraph "Main Worktree (repo/)"
        W1_HEAD["HEAD → main"]
        W1_IDX["Index"]
        W1_WD["Working Directory<br/>(main branch)"]
    end

    subgraph "Linked Worktree (repo-auth/)"
        W2_HEAD["HEAD → feature-auth"]
        W2_IDX["Index"]
        W2_WD["Working Directory<br/>(feature-auth branch)"]
    end

    W1_HEAD --> REF
    W2_HEAD --> REF
    W1_IDX --> OBJ
    W2_IDX --> OBJ
    W1_WD --> W1_IDX
    W2_WD --> W2_IDX

    style OBJ fill:#e8f5e9
    style REF fill:#e8f5e9
Terminal window
# Create a worktree for an existing branch
$ git worktree add ../repo-auth feature-auth
# Create a worktree and a new branch simultaneously
$ git worktree add -b feature-auth ../repo-auth main
# Create a worktree at a specific commit (detached HEAD)
$ git worktree add ../repo-debug a3f2b1c
# Create a worktree for a new branch from a specific commit
$ git worktree add -b hotfix-crash ../repo-hotfix a3f2b1c
Terminal window
$ git worktree list
/path/to/repo abc1234 [main]
/path/to/repo-auth def5678 [feature-auth]
Terminal window
# Remove a worktree (deletes the working directory)
$ git worktree remove ../repo-auth
# Force remove (even if there are uncommitted changes)
$ git worktree remove --force ../repo-auth
# Prune stale worktree entries (if the directory was deleted manually)
$ git worktree prune

Work on a hotfix while in the middle of a feature:

Terminal window
$ git worktree add ../repo-hotfix -b hotfix-crash main
$ cd ../repo-hotfix
# Fix the crash, test, commit, push
$ cd ../repo-main
# Continue working on your feature — no stash needed
Terminal window
$ git worktree add ../repo-review origin/feature-auth
# Open both repos in your IDE
# Diff side-by-side between ../repo-main and ../repo-review
Terminal window
$ git worktree add ../repo-test main
$ cd ../repo-test
# Run a 30-minute test suite on main
# Meanwhile, continue developing in ../repo-main
Terminal window
$ git worktree add ../repo-v1 v1.0
$ git worktree add ../repo-v2 v2.0
# Build and test both versions simultaneously

Each branch can only be checked out in one worktree at a time:

Terminal window
$ git worktree add ../repo-auth main
# Error: "main' is already checked out at '/path/to/repo'

A bare repository (no working directory) cannot have a main worktree. All worktrees are linked:

Terminal window
$ git init --bare project.git
$ git worktree add project-main main

Submodules in worktrees can be tricky — each worktree initializes submodules independently, which can lead to conflicts:

Terminal window
# In each worktree, initialize submodules separately
$ cd ../repo-auth
$ git submodule update --init --recursive
FeatureWorktreeStashBranch
Parallel workYesNoNo (must switch)
PersistentYes (until removed)Until popped/droppedYes
Independent indexYesNo (single index)No (single index)
Disk usageHigher (full checkout)MinimalMinimal
Setup costgit worktree addgit stash pushgit switch

Rule of thumb: Use worktrees when you need to work on two things simultaneously for more than a few minutes. Use stash for brief interruptions. Use branches for sequential work.

  1. Neglecting to normalise database designs, leading to data redundancy and update anomalies.

  2. Confusing authentication (who you are) with authorisation (what you can do) in security contexts.

  3. Forgetting that O(nlogn)O(n \log n) average-case for quicksort becomes O(n2)O(n^2) worst-case on already sorted input.

  4. Mixing up Big O, Big Ω\Omega, and Big Θ\Theta notation. Big O is an upper bound, not necessarily tight.

The key principles covered in this topic are linked in the sub-pages above. Focus on understanding the definitions, applying the formulas or frameworks, and evaluating strengths and limitations of each approach.

Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.

Worktrees are like having multiple desks in the same office. Instead of clearing your desk to work on a different project (stash/switch), you directly walk to another desk that already has the other project set up. Both desks share the same filing cabinet (object database) but have their own workspace. This is like having multiple browser tabs open - you can switch between them instantly without losing your place. The key insight is that worktrees eliminate context-switching overhead. You can run tests on the main branch while developing a feature on another branch, without stashing or committing incomplete work.

  • Stash - The simpler alternative for brief interruptions
  • Submodules - How submodules interact with worktrees