Lesson 0002: Working in Parallel with Worktrees

Part of Git Worktrees for Parallel Agentic Coding  |  ~15 minute read + practice

This is the lesson that changes your workflow. You'll simulate three AI coding agents working on three different branches simultaneously โ€” each in its own worktree โ€” and merge them all back. This is the pattern you'll use every day.

The Pattern: One Worktree Per Agent Per Branch

Your parallel agentic coding workflow follows a simple lifecycle:

Agent 1: feat/dark-mode โ†’ worktree: ~/dev/worktrees/dark-mode/ Agent 2: fix/login-timeout โ†’ worktree: ~/dev/worktrees/fix-login/ Agent 3: review/PR-42 โ†’ worktree: ~/dev/worktrees/review-pr-42/ All share: ~/dev/my-project/.git/ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Agent 1 โ”‚ โ”‚ Agent 2 โ”‚ โ”‚ Agent 3 โ”‚ โ”‚ dark-mode โ”‚ โ”‚ fix-login โ”‚ โ”‚ review-42 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ–ผ โ–ผ โ–ผ git worktree git worktree git worktree add ... add ... add ... โ”‚ โ”‚ โ”‚ โ–ผ โ–ผ โ–ผ ~/dev/worktrees/ ~/dev/worktrees/ ~/dev/worktrees/ dark-mode/ fix-login/ review-pr-42/ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ Shared .git/objects/ Shared .git/refs/
Worktrees solve the coordination problem between agents. Without worktrees, you either serialize agents (slow), clone the repo (disk-heavy, desynced), or juggle stashes (fragile). With worktrees, each agent gets an isolated workspace that's always in sync with the shared git database. No coordination needed โ€” just cd into the right directory.

Full Lifecycle Walkthrough

Open a terminal. We'll simulate the complete lifecycle: create โ†’ work โ†’ merge โ†’ cleanup. Use a real repo โ€” the pocock-skills repo you're in right now works perfectly.

Spin Up Worktrees for Each Agent

# Create a directory for your worktrees (do this once, ever):
mkdir -p ~/dev/worktrees

# Agent 1: building dark mode feature
git worktree add ~/dev/worktrees/dark-mode -b feat/dark-mode

# Agent 2: fixing a login timeout bug
git worktree add ~/dev/worktrees/fix-login -b fix/login-timeout

# Agent 3: reviewing PR #42
git fetch origin pull/42/head:pr-42
git worktree add ~/dev/worktrees/review-pr-42 pr-42

# Verify your setup:
git worktree list

Three worktrees created in under 3 seconds. No clones, no network, no waiting.

Simulate Concurrent Work

In a real workflow, each AI agent would work in its own directory. Let's simulate that manually โ€” imagine each cd block is a different agent process:

# === AGENT 1: Dark Mode (Terminal 1) ===
cd ~/dev/worktrees/dark-mode
echo ".dark { background: #111; }" >> dark-mode.css
git add dark-mode.css
git commit -m "feat: add dark mode stylesheet"

# === AGENT 2: Login Fix (Terminal 2) ===
cd ~/dev/worktrees/fix-login
echo "// increase timeout to 30s" >> auth.ts
git add auth.ts
git commit -m "fix: extend login timeout to 30s"

# === AGENT 3: PR Review (Terminal 3) ===
cd ~/dev/worktrees/review-pr-42
# Just reading code, making notes...
echo "LGTM on the refactor, one nit about error handling" > review-notes.md

All three worktrees are operating independently. No stashing, no context switching. Each agent stays in its own directory with its own branch, its own staged changes, its own untracked files.

Verify Isolation and Sharing

# In the main worktree โ€” see all commits from all agents:
cd ~/dev/my-project
git log --all --oneline --graph -10

# The commits from Agent 1 and Agent 2 are visible because
# they share the same object database. No fetch needed.

# But their working trees are isolated:
ls dark-mode.css auth.ts review-notes.md
# None of these files exist here โ€” they're in the other worktrees.

Merge Back to Main

# Merge Agent 1's work (dark mode):
git merge feat/dark-mode

# Merge Agent 2's work (login fix):
git merge fix/login-timeout

# Agent 3's review notes stay in the review worktree โ€”
# no merge needed since it wasn't a code change.

Clean Up

# Remove the worktrees (branches persist unless you delete them):
git worktree remove ~/dev/worktrees/dark-mode
git worktree remove ~/dev/worktrees/fix-login
git worktree remove ~/dev/worktrees/review-pr-42

# Optionally delete merged branches:
git branch -d feat/dark-mode
git branch -d fix/login-timeout
git branch -D pr-42  # -D because it's a fetched PR branch

# Verify clean state:
git worktree list
# Should only show the main worktree.

Organizing Your Worktree Directory

A consistent location for worktrees prevents chaos. Choose a convention and stick to it:

Strategy Path pattern Best for
Sibling directories ../my-project-<feature> Quick one-offs, small number of worktrees
Dedicated dir ~/dev/worktrees/<feature> Daily driver โ€” keeps repo root clean
Per-project dir ~/dev/worktrees/<project>/<feature> Multiple projects, many worktrees each
Use meaningful names for worktree directories. The directory name doesn't have to match the branch name, but it should make the purpose obvious at a glance. ~/dev/worktrees/fix-login is self-documenting; ~/dev/worktrees/wt-3 requires a git worktree list to decode.

The Agent Script: Your Daily Driver

Once you've internalized the pattern, wrap it in a shell function. Add this to your ~/.zshrc:

# Create a new worktree for agent work
wt-new() {
  local branch="$1"
  local name="${2:-$(echo "$branch" | tr '/' '-')}"
  local base="${WT_BASE:-$HOME/dev/worktrees}"

  mkdir -p "$base"
  git worktree add "$base/$name" ${3:+-b} "$branch" && cd "$base/$name"
}

# List all worktrees for the current repo
wt-list() {
  git worktree list
}

# Remove a worktree by its directory name
wt-rm() {
  local base="${WT_BASE:-$HOME/dev/worktrees}"
  git worktree remove "$base/$1"
}

# Usage:
# wt-new feat/dark-mode          # creates worktree at ~/dev/worktrees/feat-dark-mode
# wt-new fix/login-timeout       # creates at ~/dev/worktrees/fix-login-timeout
# wt-list                        # shows all worktrees
# wt-rm feat-dark-mode           # removes worktree

This gives you a single-command workflow: wt-new feat/dark-mode spins up a worktree, creates the branch, and cds you into it โ€” ready to hand off to an agent.

The Constraints That Prevent Chaos

Worktrees give you parallel workspaces, but they come with guardrails that protect you from yourself:

Constraint Why it exists
One branch cannot be checked out in two worktrees Prevents conflicting working-tree states. If two worktrees had the same branch, which one's HEAD is authoritative?
Worktrees must be on different filesystems from the main worktree Prevents confusion โ€” linked worktrees should be clearly separate directories. (You can't create a worktree inside the main worktree.)
git worktree remove refuses if the worktree is dirty Prevents accidental data loss. Use --force if you're sure.
A worktree cannot be removed if its branch is checked out nowhere else Prevents orphaning commits. Git warns you to merge or delete the branch first.
Don't rebase a branch that's checked out in another worktree. If Agent 1 is on feat/dark-mode in its worktree, and you rebase feat/dark-mode from the main worktree, Agent 1's worktree now has a diverged history. Git won't prevent this โ€” it's a coordination problem you need to manage. We'll cover this in Lesson 0003.

Recap

Primary source: Git Worktrees: A Practical Guide โ€” The GitHub Blog. The parallel workflow section is directly applicable.

Ask questions: "How do I handle merge conflicts between worktrees?" or "What's the best way to organize worktrees when I have 10+ active branches?" โ€” your agent-teacher can help you think through your specific setup.