Home

Git Worktree & Branch Isolation Primitives

Pillar: git-worktree-mechanics | Date: May 2026
Scope: Git-native mechanisms for isolating parallel work: worktree lifecycle (create, prune, cleanup), branch naming conventions for agent identity, merge queue patterns (GitHub merge queue, Bors, Mergify, Aviator), automated rebase triggers on queue drain, worktree limitations (index locks, submodules, hooks), and CI integration with worktree-based pipelines.
Sources: 31 gathered, consolidated, synthesized.

Executive Summary

Critical finding: Serial merge queues processing 100 PRs with 10-minute CI require 1,000 minutes of CI time — 100× more than batch approaches that preserve the same safety guarantee. At the same time, the productive ceiling for concurrent agents on a modern laptop is 5–7 before rate limits, disk consumption, and merge review overhead cancel out throughput gains; beyond 10, full orchestration infrastructure is mandatory.[2][16][31]

Git worktrees convert "invisible runtime corruption into visible merge-time conflicts" — the core isolation guarantee that makes multi-agent parallel development viable. Each linked worktree gets its own HEAD, index, and staging area, while sharing the object store with the main worktree. Creation takes seconds rather than the minutes required for a fresh clone, and a single fetch in any worktree synchronizes objects for all — parallel fetch with 4 workers reduces fetch time by approximately 71% compared to sequential execution.[9][28] Cursor IDE ships this pattern in production: its parallel agent feature creates one worktree per agent task, enabling simultaneous code edits without file-level collisions.[5]

Disk cost scales with file count, not history size. A 500 MB repository with five active worktrees requires at least 2.5 GB for checked-out files alone, with high-cost directories (node_modules, venv, target/) duplicating linearly per worktree.[10][28] Practical worktree ceilings are filesystem-dependent: community benchmarks place ext4 at 8–12 concurrent worktrees, XFS at 15–20+, and ZFS at 25+ with proper tuning — though Git itself enforces no hard maximum.[28] At the workflow level, 2–5 agents are manageable with tmux-based manual monitoring; 5–10 require task queuing with atomic task claims; 10+ demand conflict-detection pipelines and automated monitoring.[4][16][31]

Five shared resources account for the majority of worktree-related incidents in production agent pipelines: stash (git stash pop in one worktree applies stashes from all others, with no configuration override), hooks (all worktrees share .git/hooks/ — hardcoded paths break silently in linked worktrees), submodules (officially experimental and incomplete per Git documentation, with .git/modules/ state shared across all worktrees), concurrent git operations on the object store (Git is designed as a single-process tool; simultaneous writes risk corruption), and branch exclusivity (the same branch cannot be checked out in more than one worktree simultaneously).[8][9][16][24] Pre-flight checks for each should be part of every worktree bootstrap script. Hook path breakage is fixed with one line — always use git rev-parse --show-toplevel inside hook scripts rather than assuming the working directory.[1][14]

Worktree-based parallel CI reduces pipeline time by 63% for 3-branch scenarios: traditional sequential CI for 3 branches takes 24 minutes (8 min × 3); parallel worktree-based CI cuts that to approximately 9 minutes.[10] The single most common CI integration failure is missing the merge_group event type in GitHub Actions workflow triggers — status checks configured only for pull_request cannot satisfy merge queue requirements, causing indefinite queue stalls because the queue creates a new temporary branch and expects CI results for it, but the workflow never fires on merge group events.[15][26][29]

The merge queue ecosystem emerged from a "Not Rocket Science Rule" first implemented in the early 2000s — main always passes all tests. The tooling matured through Bors (2013, Graydon Hoare's Rust repo bot), Homu (2014), Bors-NG (2017, deprecated 2023), and enterprise internal solutions before GitHub's public beta in February 2023.[3][12] That native implementation reduced GitHub's own average merge wait times by ~33%. Enterprise adoption is substantial: Uber's SubmitQueue reduced CI wait times by 74% in their monorepo; Shopify's Shipit is used by over 90% of core application PRs.[3][18]

GitHub Native Merge Queue carries a fundamental architectural flaw: two-phase testing means the SHA that passes CI (a1b2c3d) is not the SHA that lands on main (7d8e9f0) — the server rebuilds the merge commit before landing. Tested code differs from merged code, creating an undetected regression window.[2] Both Aviator and Mergify guarantee "Tested SHA = Merged SHA." Beyond that gap, GitHub Native is FIFO-only (no priority reordering), lacks CI batching, has no analytics dashboard, and cannot be paused — making it fit only for small teams (<10 engineers), low PR volume (<20/day), and CI under 15 minutes.[2] Aviator's Parallel Mode extends further: an "eventual consistency" fallback merges all PRs through a completed one when another is stuck, so the queue never blocks on a single slow CI run — a property absent from both GitHub Native and Mergify and critical for heterogeneous CI check durations.[7][25] Aviator also supports "thousands of parallel queues" for monorepos via affected-target detection, validating independent CI check sets and merging concurrently when two PRs share no overlapping targets.[6][17]

Branch naming is not cosmetic — it is the routing mechanism for CI/CD workflows, issue tracker auto-linking, and multi-agent collision prevention. The agent/ prefix convention (e.g., agent/TASK-123-implement-auth) provides machine-parseable traceability back to the task system, prevents collision with human developer branches, and enables CI routing rules specific to agent work.[16][30] Branch names must stay under 60–80 characters — CI systems, Windows paths, and older git versions fail silently on longer names. Poor branch naming produces three concrete operational failures: CI pipelines that cannot parse patterns fail silently; unclear scopes generate merge conflicts from overlapping parallel work; and branches lacking ticket IDs require manual cross-referencing that compounds with fleet size.[30] IDE support for worktrees arrived in VS Code in July 2025 and JetBrains 2026.1 (March 2026) — prior to those versions, the CLI is the authoritative view of worktree state.[1][11]

Implications for practitioners: The worktree + merge queue combination forms a complete parallel agent pipeline only when all three layers are configured correctly: worktrees with proper lifecycle management (lock before agent runs, use git worktree remove not rm -rf, run git worktree prune before each CI run), task decomposition that maps file ownership before creating worktrees (overlapping file lists require sequential not parallel execution), and a merge queue matched to team scale — GitHub Native for <20 PRs/day with simple CI, Mergify for teams with expensive CI or monorepos, Aviator for high-throughput pipelines where the SHA-integrity gap and FIFO blocking become operational risks. Teams reaching the 5–7 agent ceiling should add task queuing with atomic claims before adding more agents, not after. Enabling git rerere (git config rerere.enabled true) at fleet startup pays compounding dividends: Git records and reapplies conflict resolutions automatically as the same hotspot files generate repeated merge conflicts across worktree branches.[1][8][16][31]



Table of Contents

  1. Git Worktree Architecture and Core Mechanics
  2. Worktree Lifecycle: Create, List, Lock, Move, Remove, Prune, Repair
  3. Performance Characteristics and Storage
  4. Worktree Limitations and Known Failure Modes
  5. Branch Naming Conventions for Agent Identity
  6. AI Agent Workflow Patterns with Worktrees
  7. CI/CD Integration with Worktree-Based Pipelines
  8. Merge Queue Concepts: History and Core Guarantees
  9. Merge Queue Tool Comparison
  10. Parallel Mode and Automated Rebase Triggers

Section 1: Git Worktree Architecture and Core Mechanics

A Git worktree is "an additional working directory attached to the same repository."[9][14] Using git worktree add, a linked working tree is associated with an existing repository. Every repository begins with one main worktree (created by git init or git clone) and may have zero or more linked worktrees, each checked out to an independent branch.[8][9]

Two-Pointer Architecture

Each linked worktree maintains a two-pointer architecture that separates private worktree state from shared repository data:[9][11][28]

PointerPoints ToContains
$GIT_DIR .git/worktrees/<id>/ Per-worktree HEAD, index, per-worktree logs, lock marker
$GIT_COMMON_DIR Main .git/ directory All shared data: objects, refs, config, hooks

Each linked worktree contains a small .git file (not directory) pointing back to the main repo's object store.[9][11]

Internal Data Layout

$GIT_DIR/worktrees/<id>/
├── HEAD              # Per-worktree HEAD
├── index             # Per-worktree index
├── config.worktree   # Per-worktree config (if extensions.worktreeConfig enabled)
├── locked            # Lock marker file (contains reason text)
├── gitdir            # Points to worktree filesystem location
└── .git              # Points back to main repository

[9][14]

Shared vs. Per-Worktree Resources

ResourceScopeNotes
HEADPer-worktreeIndependent branch checkout per worktree
Index (staging area)Per-worktreeCompletely independent staging per worktree
MERGE_HEAD, REBASE_HEAD, CHERRY_PICK_HEADPer-worktreeIn-progress operation state isolated
refs/bisect/*, refs/worktree/*, refs/rewritten/*Per-worktreePseudo-refs under $GIT_DIR
Object store (.git/objects/)SharedCommits, trees, blobs never duplicated
All refs (refs/heads/, refs/tags/, refs/remotes/)SharedBranch refs visible across all worktrees
Hooks (.git/hooks/)Shared ⚠️Path assumptions in hooks break in linked worktrees
StashShared ⚠️git stash pop in one worktree applies stashes from others
Repository configShared (default)Override with extensions.worktreeConfig
.git/modules/ (submodules)Shared ⚠️Switching submodule commits in one worktree affects all

[9][14][24][28]

Why Worktrees Solve the Multi-Agent Problem

Without worktrees, concurrent agents encounter four structural failure modes:[1][11][28]

  1. Concurrent File Overwrites — changes silently overwrite each other without detection until merge time
  2. Context Contamination — agents operating on stale code cause cascading failures across interdependent changes
  3. Race Conditions — shared build caches, test databases, and config create classical concurrency issues
  4. Git Lock Contention — multiple agents competing for .git/index.lock causes fatal errors and potential system freezes
Key finding: Worktrees convert "invisible runtime corruption into visible merge-time conflicts." Each agent operates on its own branch, in its own filesystem path, with no possibility of direct file-level collisions during active work.[1][11][28]

Cursor IDE ships this pattern in production — its parallel agent feature creates one worktree per agent task, enabling multiple simultaneous code edits without conflicts.[5]

Isolation Boundaries: What Worktrees Do NOT Protect Against

Worktrees isolate agents at the filesystem level but provide no coordination at the semantic level. Two agents working on different features will frequently touch shared "hotspot files" — route definitions, configuration files, barrel exports, type definitions, and database schemas.[8] Worktrees also provide no runtime isolation — they share ports, databases, and process namespaces; layering lightweight containers on top of worktrees is required for full isolation.[1][11][28]

Storage Model Comparison

FactorWorktreesDockerSeparate Clones
Creation timeSecondsSeconds–minutesMinutes
Storage efficiencyShared objectsImage layers + deltaFull duplication
Filesystem isolationFullFull (OverlayFS)Full
Runtime isolationNone ⚠️Full (namespaces)None ⚠️
Best forCode-only workflowsFull-stack agentsOne-off isolated testing

[1][11][20]

See also: Concurrency Control Theory (classical isolation models)

Section 2: Worktree Lifecycle: Create, List, Lock, Move, Remove, Prune, Repair

Creating Worktrees

The core command is:[9][14]

git worktree add -b <new-branch> <path> <commit-ish>

Key flags for the add subcommand:[9][14][27]

FlagEffectGit Version
-b / -B <new-branch>Create / reset branch at commit-ishAll
-d / --detachCreate with detached HEADAll
--no-checkoutSkip automatic checkout (enables sparse-checkout config)All
--orphanCreate empty worktree with unborn branchGit 2.44+ (2024)
--lockKeep worktree locked immediately after creationAll
--guess-remote / --no-guess-remoteMatch remote tracking branchesAll
-q / --quietSuppress feedbackAll

By default, add refuses to create a worktree when <commit-ish> is a branch already checked out by another worktree.[9][14][27]

Directory Layout Patterns

PatternExample LayoutRecommended By
Sibling directory ~/projects/ml-pipeline-feature-auth/ (sibling of main repo) gitworktree.org[10]
Gitignored subdirectory .trees/TASK-123/ inside main repo, gitignored Augment Code[11]
Named subdirectory variant .worktrees/ or .claude/worktrees/ MindStudio[16]

Most common naming convention: projectname-branchname for self-documenting layout.[10][19][11]

Listing Worktrees

git worktree list              # human-readable
git worktree list -v           # verbose (locked/prunable annotations)
git worktree list --porcelain  # machine-parseable (stable across versions)

The --porcelain format is stable across Git versions and is the correct choice for scripted parsing.[9][10] Each worktree is emitted as a blank-line-delimited stanza:

worktree /path/to/linked-worktree
HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
branch refs/heads/master

worktree /path/to/locked-worktree
HEAD 5678abc5678abc5678abc5678abc5678abc5678c
branch refs/heads/locked-branch
locked reason why is locked

[9][10]

Locking and Unlocking

Locking prevents a worktree from being pruned, moved, or deleted:[9][10][19][27]

git worktree lock --reason "Agent running" .trees/TASK-123
git worktree unlock .trees/TASK-123

Critical use case: worktrees on portable devices, network drives, or hosting actively running agents. When locked, git worktree prune ignores the worktree even if its directory is missing.[9][27]

Removing Worktrees

git worktree remove .trees/TASK-123          # safe removal (directory + metadata)
git worktree remove --force .trees/TASK-123  # force remove with uncommitted changes
# --force twice: remove locked worktrees

git worktree remove simultaneously deletes files from disk AND removes metadata from .git/worktrees/. It refuses to remove worktrees with untracked files or uncommitted changes unless --force is used. The main worktree cannot be removed.[9][10][27]

Key finding: Always prefer git worktree remove over manual rm -rf. Manual deletion leaves stale metadata behind, causing phantom entries in git worktree list and "already checked out" errors.[1][4][10]

Pruning Stale Metadata

git worktree prune                  # remove stale administrative data
git worktree prune -n -v            # dry run with verbose output
git worktree prune --expire <time>  # only prune older than specified time
git worktree prune --verbose        # report all removals

When a worktree directory is deleted with rm -rf, Git still considers it active, causing three specific problems:[10][19][27]

Git automatically runs a lightweight prune during git worktree add. Automatic garbage collection uses gc.worktreePruneExpire (default: 3 months). Force immediate prune: git config gc.worktreePruneExpire now.[10][19][27]

Moving Worktrees

git worktree move <worktree> <new-path>

Limitations: cannot move the main worktree; cannot move linked worktrees containing submodules; requires --force twice if destination is locked.[9][14]

Repairing Broken Links

Worktrees rely on bi-directional pointers: the worktree has a .git file pointing to the main repo; the main repo has a path pointing to the worktree. If either is moved manually, pointers break:[10][19][27]

git worktree repair ../path/to/moved-worktree1 ../path/to/moved-worktree2

Configuration Options

OptionDefaultPurpose
worktree.guessRemotefalseAuto-track remote if unique match exists
worktree.useRelativePathsfalseRelative internal links — repo can move without breaking worktrees (Git 2.46+)
gc.worktreePruneExpire3 monthsAuto-prune interval for stale worktree metadata
extensions.worktreeConfigfalseEnables per-worktree config.worktree file

[9][14][24]

Per-Worktree Configuration

git config extensions.worktreeConfig true
git config --worktree <key> <value>
# Stored in: $GIT_DIR/worktrees/<id>/config.worktree

Configuration variables that must NOT be shared across worktrees: core.worktree (never shared), core.bare (don't share if true), core.sparseCheckout (don't share unless consistent).[9][14][24]

Branch Exclusivity Constraint

Git enforces that the same branch cannot be checked out in more than one worktree simultaneously. This restriction prevents conflicting updates to the same branch ref — if two worktrees could modify the same branch independently, commits could be lost. Workarounds:[1][9][28]

Git Version Milestones

VersionReleaseWorktree Feature Added
Git 2.442024git worktree add --orphan — creates worktree with unborn branch (useful for gh-pages-style split deploy branches)
Git 2.462024worktree.useRelativePaths config + --relative-paths flag — enables extensions.relativeWorktrees so main repo can move without breaking worktrees

[11][24]


Section 3: Performance Characteristics and Storage

Creation Performance

Creating a worktree is faster than cloning because git worktree add shares the existing repository objects instead of re-fetching them. A single fetch in any worktree synchronizes objects for all worktrees, eliminating redundant network transfers.[28] Parallel fetch with 4 workers can reduce fetch time by approximately 71% compared to sequential execution.[28] (Note: this figure is sourced from gitcheatsheet.dev, a community reference resource, not a primary benchmark study; treat it as an order-of-magnitude guideline rather than a verified measurement.)

Disk Cost Model

Working-directory files are still copied per worktree; disk cost scales with file count, not history size. A 500 MB repository with five active worktrees uses at least 2.5 GB for checked-out files alone.[10][28] High-cost directories (node_modules, venv, target/) are per-worktree and multiply linearly.[8][16]

Filesystem-Specific Worktree Limits

FilesystemApproximate Community BenchmarkNotes
ext4~8–12Typical developer machine ceiling
XFS15–20+Better inode scaling
ZFS25+Dynamic inode allocation with proper tuning

[28]

Note: These figures are community-reported practical ceilings, not hard limits enforced by Git. Git itself imposes no maximum worktree count; actual limits depend on available disk space, memory, and inode allocation on the host filesystem. Source: gitcheatsheet.dev (raw_28.md) — no primary benchmark study or kernel/Git documentation backs these specific numbers.

Parallel Agent Throughput Scaling

Agent CountPractical CeilingRequired Infrastructure
2–5Standard workflow (tmux-based or manual)Manual monitoring; no additional tooling required[4][31]
5–7Modern laptop productive ceilingRate limits, disk consumption, merge review overhead cancel throughput gains[16]
5–10Requires task queuingShared JSON with locking for atomic task claims, headless execution, dependency-aware scheduling[31]
10+Full orchestration requiredTask queues, rate limit handling, automated monitoring, conflict detection pipelines[16]

CI Performance Impact

Traditional sequential CI for 3 branches takes 24 minutes (8 min × 3); worktree-based parallel CI cuts that to approximately 9 minutes — a 63% reduction.[10] With 30-minute CI and a serial merge queue, maximum theoretical throughput is approximately 48 PRs/day; batching and parallelism multiply this significantly.[18]

Key finding: Parallel fetch with 4 workers cuts fetch time by ~71%; worktree-based parallel CI cuts pipeline time by ~63% for 3-branch scenarios. The shared object store is the mechanism behind both gains — no re-fetching, no re-storing.[28][10]

Sparse Checkout Integration

Pair git worktree add with sparse checkout to constrain disk usage for agent-relevant file domains in monorepos:[1][11]

git worktree add --no-checkout .trees/TASK-123 -b agent/TASK-123 origin/main
cd .trees/TASK-123
git sparse-checkout set <paths>
git checkout
See also: Monorepo Tooling (Bazel/Buck integration with sparse checkouts)

Section 4: Worktree Limitations and Known Failure Modes

Index Lock (.index.lock) Issues

Git creates an index.lock file before any write operation to prevent concurrent modifications. If the agent process crashes during a git operation, the lock file persists. Each worktree has its own index lock at .git/worktrees/<n>/index.lock, so crashes affect only the specific worktree.[8][14]

Common causes of stale locks: background IDE/editor processes (VS Code, JetBrains keep background git processes running), file watchers, git hooks. Diagnosis:

find .git/worktrees -name "index.lock"
# Remove only if no Git process is running

[8][14]

Submodule Limitations

Multiple checkout with submodules is still experimental and support is incomplete per official Git documentation.[8][9][14][24]

Submodule RestrictionImpact
Cannot use git worktree move on worktrees with submodulesBlocks filesystem reorganization
Unclean worktrees with submodules require --force to removeComplicates automated cleanup
.git/modules/ is shared — switching submodule commits in one worktree affects all othersCross-worktree state pollution
Official docs: "NOT recommended to make multiple checkouts of a superproject"No upstream fix planned

Mitigations: prefer git subtrees or vendoring over submodules; configure submodule.recurse true, diff.submodule log, status.submodulesummary 1.[8][9][24]

Shared Hooks: Path Assumption Breakage

All worktrees share the same hooks from the main .git/hooks/. A hook that uses hardcoded paths or assumes it's running at the repo root breaks in linked worktrees.[1][8][14][24] The fix: always use git rev-parse --show-toplevel in hooks:

#!/bin/bash
ROOT=$(git rev-parse --show-toplevel)
npm --prefix "$ROOT" run lint-staged

Per-worktree hook customization requires core.hooksPath set per-worktree using extensions.worktreeConfig.[1][8][14][24]

Shared Stash Gotcha

git stash pop in one worktree can apply a stash created in another. This is a structural behavior, not a bug, and has no configuration override.[24]

IDE Indexing Overhead

IDE indexes run independently per worktree, creating duplicate CPU and disk usage with no known workaround.[24]

IDEWorktree Support Added
VS CodeJuly 2025
JetBrains2026.1 (March 2026)

Treat CLI as authoritative worktree state view for IDE versions prior to these dates.[1][11][20]

No Cross-Worktree Conflict Warnings

Git provides no mechanism warning when parallel agents modify identical files on different branches — conflicts only surface at merge time.[1][8][16] Mitigations: assign agents to strictly non-overlapping file domains; enable git rerere for automatic conflict resolution reapplication; pre-plan file ownership before launching agents. Enable rerere with git config rerere.enabled true — Git then records conflict resolutions and reapplies them automatically when the same conflict recurs across worktree merges.

Shared Object Database Corruption Risk

Running concurrent git operations across multiple worktrees can cause corruption of the shared .git object store. Git is designed as a single-process tool. The safe model: each agent runs its own git operations in its own worktree; no two agents run git commands simultaneously in the same worktree.[16][28]

Consolidated Shared vs. Per-Worktree Behavior Reference

AreaBehaviorRisk Level
IndexPer-worktree (independent staging)Safe
HEADPer-worktree (independent)Safe
Object storeShared (efficient disk use)Safe (read-only concurrent access)
Refs (refs/heads/, etc.)Shared across worktreesCaution (branch name collisions)
ConfigShared (main .git/config)Caution
StashShared across all worktrees ⚠️High
HooksShared from .git/hooks/ ⚠️High (path assumptions break)
SubmodulesShared .git/modules/; move blocked ⚠️High
Branch checkoutSame branch cannot be in two worktrees ⚠️Enforced by Git

[24]

Key finding: The five high-risk shared resources — stash, hooks, submodule data, concurrent git operations on the object store, and branch exclusivity — account for the majority of worktree-related incidents in production agent pipelines. Pre-flight checks for each should be part of any worktree bootstrap script.[8][16][24][28]

Section 5: Branch Naming Conventions for Agent Identity

Standard Prefix Taxonomy

PrefixSemantic MeaningMachine-Routable
feature/Developing new featuresYes — triggers test workflows
bugfix/Fixing bugsYes
hotfix/Critical production fixesYes
release/Preparing a production releaseYes — triggers deploy workflows
chore/, refactor/, docs/, test/, ci/Non-feature workPartial
agent/AI agent-driven branches (emerging convention)Yes — enables agent-specific CI routing

[30]

Naming Rules

Agent-Specific Naming Patterns

The agent/ prefix with task ID provides clear identification of machine-generated branches, traceability back to the task system, collision prevention with human developer branches, and enables CI/CD routing rules specific to agent work.[16][30]

PatternExampleUse Case
Agent + task IDagent/TASK-123-implement-authSingle-agent task tracking[30]
Agent + feature nameagent/feat-auth-moduleFeature-scoped work[16]
Worktree slug + agent nameworktree/auth-module--claude-01Multi-agent environments[16]
Spec-linked namesfeature/spec-3.2-jwt-refreshMindStudio playbook — maps branches to spec sections, prevents scope creep[16]

Ticket ID Embedding for Traceability

Embedding the ticket ID in the branch name enables automatic linking in issue trackers. Specifically, it enables: JIRA, Linear, and GitHub to auto-link branches to tickets, auto-populate PR descriptions from ticket titles, show sprint boards with active branches, and generate release notes from merged branch names.[30]

feature/JIRA-456-add-dark-mode
bugfix/GH-123-fix-login-redirect
agent/TASK-123-implement-auth

CI/CD Integration via Branch Names

Modern CI/CD pipelines use branch names for workflow routing:[30]

Validation regex for CI enforcement:[30]

^(feature|bugfix|hotfix|release|chore|refactor|docs|test|ci|agent)\/[a-z0-9][a-z0-9-\/]*$
Key finding: Poor branch naming creates three concrete operational failures — CI/CD pipelines that cannot parse patterns fail silently; unclear scopes generate merge conflicts from parallel work on overlapping areas; and branches lacking ticket IDs require manual cross-referencing that compounds as agent fleet size grows.[30]

Section 6: AI Agent Workflow Patterns with Worktrees

Worktree-Per-Task vs. Worktree-Per-Agent

StrategyBest ForTrade-offs
Worktree-Per-Task (recommended default) Ephemeral agents completing work in under an hour Minimal overhead; agents reassigned as needed; clean lifecycle[1][11][20]
Worktree-Per-Agent Persistent specialist agents in extended sessions Warm dependency caches, accumulated context; harder lifecycle management[1][11][20]

Bootstrap Script (Production Pattern)

TASK_ID="${1:?Usage: $0 <task-id> [base-branch]}"
BASE_BRANCH="${2:-main}"
BRANCH_NAME="agent/$(sanitize_branch_name "${TASK_ID}")"
WORKTREE_PATH=".trees/${TASK_ID}"

git fetch origin main
git worktree add -b "${BRANCH_NAME}" "${WORKTREE_PATH}" "origin/${BASE_BRANCH}"
cd "${WORKTREE_PATH}" && npm ci --prefer-offline
git worktree lock --reason "Agent running" "${WORKTREE_PATH}"

[1][11][16]

Deterministic Port Assignment

To prevent runtime port collisions across worktrees, use branch name hashing to assign stable ports:[11][20]

PORT=$(( 3100 + $(echo "${BRANCH_NAME}" | cksum | cut -d' ' -f1) % 6899 ))

This assigns a stable port in the range 3100–9999 per branch, deterministically derived from the branch name.

Dependency Management Strategies

StrategyBest ForTrade-offs
Symlink node_modulesByte-identical package-lock.jsonFast; risky if locks diverge between worktrees
Copy-on-WritemacOS APFS onlyZero upfront cost; not portable
npm WorkspacesMonoreposShared top-level node_modules
Offline Cache (npm ci --prefer-offline)Universal defaultLonger first install; always safe

[1][11][20]

Task Decomposition: Mandatory Prerequisite

Worktree isolation only works for genuinely independent tasks. "If two tasks have overlapping file lists, they need to be sequential, not parallel."[4][16][31] Map file ownership before creating worktrees. The most common mistake: "launching agents before planning file ownership" creates expensive merge conflicts requiring rework.[4][16][31]

Shared Context Without Shared State

Distribute an AGENTS.md project brief containing architecture decisions, coding conventions, API contracts between components, and active task ownership list. This prevents context drift while maintaining filesystem isolation. A "living spec" serves as the shared coordination artifact all agents read from and write to.[16][31]

Emergency Fix Pattern

A canonical use case for worktrees is applying an emergency fix to a stable branch without disturbing in-progress work. The full lifecycle in three commands:[9]

git worktree add -b emergency-fix ../temp master
cd ../temp
git commit -a -m 'emergency fix'
cd -
git worktree remove ../temp

Verification Gates

Establish a clean test baseline before handing off to agents:[1][11]

  1. Create worktree and run npm lint && npm test
  2. Confirm suite passes green
  3. Delegate to agent for implementation
  4. Run tests again after completion — any new failures are attributable to agent changes

Merge Strategy

Standard practice is rebasing feature branches on latest main before merging. For fleets beyond 5–7 agents, FIFO merge queues with tiered conflict resolution automation handle ordering and reduce manual review overhead.[1][11]

Three-Tier Agent Architecture (Augment Code)

A structured multi-agent coordination pattern with three layers:[1][11][20]

  1. Coordinator — plans and decomposes work; manages alignment, dependency ordering, and handoffs
  2. Specialists (six personas) — execute in parallel: Investigate, Implement, Verify, Critique, Debug, Code Review
  3. Verifier — quality gate checking results against spec before developer review

All agents share a Context Engine for semantic codebase understanding.[1][11][20]

Common Failure Modes

#Failure ModeRoot CauseMitigation
1File ownership conflictsLaunching agents before planning file assignmentsPre-map file ownership; enforce non-overlapping domains[31]
2Node modules corruptionShared symlinked dependencies with concurrent installsKeep modules isolated per worktree[31]
3Context driftArchitectural decisions made mid-task not propagatedUpdate shared brief immediately on any decision[31]
4Undefined completionAgents lack explicit exit criteriaDefine acceptance criteria per task before agent launch[31]
5Skipped code reviewSpeed of generation → skipping review stepAI-generated code still requires human review regardless of speed[31]

Quick-Start Checklist (Full Lifecycle)

echo '.trees/' >> .gitignore
git worktree add .trees/TASK-123 -b agent/TASK-123 origin/main
cd .trees/TASK-123 && npm ci --prefer-offline
git worktree lock --reason "Agent running" .trees/TASK-123
git worktree list --porcelain
# ... agent runs ...
git worktree unlock .trees/TASK-123
git worktree remove .trees/TASK-123
git worktree prune

[1][11][20]

Key finding: The productive ceiling for parallel agents on a modern laptop is 5–7 concurrent before rate limits, disk consumption, and merge review overhead cancel out throughput gains. Beyond 10 agents, full orchestration infrastructure is mandatory.[16][31]

Section 7: CI/CD Integration with Worktree-Based Pipelines

Standard CI Worktree Pattern

# Prune before creating (avoids stale metadata errors)
git worktree prune
git worktree add ../acme-build release/v2.3
# ... run build and tests ...
git worktree remove ../acme-build

[10][27]

A common CI failure is when a previous worktree wasn't cleaned up: error "worktree path already exists." Solution: add force cleanup to CI script:[10][27]

git worktree prune
git worktree remove --force ../ci-build-* || true
git worktree add ../ci-build-$CI_COMMIT_SHA $CI_COMMIT_SHA

PR Review Environment Pattern

git worktree add --detach ../review-$PR_NUMBER
git fetch origin pull/$PR_NUMBER/head:pr-$PR_NUMBER
git -C ../review-$PR_NUMBER checkout pr-$PR_NUMBER
cd ../review-$PR_NUMBER && npm ci && npm test

[27]

Auto-Update All Worktrees Script

#!/bin/zsh
git fetch --all --prune
WORKTREES=$(git worktree list | awk '{print $1}' | tail -n +2)
for DIR in $WORKTREES; do
  cd "$DIR" || continue
  BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "detached")
  if [[ "$BRANCH" != "detached" ]]; then
    git rebase origin/"$BRANCH"
  fi
  cd - > /dev/null
done

[10][19]

GitHub Actions: merge_group Event Trigger

When using GitHub Merge Queue, CI must be updated to include the merge_group event trigger:[15][26]

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]
  merge_group:
    types: [checks_requested]

For third-party CI providers, configure to run on branches matching pattern gh-readonly-queue/{base_branch}/*.[15][26]

Known pitfall: Having required status checks configured only for pull_request triggers causes the merge queue to stall — the queue creates a new temporary branch and expects CI results for it, but the workflow only fires on PR events, not merge group events.[15][26][29]

CI Status Integration: wt CLI Tool

Tools like wt support wt status --ci, which displays CI/CD pipeline status per worktree — showing ✓ (pass), ✗ (fail), or ● (pending) for each branch's latest pipeline run. This feature requires gh (GitHub CLI) or glab (GitLab CLI) to be installed and authenticated.[10]

CI Best Practices

PracticeRationale
Name worktrees with descriptive prefixes (project-review-, project-build-)Enables scripted pattern-match cleanup[10][19][27]
Automate cleanup with scheduled cron jobs or pre-push hooksPrevents stale metadata accumulation[10]
Use --lock for portable/network worktreesPrevents accidental prune of active worktrees[10]
Add .trees/ or .worktrees/ to .gitignorePrevents accidental tracking of worktree directories[11][16]
Use --porcelain format for all scripted output parsingStable format across Git versions[9][10]
Run git worktree prune before git worktree add in CIAvoids "path already exists" CI failures[10][27]

Shell Convenience Aliases

alias gwtclean='git worktree prune --verbose && git worktree list'
git config --global alias.wt-clean '!git worktree prune -v && git worktree list'

[10][19]

Key finding: The single most common CI/CD integration failure is missing the merge_group event type in GitHub Actions workflow triggers. Status checks configured only for pull_request cannot satisfy merge queue requirements, causing indefinite queue stalls.[15][26][29]

Section 8: Merge Queue Concepts: History and Core Guarantees

The Core Problem: Merge Skew and Semantic Conflicts

Merge skew occurs when changes appear compatible individually but break when merged together into an updated codebase — two PRs may each pass CI independently, but break main after merging.[29][18]

Semantic conflict: a change does not integrate properly even though Git reports no textual conflict. Examples:[29]

"CI lacks awareness of the bigger picture" — it cannot pre-emptively perform checks on hypothetical future states resulting from multiple PR merges.[29][18]

How Merge Queues Solve the Problem

A merge queue:[3][29]

  1. Determines an order all PRs should be merged in
  2. Tests each PR in a merged state (via temporary branches against current main + PRs ahead of it)
  3. Ensures PRs are healthy to merge in that order (catching both textual and logical conflicts)
  4. Performs the actual merge automatically

The fundamental guarantee: "main branch always passes all tests."[3][29]

History and Evolution of Merge Queues

YearTool / EventKey Contribution
Early 2000sBen Elliston's cron + DB systemFirst implementation of "Not Rocket Science Rule" — always passing tests[3][12][22]
2013Bors (Graydon Hoare)Bot for Rust repo — merged to temp branch, ran tests, only fast-forwarded main on pass[3][12]
2014Homu (Barosl Lee)Tested changes before landing by temporarily combining with up-to-date main; launched homu.io 2015; stagnated ~2018[3][22]
2017Bors-NG (Michael Howell)Open-source replacement; faster, easier self-hosting; deprecated 2023 when GitHub launched native queue[3][12]
2017Bulldozer (Palantir)Automated merges when checks passed; auto-updated branches[3][12]
2018Mergify (Julien Danjou & Mehdi Abaakouk)SaaS "merge queue as a service" — flexible rules, priority configs, batch merging[3][22]
2019Kodiak (Christopher Blump)FIFO PR processing, proper queue management eliminating race conditions; gained adoption after Vercel CEO endorsement[22]
2019GitLab Merge Trains (12.0)Built-in queue — sequences MRs, runs pipelines on each result before landing[3][22]
2023 FebGitHub Merge Queue (public beta)Native GitHub implementation; reduced GitHub's own average wait times by ~33%[3][12][22]
2023 JulGitHub Merge Queue (GA)Generally available; Bors-NG formally deprecated[3][12]

Enterprise Internal Solutions

CompanyToolReported Impact
UberSubmitQueueReduced CI wait times by 74% in their monorepo[3][18]
ShopifyShipitOver 90% of core application PRs use the merge queue[3][18]
StravaButlerEnforces orderly merging for fast-moving teams[3]

GitHub Merge Queue: Internal History

GitHub engineers were merging approximately 1,000 PRs monthly by 2016. Internal systems matured 2020–2021 before public beta in February 2023. The implementation reduced average wait times by ~33% internally.[3][12][22]

Queue Drain Mechanics (GitHub)

  1. User adds PR #1 to the merge queue
  2. Queue creates a temporary branch: target branch + PR #1 changes
  3. merge_group webhook dispatched, awaits CI results
  4. User adds PR #2; new temporary branch: target branch + PR #1 + PR #2
  5. When CI passes for both temporary branches, final combined branch merges into target
  6. On CI failure: failing PR removed, temporary branch recreated for next PR without failing changes[15][26]

Automatic Rebase on Queue Drain

When the queue drains (a PR at the front is merged), merge queue tools automatically:[6][17][18]

  1. Update subsequent PRs to include the merged changes
  2. Trigger CI reruns on the updated temporary branches
  3. Proceed with merge if CI passes on the rebased state

This automated rebase trigger fires on every queue drain event and is the mechanism that maintains the "main always passes" guarantee across concurrent PRs.

Batching for Throughput

Batching multiple PRs into a single CI run can reduce CI time by up to 66% when most PRs don't have semantic conflicts.[18][29] On batch failure, the queue bisects to find the culprit. Concrete throughput comparison:[2]

ScenarioCI DurationPRsTotal CI Time
Bors/batch merge10 min10010 minutes total
GitHub Merge Queue (serial)10 min1001,000 minutes total

[2]

Key finding: Serial merge queues with 10-minute CI and 100 PRs require 1,000 minutes of CI time — 100× more than batch approaches. Batching with bisect-on-failure preserves the safety guarantee while eliminating the serial throughput bottleneck.[2][18]
See also: Post-Merge Agent Recovery (rebase vs. restart decision logic after queue drain)

Section 9: Merge Queue Tool Comparison

GitHub Native Merge Queue

Built-in; no additional setup beyond branch protection rules. Public beta February 2023, GA July 2023. Reduced GitHub's own average wait times by ~33%.[3][12]

Technical limitations:[2]

Fit: Small teams (<10 engineers), simple CI (<15 min), low PR volume (<20/day), no monorepo complexity.[2]

Mergify

SaaS, launched 2018. Addresses key GitHub Native gaps — CI batching, two-step CI validation, queue pause, analytics, Slack/Datadog integrations.[2][13][21]

Capability gaps vs. Aviator:[13][21]

Fit: Teams with 20+ daily contributors, expensive CI, monorepos, complex validation requirements.[2]

Aviator MergeQueue

Most feature-complete of the three. Supports both cloud and self-hosted (GitHub Enterprise) deployment. Open-source CLI (av) for stacked PR workflows.[6][13][23][25]

Complete Feature Matrix

FeatureAviatorMergifyGitHub Native
Speculative checks
CI batching
Parallel mode testing
Two-step CI validationLimited ⚠️
Monorepo batching
Affected targets (multi-queue)
Multiple priority levels❌ (jump to front only)
Queue pause
Auto-retry on flaky tests
Analytics dashboard
Tested SHA = Merged SHA❌ ⚠️
Stacked PR support
Fast forwarding (linear history)
Cross-repo PR dependencies
Self-hosted optionLimitedN/A
GraphQL API

[2][13][21][23]

Affected Targets: Monorepo Strategy

Aviator's "affected targets" strategy focuses testing only on parts of the codebase directly impacted by a pull request. Aviator can create "thousands of parallel queues" for monorepos, validating independent CI check sets and merging concurrently. When two PRs have no overlapping affected targets, they can be tested and merged independently in any order.[6][17][18][25]

Semantic Conflict Detection Tooling

Beyond merge queues, dedicated research tools exist for semantic conflict detection:[18][29]

Other Tools

Key finding: GitHub Native Merge Queue's two-phase testing flaw — where the tested SHA differs from the merged SHA — is a fundamental architectural gap that Aviator and Mergify both solve with "Tested SHA = Merged SHA" guarantees. For any team where post-merge regressions have operational consequences, GitHub Native is insufficient.[2]
See also: Monorepo Tooling (monorepo-specific queue strategies with Bazel/Buck affected target detection)

Section 10: Parallel Mode and Automated Rebase Triggers

Aviator Parallel Mode: Mechanics

Parallel Mode creates Draft PRs combining queued changes and runs CI in parallel optimistically. On failure, it closes subsequent Draft PRs and restarts the queue.[7][25]

CI Failure Handling in Parallel Mode

ScenarioBehavior
First Draft PR fails; no other PR queuedOriginal PR is dequeued[7][25]
First Draft PR fails; others are queuedBot closes all subsequent Draft PRs; restarts queue without the failing PR[7][25]
A Draft PR's CI is stuck but a subsequent one completes"Eventual consistency" logic merges all PRs through the completed one[7][25]
Flaky test on a Draft PRConfigurable retry count; TestDeck integration for flake detection[7][25]

The max_parallel_builds config controls concurrent Draft PR builds.[7][25]

Stacked PR Support

Aviator's open-source CLI (av) supports stacked PR workflows. av pr --queue queues entire stacks; the tool handles stack-aware ordering and syncing. No equivalent capability exists in Mergify or GitHub Native Merge Queue.[7][13][25]

Merge Methods Supported

MethodHistory ShapeNotes
Merge commitNon-linear, full historyTraditional; default for most tools[15][17]
RebaseLinear, commits preservedAdds commits to head of target branch[15][17]
SquashLinear, commits condensedSingle new commit per PR[15][17]
Fast forward (Aviator only)Linear, no merge commitsMaintains cleaner history; not available in GitHub Native or Mergify[6][13]
Key finding: Parallel Mode's "eventual consistency" fallback — merging all PRs through a completed one when another is stuck — means Aviator's queue never blocks on a single slow CI run. This property is absent from both GitHub Native and Mergify, making Aviator the only production-grade option for high-throughput pipelines with heterogeneous CI check durations.[7][25]
See also: Post-Merge Agent Recovery (rebase vs. restart decision logic for agents after merge queue drain events)

Sources

  1. How to Use Git Worktrees for Parallel AI Agent Execution | Augment Code (retrieved 2026-05-03)
  2. Mergify vs GitHub Merge Queue | Mergify (retrieved 2026-05-03)
  3. The Origin Story of Merge Queues | Mergify (retrieved 2026-05-03)
  4. Git Worktrees for AI Coding: How to Run Multiple Agents Without Conflicts | MindStudio (retrieved 2026-05-03)
  5. Git Worktrees: The Power Behind Cursor's Parallel Agents - DEV Community (retrieved 2026-05-03)
  6. Aviator MergeQueue: Keep Builds Green with Scalable Merge Automation (retrieved 2026-05-03)
  7. Parallel Mode | Aviator Documentation (retrieved 2026-05-03)
  8. Git - git-worktree Documentation (official) (retrieved 2026-05-03)
  9. Git - git-worktree Official Documentation (retrieved 2026-05-03)
  10. git worktree prune - Clean Up Stale Worktrees | GitWorktree.org (retrieved 2026-05-03)
  11. How to Use Git Worktrees for Parallel AI Agent Execution | Augment Code (retrieved 2026-05-03)
  12. The Origin Story of Merge Queues | Mergify (retrieved 2026-05-03)
  13. Aviator MergeQueue vs. Mergify: A Comparison (retrieved 2026-05-03)
  14. Git - git-worktree Documentation (Official) (retrieved 2026-05-03)
  15. Managing a merge queue - GitHub Docs (retrieved 2026-05-03)
  16. Parallel Agentic Development With Git Worktrees: A Practical Playbook | MindStudio (retrieved 2026-05-03)
  17. What is a Merge Queue? How GitHub Merge Queue Helps CI/CD | Aviator (retrieved 2026-05-03)
  18. Merge Queues for Large Monorepos | Aviator (retrieved 2026-05-03)
  19. git worktree prune - Clean Up Stale Worktrees | GitWorktree.org (retrieved 2026-05-03)
  20. How to Use Git Worktrees for Parallel AI Agent Execution | Augment Code (retrieved 2026-05-03)
  21. Aviator MergeQueue vs. Mergify: A Comparison (retrieved 2026-05-03)
  22. The Origin Story of Merge Queues | Mergify (retrieved 2026-05-03)
  23. Aviator MergeQueue vs GitHub Merge Queue | Aviator (retrieved 2026-05-03)
  24. Git - git-worktree Documentation (official) (retrieved 2026-05-03)
  25. Parallel Mode | Aviator Documentation (retrieved 2026-05-03)
  26. Managing a merge queue - GitHub Docs (retrieved 2026-05-03)
  27. git worktree prune - Clean Up Stale Worktrees | GitWorktree.org (retrieved 2026-05-03)
  28. Performance Optimization for Git Worktrees – Git Cheat Sheet + Reference (retrieved 2026-05-03)
  29. What is a Merge Conflict? Understanding the Difference Between Semantic and Code Conflicts - DEV Community (retrieved 2026-05-03)
  30. Master Git Branch Naming: 2026 Guide to Best Conventions (retrieved 2026-05-03)
  31. Parallel Agentic Development With Git Worktrees: A Practical Playbook | MindStudio (retrieved 2026-05-03)

Home