Stop Cloning Your Repos: A Guide to Git Worktrees for Heavy Monoliths and AI Agents

Christopher Espiritu

Christopher Espiritu

Stop Cloning Your Repos: A Guide to Git Worktrees for Heavy Monoliths and AI Agents

If you've ever been deep in the zone on a feature branch, only to be interrupted by an urgent hotfix, you know the pain of Git context switching. You stash your messy changes, stop your local development server, switch to main, and pray you don't encounter conflicts when you come back.

Or maybe you're stepping into the future: you want to run multiple AI coding agents (like Claude and Codex) simultaneously — Claude working on Feature A and Codex working on Feature B at the exact same time.

If you just run git checkout in a single folder, they overwrite each other. If you run git clone three times, you waste gigabytes of disk space and have to constantly sync with git pull.

Enter Git Worktrees.


What is a Git Worktree?

A Git worktree allows you to check out multiple branches into completely separate physical folders on your hard drive, while sharing the exact same underlying .git database.

Think of it this way: a clone makes a completely independent, duplicated universe. A worktree just gives you a second physical desk to work on the exact same project.

The Visual Difference

❌ The Old Way: git clone Uses double the disk space. Commits don't sync locally.

Folder A: /my-app/               Folder B: /my-app-claude/
├── .git/  (1GB database)        ├── .git/  (1GB database)  ← Duplicated!
├── .env                         ├── .env
└── index.php                    └── index.php

✅ The New Way: git worktree Instant setup. Barely uses extra disk space. Commits sync instantly.

Folder A: /my-app/               Folder B: /my-app-claude/
├── .git/  (1GB database) ◄───── .git   (1KB text file)    ← Shared Brain!
├── .env                         ├── .env
└── index.php                    └── index.php

Because they share the same brain, a commit made in Folder B is instantly visible in Folder A's git log. No pushing or pulling required.

The "Simultaneous" Superpower

Because worktrees are separate folders, you can run multiple development servers side-by-side without them interfering with each other.

If you're using PHP/Laravel:

/my-app       → php artisan serve --port=8000   # main branch
/my-app-claude → php artisan serve --port=8001  # Feature A
/my-app-codex  → php artisan serve --port=8002  # Feature B

You can open three browser tabs and see three different branches of your code running live.


The "Gotcha": The Ignored Files Tax

Creating a worktree is easy:

git worktree add ../app-claude feature-a

But when you open that new folder, you might panic — your .env is gone, and your node_modules/ or vendor/ folders are missing.

This is a feature, not a bug. Git only copies tracked files into a new worktree. Anything in your .gitignore is intentionally left behind, which provides powerful environmental isolation:

  • An agent can install a new NPM package in its worktree without breaking your main branch dependencies.
  • You can run different versions of PHP or Node in different folders.

The trade-off is the Setup Tax — every time you create a worktree, you need to copy your .env and run npm install or composer install.

Pro tip: Don't create new worktrees every day. Instead, create 2–3 permanent ones (e.g., app-review, app-hotfix) and just swap branches inside them to reuse node_modules.


The Monolith Meltdown: Docker and Worktrees

If your app uses Docker, worktrees introduce a serious challenge.

A typical modern app doesn't just run one service — it might spin up a web container, a Postgres database, a Redis cache, and a LocalStack instance to emulate AWS services locally. If you run docker compose up in /my-app, Docker binds all of those to their respective ports. If an agent then tries to run docker compose up in its own worktree, Docker throws a "port already allocated" error and crashes.

You could work around this by offsetting ports in each .env file (e.g., DB_PORT=5433, REDIS_PORT=6380). That gives each worktree a fully isolated stack — but it doesn't scale.

The real problem: heavy services multiplied.

With your main app plus two agent worktrees each running their own full stack, you're suddenly running three copies of Postgres, three Redis instances, and three LocalStack containers simultaneously. Your machine will be gasping before a single line of code gets written.

The Solution: The Logical Database Architecture

Instead of duplicating the heavy infrastructure, run your shared services once and use Docker networks to let the separate worktrees connect to them.

To prevent agents from clobbering each other's data, create separate logical databases inside the single Postgres instance (Redis and LocalStack can typically be shared as-is, since they're either ephemeral or namespace-isolated):

┌─────────────────────────────────────────────────────────────┐
│                 Your Laptop (CPU & RAM Saver)               │
│                                                             │
│  ┌───────────────────────────────────────────────────────┐  │
│  │          Shared Infrastructure (Runs Once)            │  │
│  │  Postgres :5432 → db_main / db_claude / db_codex      │  │
│  │  Redis    :6379 → shared (keys namespaced per env)    │  │
│  │  LocalStack :4566 → shared AWS emulation              │  │
│  └───────────────────────────────────────────────────────┘  │
│                                                             │
│  /my-app      → Web :8000  → db_main                        │
│  /app-claude  → Web :8001  → db_claude                      │
│  /app-codex   → Web :8002  → db_codex                       │
└─────────────────────────────────────────────────────────────┘

Setup steps:

  1. Run the heavy lifting once. Start your shared services from /my-app on a named Docker network.

  2. Create logical databases. Inside the running Postgres container:

    CREATE DATABASE db_claude;
    CREATE DATABASE db_codex;
    
  3. Strip down the worktrees. In each agent's folder, remove Postgres, Redis, and LocalStack from docker-compose.yml entirely — they only need their lightweight web/app containers.

  4. Connect the wires. In each agent's .env, point to the shared containers but use isolated databases where needed:

    DB_HOST=shared_postgres_container_name
    DB_PORT=5432
    DB_DATABASE=db_claude
    
    REDIS_HOST=shared_redis_container_name
    REDIS_PORT=6379
    REDIS_PREFIX=claude_
    
    AWS_ENDPOINT=http://shared_localstack_container_name:4566
    

Summary

flowchart TD
    subgraph BEFORE["❌ Before: git clone"]
        direction LR
        A1["📁 /my-app.git/ — 1GB"]
        A2["📁 /my-app-claude.git/ — 1GB (duplicated)"]
        A3["📁 /my-app-codex.git/ — 1GB (duplicated)"]
        A1 -.->|no local sync| A2
        A1 -.->|no local sync| A3
    end

    BEFORE -->|upgrade to| AFTER

    subgraph AFTER["✅ After: git worktree"]
        direction LR
        B1["📁 /my-app.git/ — 1GB (source of truth)"]
        B2["📁 /my-app-claude.git — 1KB pointer"]
        B3["📁 /my-app-codex.git — 1KB pointer"]
        B2 -->|shared brain| B1
        B3 -->|shared brain| B1
    end

    AFTER -->|enables| AGENTS

    subgraph AGENTS["🤖 Parallel AI Workflow"]
        direction LR
        YOU["👤 You port 8000 · branch: main"]
        CLAUDE["🤖 Claude port 8001 · branch: feature-a"]
        CODEX["🤖 Codex port 8002 · branch: feature-b"]
    end

    subgraph INFRA["🐳 Shared Docker Infrastructure — runs once"]
        PG["🐘 Postgres :5432"]
        RD["⚡ Redis :6379 namespaced per agent"]
        LS["☁️ LocalStack :4566"]
        PG --> M["db_main"]
        PG --> C["db_claude"]
        PG --> X["db_codex"]
    end

    YOU --> M
    YOU --> RD
    YOU --> LS
    CLAUDE --> C
    CLAUDE --> RD
    CLAUDE --> LS
    CODEX --> X
    CODEX --> RD
    CODEX --> LS

Git worktrees are the ultimate unlock for local development. By isolating your physical files while sharing your Git history, you can test complex features side-by-side, run multiple AI agents concurrently, and — with the right Docker architecture — do it all without turning your laptop into a space heater.