Git, CI/CD & GitOpsXXIII · WorktreesWorktrees
What a worktree is — multiple working trees sharing one .git directory
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
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/:
| Component | Owned per worktree | Shared across worktrees |
|---|---|---|
| Working tree files | Yes | No |
| Index | Yes | No |
| HEAD ref | Yes | No |
| Object database (blobs, trees, commits) | No | Yes |
Refs under .git/refs/ | No | Yes |
Config under .git/config | No | Yes |
Hooks under .git/hooks/ | No | Yes |
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
- Prefer worktrees over clones for second working copies on the same machine. A worktree reuses the object database; a clone duplicates it.
- 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.
- List worktrees before assuming a directory is a clone. A
directory with checked-out files might be a worktree pointing
at a
.gitthree levels up.git worktree listfrom the main worktree tells you which is which. - 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
Q1. Which of the following is shared between every worktree attached to the same .git directory?
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.
Q3. Name the three infrastructure scenarios where a second worktree beats a second clone, and explain why for each.
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.