Git, CI/CD & GitOpsXXIII · WorktreesWorktrees
Multiple worktrees and shared git — how .git/ is shared
What you'll learn
- Describe the .git/worktrees/$NAME/ metadata layout (HEAD, gitdir, commondir, lock)
- Explain how the per-worktree .git file redirects operations to the shared .git directory
- Identify what operations are safe across worktrees (fetch, gc) and what operations are per-worktree (checkout, reset)
- Recognise the failure modes when .git/worktrees/$NAME metadata is corrupted
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
Lesson 01 established that a worktree shares the object database
with the main worktree. Lesson 02 covered the create and remove
commands. This lesson goes one level deeper: what exactly is on
disk under .git/worktrees/$NAME/, how the per-worktree .git
file points back at the shared metadata, and which operations are
safe to run concurrently across worktrees and which are not. The
mechanics matter because the failure modes of worktrees (stale
metadata, lock contention, index corruption) all live at this
layer.
The .git/worktrees/$NAME/ layout
When a worktree is added at $PATH against a branch $NAME,
Git creates a metadata directory at
$MAIN/.git/worktrees/$BRANCH_BASENAME/. The directory holds
four files that describe the linked worktree:
# Inspect the metadata for a linked worktree
ls -la ~/work/iac/.git/worktrees/iac-feature-iam/
# HEAD
# commondir
# gitdir
# locked (only present if the worktree is locked)
# locks/ (only present if a long-running operation is in progress)
cat ~/work/iac/.git/worktrees/iac-feature-iam/HEAD
# ref: refs/heads/feature/iam-rotation
cat ~/work/iac/.git/worktrees/iac-feature-iam/commondir
# ../..
cat ~/work/iac/.git/worktrees/iac-feature-iam/gitdir
# /home/alice/work/iac-feature-iam/.git
Each file has a specific role:
- HEAD — the branch or commit the worktree has checked out.
Same format as the main
.git/HEAD. - commondir — the path (relative to the worktree’s metadata
directory) to the shared
.gitdirectory. For a worktree off the main repo, this is../..(two levels up fromworktrees/$NAMEback to.git). - gitdir — the absolute path back to the per-worktree
.gitfile (a file, not a directory — covered below). - locked — present when the worktree is locked (covered in lesson 06); absence means unlocked.
flowchart TB
subgraph SHARED[".git (shared)"]
OBJ["objects/ - blobs, trees, commits"]
REFS["refs/ - branches, tags"]
CFG["config"]
HOOKS["hooks/"]
WTROOT["worktrees/"]
end
subgraph META["worktrees/iac-feature-iam/"]
HEAD1["HEAD - ref: refs/heads/feature/iam-rotation"]
COMMON["commondir - ../.."]
GITDIR["gitdir - /abs/path/to/iac-feature-iam/.git"]
end
subgraph LINKED["iac-feature-iam/.git (file)"]
POINTER["gitdir: /abs/path/to/.git/worktrees/iac-feature-iam"]
end
WTROOT --> META
META --> LINKED
OBJ -.shared.-> META
REFS -.shared.-> META
The per-worktree .git file
In a normal clone, .git is a directory. In a linked worktree,
$PATH/.git is a file containing one line:
cat ~/work/iac-feature-iam/.git
# gitdir: /home/alice/work/iac/.git/worktrees/iac-feature-iam
This file is what tells Git “this directory is a worktree of that
other .git”. Every Git command run from ~/work/iac-feature-iam
reads the file, follows the pointer to the metadata directory,
and resolves operations against the shared .git. The redirect
is invisible to the user: from the command line, the worktree
looks and behaves like a normal repository. The redirection is
what makes operations like git status and git log work
correctly without any flag telling them “you are a worktree”.
Operations safe across worktrees
The shared object database and shared refs make several operations safe to run concurrently from any worktree — the results are seen by all worktrees:
git fetch— updates remote-tracking refs in the shared.git/refs/remotes/. Every worktree sees the new refs on its nextgit log origin/main.git gc— runs garbage collection on the shared object database. Any worktree’sgit gcbenefits all worktrees.git remote add,git config --local— modifies the shared.git/config. Changes are visible from every worktree.git branch -d $MERGED_BRANCH— removes a ref from the shared refs. All worktrees see the branch disappear.git tag $TAG $COMMIT— creates a shared tag. All worktrees see the new tag.
These operations either modify the shared object database (where Git’s own concurrency handles safety) or modify the shared refs (with file-rename atomicity on the ref files). They do not interfere with per-worktree state.
Operations per-worktree only
Several operations are intrinsically per-worktree and must not be run concurrently across worktrees:
git checkout $BRANCH— writes the worktree’s index and working tree. Running concurrently from two worktrees on the same branch (impossible because Git refuses to dual-checkout, but possible via--forceor by racing two worktrees) corrupts one or both indices.git reset --hard,git restore .— rewrites the worktree’s working tree and index. Safe in isolation; dangerous if another process is writing the same files.- Index writes in general —
git add,git stash,git commit(which writes the index to create the commit object) all modify the per-worktree index file. The shared object database receives the new commit object, but the index is per-worktree and concurrent writes are not safe. git merge,git rebase— modify the per-worktree index extensively and may produce conflicts that require user resolution. Two worktrees cannot share the merge state.
The rule: shared state can be modified from any worktree;
per-worktree state must be modified from that worktree only.
The shared .git directory is the boundary; operations on the
shared side are cross-worktree safe; operations on the
per-worktree side are not.
Production discipline
- Run shared operations from any worktree.
git fetch,git gc,git remote add— pick whichever worktree is convenient; the effect is global. - Never edit
.git/worktrees/$NAME/by hand. Use thegit worktreesubcommands. Hand-editing produces silent corruption that surfaces as wrong-HEAD errors days later. - Treat the per-worktree
.gitfile as opaque. It is a pointer; do not edit, do not delete, do not move it. The worktree primitive depends on it. - Run concurrent
git fetches freely, concurrentgit checkouts never. The first is shared-state, cross-worktree safe; the second is per-worktree state, cross-worktree destructive. - If
git worktree listshows a phantom entry, do not delete the metadata by hand. Rungit worktree prune(covered in lesson 06) and let Git clean it up.
Cross-course references
- Git, CI/CD & GitOps - Part II (GitModel) lesson 04 covers
the
.git/directory layout that this lesson extends with theworktrees/subdirectory. - Git, CI/CD & GitOps - Part III (Objects) lesson 01 covers the object database that worktrees share; the safety of shared operations derives from the safety of object-database writes.
- Linux for Production Sysadmins - Part XX (Filesystems) covers POSIX rename atomicity, which is the mechanism that makes shared ref updates safe.
Quiz
Knowledge check · 4 questions
Q1. What does the file at `$WORKTREE/.git` contain in a linked worktree?
Q2. Running `git fetch` from one worktree updates the remote-tracking refs in the shared .git directory, and the new refs are visible from every other worktree attached to the same .git.
Q3. Name the four files (or file types) under `.git/worktrees/$NAME/`, and describe the role of each.
Q4. Diagnose a worktree failure caused by hand-edited metadata, and recommend the correct recovery.
An engineer, trying to free disk space, manually deleted `.git/worktrees/iac-feature-iam/` from the main worktree while the linked worktree `~/work/iac-feature-iam/` was still on disk. Subsequent `git status` runs in the linked worktree report `fatal: not a git repository`. `git worktree list` from the main worktree no longer shows the linked worktree.
Passing score: 75%. Answers are checked in this browser.