Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXIII · WorktreesWorktrees

What a worktree is — multiple working trees sharing one .git directory

Advanced⏱ ~20 mingit

What you'll learn

  • Explain what a worktree is and how it differs from a clone
  • Identify the four logical pieces a worktree has (working tree, index, HEAD, branch ref)
  • Recognise the cases where a second worktree beats a second clone for an infrastructure engineer
  • Map the cost savings of worktrees to common IaC and CI scenarios

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

The default mental model of a Git repository is one working tree checked out at a time, with one HEAD, one index, and one branch active. The mental model is incomplete. A single Git repository can have many working trees, each checked out at its own commit, each with its own HEAD and index, all sharing one .git directory at the top of the primary tree. The mechanism that makes this possible is git worktree. This lesson establishes what a worktree is, what it shares, what it does not share, and why the difference matters for an infrastructure team.

Worktree versus clone

The two ways to get a second working copy of a repository are a clone and a worktree. They look similar from the outside (a directory with checked-out files and a .git somewhere) but the internals are different:

# A second clone — a fresh copy of the object database
git clone git@github.com:acme/iac.git ~/work/iac-feature-iam
cd ~/work/iac-feature-iam
git checkout -b feature/iam-rotation

# A worktree — a second working tree attached to the existing .git
cd ~/work/iac
git worktree add ../iac-feature-iam -b feature/iam-rotation

The clone duplicates the entire object database (every commit, every tree, every blob the repo has ever produced) into a new .git directory. The worktree adds a new directory, a new HEAD, and a new index; the existing .git directory is extended with a record under .git/worktrees/$NAME that points at the new working tree.

flowchart TB
    subgraph REPO[".git directory (shared)"]
        OBJ["object database - blobs, trees, commits"]
        REFS["refs - branches, tags"]
        WT["worktrees/ directory"]
    end
    subgraph MAIN["main working tree"]
        HEAD1["HEAD - main"]
        IDX1["index"]
        FS1["working tree files"]
    end
    subgraph FEAT["feature working tree"]
        HEAD2["HEAD - feature/iam-rotation"]
        IDX2["index"]
        FS2["working tree files"]
    end
    WT --> FEAT
    OBJ --> MAIN
    OBJ --> FEAT
    REFS --> MAIN
    REFS --> FEAT

The practical difference: a clone of a large infrastructure repository (Terraform state references, hundreds of modules, years of history) is a copy of gigabytes and a full re-download of every object. A worktree is a directory and a metadata record. Adding ten worktrees to a repository is cheap; adding ten clones of a gigabyte-scale repository is a disk and bandwidth tax.

What a worktree owns and what it shares

Each worktree owns three things: its working tree files, its index, and its HEAD. Each worktree shares the object database, the refs, and the configuration under .git/:

ComponentOwned per worktreeShared across worktrees
Working tree filesYesNo
IndexYesNo
HEAD refYesNo
Object database (blobs, trees, commits)NoYes
Refs under .git/refs/NoYes
Config under .git/configNoYes
Hooks under .git/hooks/NoYes

The sharing is what makes worktrees cheap. Creating a worktree does not copy the object database; it points at the existing one. Checking out a branch in a worktree does not re-fetch the objects; it reads them from the existing .git/objects/ directory. The only new on-disk data is the working tree files themselves, the per-worktree index, and a small metadata record under .git/worktrees/$NAME.

When a worktree is the right tool

Three situations come up constantly in infrastructure work where a second worktree beats a second clone:

  • Parallel IaC branches. An engineer is mid-edit on a Terraform branch and an urgent fix lands on main. Stashing, switching, fixing, switching back, and unstashing works but is lossy; a second worktree for the urgent fix keeps both edits intact and reviewable.
  • CI running in a worktree. A CI runner that checks out the job’s branch into a worktree (rather than a fresh clone per build) reuses the object database across builds and skips the clone cost on every run.
  • Long-running checkouts. An operator needs a long-lived working tree for an incident, a migration, or a slow rollout — a directory that stays at a known commit for days. A worktree pinned to that commit is exactly that; a clone is a one-shot snapshot that has to be manually kept in sync.

The worktree is not always the right tool. If the second copy needs to be on a different machine, or needs a fully independent .git, or needs a different user.email, a clone is the answer. The worktree is for “I need a second working copy on this machine, sharing the history I already have”.

Listing worktrees

The inventory of worktrees attached to the current repository is git worktree list:

git worktree list
# /home/alice/work/iac                       a1b2c3d [main]
# /home/alice/work/iac-feature-iam           d4e5f6a [feature/iam-rotation]
# /home/alice/work/iac-hotfix                7g8h9i0 [hotfix/vpn-cert]

Each line is the working tree path, the checked-out commit, and the branch (or (detached HEAD) if no branch is checked out). The first entry is always the main worktree — the working tree whose .git is the one being listed. Subsequent entries are linked worktrees attached to that same .git.

Production discipline

  1. Prefer worktrees over clones for second working copies on the same machine. A worktree reuses the object database; a clone duplicates it.
  2. One branch per worktree, by design. Do not fight the “branch already checked out” error by switching the other worktree first — the error is Git protecting you from two working trees silently diverging.
  3. List worktrees before assuming a directory is a clone. A directory with checked-out files might be a worktree pointing at a .git three levels up. git worktree list from the main worktree tells you which is which.
  4. Use absolute paths or paths relative to the main worktree when scripting worktrees. Relative paths behave predictably across moves; absolute paths break when the main worktree is moved.

Cross-course references

  • Git, CI/CD & GitOps - Part V (HEAD) lesson 03 establishes the HEAD/current-state model that this lesson extends to multiple worktrees.
  • Git, CI/CD & GitOps - Part II (GitModel) lesson 01 covers the working-tree/index/repository model that the worktree primitive is built on top of.
  • CI/CD Pipeline Patterns - Part III (CheckoutStrategies) discusses clone-versus-worktree trade-offs in CI runners.

Quiz

Knowledge check · 4 questions

  1. Q1. Which of the following is shared between every worktree attached to the same .git directory?

  2. Q2. Creating a worktree duplicates the entire object database (every commit, tree, and blob the repository has ever produced) into a new .git directory, the same way a clone does.

  3. Q3. Name the three infrastructure scenarios where a second worktree beats a second clone, and explain why for each.

  4. Q4. Decide whether to use a worktree or a clone for the second working copy, and justify the choice.

    An infrastructure engineer is mid-edit on `feature/iam-rotation` (a Terraform IAM refactor, ~3 days of in-progress changes, uncommitted) when an urgent request comes in to fix `main` for a misconfigured S3 bucket policy. The engineer needs both edits reviewable and switchable. The repository is large (~2 GB of object history from years of Terraform state references).

Passing score: 75%. Answers are checked in this browser.