Lesson 0000: Git Worktrees โ€” The Mental Model

Part of Git Worktrees for Parallel Agentic Coding  |  ~10 minute read

You have three AI coding agents running. One is fixing a bug on fix/login-timeout, another is building a feature on feat/dark-mode, and a third is doing code review on a PR branch. Right now, switching between them means stash-pop-commit-juggle โ€” or cloning the repo three times. There's a better way.

What You Already Know

You know that a normal git repository has two parts that live together:

my-project/ โ† the working tree (your files, editable) โ”œโ”€โ”€ .git/ โ† the git directory (all the history, objects, refs) โ”‚ โ”œโ”€โ”€ objects/ โ”‚ โ”œโ”€โ”€ refs/ โ”‚ โ”œโ”€โ”€ HEAD โ”‚ โ””โ”€โ”€ config โ”œโ”€โ”€ src/ โ”œโ”€โ”€ package.json โ””โ”€โ”€ ...

When you git checkout feature-branch, git updates both your working tree and the HEAD pointer inside .git/. Your entire working tree flips to match the new branch. One working tree, one branch at a time.

This is the single-working-tree constraint. It's why you can't have two branches checked out simultaneously in the same repo โ€” and it's exactly the problem worktrees solve.

The Core Idea

A worktree is an additional working tree attached to the same .git directory. Instead of one working tree, you have many. Each one has its own branch checked out, its own staged changes, and its own untracked files. But they all share one object database, one set of refs, one history.

A worktree is not a clone. A clone copies the entire .git directory โ€” all objects, all refs, all history. A worktree shares the same .git. Creating one is instantaneous (no network, no copying) and they stay in sync automatically โ€” a branch created in one worktree is immediately visible in all others.

The Structure

Here's what a repository with two additional worktrees looks like:

~/dev/my-project/ โ† main worktree (the original) โ”œโ”€โ”€ .git/ โ† the real git directory (shared by ALL worktrees) โ”‚ โ”œโ”€โ”€ objects/ โ”‚ โ”œโ”€โ”€ refs/ โ”‚ โ”œโ”€โ”€ HEAD โ”‚ โ”œโ”€โ”€ config โ”‚ โ””โ”€โ”€ worktrees/ โ† metadata for linked worktrees โ”‚ โ”œโ”€โ”€ fix-login/ โ† one entry per linked worktree โ”‚ โ”‚ โ”œโ”€โ”€ HEAD โ”‚ โ”‚ โ”œโ”€โ”€ index โ”‚ โ”‚ โ””โ”€โ”€ ... โ”‚ โ””โ”€โ”€ dark-mode/ โ”‚ โ”œโ”€โ”€ HEAD โ”‚ โ””โ”€โ”€ ... โ”œโ”€โ”€ src/ โ””โ”€โ”€ package.json ~/dev/my-project-fix-login/ โ† linked worktree (branch: fix/login-timeout) โ”œโ”€โ”€ .git โ†’ ~/dev/my-project/.git/worktrees/fix-login/ โ† NOT a directory, a pointer file โ”œโ”€โ”€ src/ โ† independent checkout of fix/login-timeout โ””โ”€โ”€ package.json ~/dev/my-project-dark-mode/ โ† linked worktree (branch: feat/dark-mode) โ”œโ”€โ”€ .git โ†’ ~/dev/my-project/.git/worktrees/dark-mode/ โ† points to its metadata โ”œโ”€โ”€ src/ โ† independent checkout of feat/dark-mode โ””โ”€โ”€ package.json

Three critical observations from this diagram:

What's shared The object database (.git/objects/), refs (.git/refs/), config, hooks โ€” everything in the real .git/ directory. A commit made in one worktree is immediately reachable in all others. A branch created in one worktree appears in git branch everywhere.
What's isolated The working tree files, the index (staging area), and HEAD โ€” each worktree maintains its own versions of these in .git/worktrees/<name>/. Staged changes in one worktree are invisible to others. You can have different files open in different editors pointed at different worktrees.
The pointer file Each linked worktree has a .git file (not a directory!) that contains a single line: gitdir: /path/to/main/.git/worktrees/name/. This is how git knows which worktree-specific metadata to use. Run cat .git in a linked worktree to see it.
One branch, one worktree. You cannot check out the same branch in two worktrees simultaneously. Git enforces this because two working trees on the same branch would create conflicting states. If you try, git will refuse with a clear error message.

The Problem It Solves For You

Your parallel agentic coding workflow today probably looks like one of these:

Option A: The Stash Juggle

# Agent 1 finishes on feat/dark-mode
git stash
git checkout fix/login-timeout
# Agent 2 works...
git checkout feat/dark-mode
git stash pop
# Fragile. One mistake and you lose work.

Option B: The Clone Farm

git clone my-project my-project-agent-2
git clone my-project my-project-agent-3
# Slow. Disk-heavy. Branches get out of sync.
# You need to git fetch in each clone to see new branches.

Option C: Worktrees (The Target State)

# Spin up a worktree for each agent in under a second:
git worktree add ../my-project-fix-login fix/login-timeout
git worktree add ../my-project-dark-mode feat/dark-mode

# Each agent gets its own directory, its own branch, its own staged state.
# All share the same .git โ€” no syncing needed.
# When done:
git worktree remove ../my-project-fix-login
Worktrees make parallel work trivial because they eliminate the cost of context-switching. Each worktree is a stable workspace that stays exactly as you left it. No stash, no checkout, no "wait, which branch am I on?" โ€” just cd into the directory and you're there.

Key Commands (Preview)

We'll practice these properly in the next lesson. For now, here's the shape of the API so you can see how simple it is:

Command What it does
git worktree add <path> <branch> Create a new worktree at path, checking out branch
git worktree list Show all worktrees and which branch each is on
git worktree remove <path> Delete a worktree (safe โ€” refuses if there's uncommitted work)
git worktree prune Clean up metadata for worktrees whose directories were manually deleted

The Three Rules That Prevent Surprises

If you remember nothing else from this lesson, remember these:

  1. Everything in .git/ is shared. A git fetch in any worktree updates refs for all worktrees. A git branch -D in any worktree deletes the branch everywhere. There is no per-worktree isolation at the git-database level.

  2. The working tree and index are private. Each worktree has its own files on disk and its own staging area. You can have src/app.ts open in three different editors with three different versions, and git handles it correctly.

  3. The .git in a linked worktree is a file, not a directory. This is the secret handshake. If you ever wonder "is this a main worktree or a linked one?", run cat .git. A directory means main worktree; a file containing gitdir: means linked.

Open a terminal and run ls -la .git in your current repo. Now imagine that instead of a directory, it's a single file pointing somewhere else. That mental shift โ€” .git as a pointer, not a container โ€” is the foundation of worktrees. When you're ready, proceed to Lesson 0001: Creating & Listing Worktrees to start using them.

Recap

Primary source: git-worktree official documentation. Read the DESCRIPTION section โ€” it's concise and well-written.

Ask questions: If anything in this lesson is unclear, ask your agent-teacher. You can say "I don't understand the pointer file" or "show me the difference between a clone and a worktree again" and I'll explain it differently.