Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXIII · WorktreesWorktrees

Multiple worktrees and shared git — how .git/ is shared

Advanced⏱ ~22 mingit

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

Not yet marked complete on this device.

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 .git directory. For a worktree off the main repo, this is ../.. (two levels up from worktrees/$NAME back to .git).
  • gitdir — the absolute path back to the per-worktree .git file (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 next git log origin/main.
  • git gc — runs garbage collection on the shared object database. Any worktree’s git gc benefits 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 --force or 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 generalgit 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

  1. Run shared operations from any worktree. git fetch, git gc, git remote add — pick whichever worktree is convenient; the effect is global.
  2. Never edit .git/worktrees/$NAME/ by hand. Use the git worktree subcommands. Hand-editing produces silent corruption that surfaces as wrong-HEAD errors days later.
  3. Treat the per-worktree .git file as opaque. It is a pointer; do not edit, do not delete, do not move it. The worktree primitive depends on it.
  4. Run concurrent git fetches freely, concurrent git checkouts never. The first is shared-state, cross-worktree safe; the second is per-worktree state, cross-worktree destructive.
  5. If git worktree list shows a phantom entry, do not delete the metadata by hand. Run git 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 the worktrees/ 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

  1. Q1. What does the file at `$WORKTREE/.git` contain in a linked worktree?

  2. 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.

  3. Q3. Name the four files (or file types) under `.git/worktrees/$NAME/`, and describe the role of each.

  4. 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.