Git Worktree Parallelism skill for Claude Code
Several Claude sessions, one repo, zero collisions. Lets you run two to four Claude Code sessions at once without them trampling each other. Claude splits work into tasks with disjoint file scopes, creates a worktree and branch per task, makes each checkout runnable with its own env file, port and database, hands every session a written contract, then rebases and merges in a planned order and removes everything afterwards only with your confirmation.
- name
git-worktree-parallelism - size186 lines · ≈1,950 tokens
- files1
- licenseMIT
- updated
What Claude sees before loading it
This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.
description: Runs several Claude Code sessions in parallel on one repository using git worktrees, with one branch, environment, port, and database per worktree, a written task contract per session, a merge order that avoids conflicts, and safe cleanup. Use when the user wants Claude working on multiple features or bugs at once, to try two approaches side by side, keep a long task running while fixing something else, or clean up stale worktrees and branches. Try asking
- Set up worktrees so Claude can build search and fix the cart bug at the same time
- Try both caching approaches in parallel worktrees and compare them
- Clean up all the old worktrees and merged branches in this repo
Use it when
- Two or more independent tasks could progress at the same time
- You want to compare competing implementations side by side
- A long session is running and an urgent fix comes in
- Stale worktrees and branches have piled up
Skip it when
- The tasks touch the same files or depend on each other — run them sequentially
- You only need isolated read-only research — use subagent-design instead
- Rewriting or repairing commit history — use git-history-surgery instead
How to check the result
Each worktree passes its tests alone, each branch's changed files stay inside its contract scope, and main stays green after every merge.
The common mistake it prevents
Letting parallel worktrees share one dev server port or one database, so tests silently run against the other branch's code or schema.
Parallel sessions pay off only when the tasks are independent at the file level. Done well means: each worktree is a fully working checkout (dependencies, env files, its own port and database), each session has a written scope it stays inside, branches merge back through normal review in a planned order, and nothing is left behind afterwards.
Should this run in parallel?
| Good fit | Poor fit |
|---|---|
| Independent features in different modules | Changes that touch the same files or the same shared types |
| A bugfix while a long feature session continues | A refactor everyone else depends on (do it first, alone) |
| Two competing approaches to compare, one to be discarded | Sequential steps where B needs A’s result |
| Long-running work (migration rehearsal, big test runs) beside normal work | Multiple schema migrations against one database |
Practical ceiling: 2-4 active sessions. Review capacity, not machine capacity, is the bottleneck.
Workflow
- [ ] 1. Split work into tasks with disjoint file scopes; write a contract per task
- [ ] 2. Create one worktree + branch per task from fresh origin/main
- [ ] 3. Make each worktree runnable (deps, env, port, DB)
- [ ] 4. Start one Claude session per worktree with its contract
- [ ] 5. Monitor; keep each session inside its scope
- [ ] 6. Rebase, test, and merge in the planned order
- [ ] 7. Remove worktrees and branches (confirm before forcing anything)
1. Task contract
Give each session a self-contained brief as its first prompt (or a TASK.md that is
gitignored):
Task: Add full-text search to the products API
Branch: feat/product-search Worktree: ../shop-wt/search
In scope: packages/api/src/search/**, packages/api/test/search/**, docs/search.md
Out of scope: packages/db/schema (owned by feat/inventory), any shared UI components
Done when: `pnpm --filter api test` passes, new endpoint documented, no files outside scope changed
Commands: dev `PORT=3101 pnpm --filter api dev`; tests `pnpm --filter api test`
If you need an out-of-scope change: stop and describe it instead of making it.
2. Create worktrees
Prefer a sibling directory so test runners, linters, and file watchers in the main checkout do not crawl the other worktrees.
git fetch origin
git worktree add -b feat/product-search ../shop-wt/search origin/main
git worktree add -b fix/cart-rounding ../shop-wt/cart origin/main
git worktree list
If worktrees must live inside the repo (.worktrees/), add that directory to
.gitignore and to the ignore settings of the test runner, linter, TypeScript
exclude, and bundler.
3. Make each worktree runnable
Untracked files do not come with a new worktree. Check each item:
| Item | Action |
|---|---|
.env, .env.local, local config | Copy from the main checkout (never commit) |
.claude/settings.local.json, CLAUDE.local.md | Copy if the session should share your local permissions/notes |
| Dependencies | Install per worktree (pnpm install --frozen-lockfile; pnpm/uv caches keep it cheap) |
| Dev server port | Unique per worktree (PORT=3101, 3102, …) |
| Database | Separate DB name or schema per worktree; never run two branches’ migrations against one DB |
| Docker Compose | Unique COMPOSE_PROJECT_NAME per worktree so containers and volumes do not collide |
| Submodules | git submodule update --init --recursive in each worktree |
| Generated code | Run codegen in each worktree (pnpm codegen, prisma generate) |
cd ../shop-wt/search
cp ../../shop/.env.local .
pnpm install --frozen-lockfile
createdb shop_search 2>/dev/null; echo "DATABASE_URL=postgres://localhost/shop_search" >> .env.local
pnpm db:migrate && pnpm --filter api test # prove the worktree works before Claude starts
4. Start sessions
- Launch
claudefrom inside each worktree directory, one terminal (or tmux window) per worktree. Each session loads that checkout’s CLAUDE.md and.claude/config. - Session history is keyed to the directory, so
claude --continueand/resumeinside a worktree find that worktree’s sessions. - Recent Claude Code versions can create and manage worktrees themselves; check
claude --helpfor a worktree option before scripting your own. - Add a Notification hook (see
hooks-automation) so you know which session is waiting.
5. Monitor
Status of all worktrees at a glance:
git worktree list --porcelain | awk '/^worktree /{print $2}' | while read -r wt; do
printf '%-36s %-26s %s changed\n' "$wt" "$(git -C "$wt" branch --show-current)" \
"$(git -C "$wt" status --porcelain | wc -l | tr -d ' ')"
done
Scope check for a branch against its contract:
git -C ../shop-wt/search diff --name-only origin/main...HEAD
Any path outside the contract’s scope is a conversation with that session, not something to merge silently.
6. Merge order
-
Merge foundational or smallest changes first (shared types, schema, config).
-
For each remaining branch, in its own worktree:
git fetch origin && git rebase origin/main pnpm install --frozen-lockfile && pnpm test git push --force-with-lease -u origin HEAD # own feature branch only -
Open a PR per branch; review as usual. Never merge worktree branches into each other locally to “save time”.
-
Conflict rules: resolve in the later branch’s worktree; regenerate lockfiles rather than hand-merging them; renumber migrations so they apply in merge order.
-
Comparing two approaches: pick the winner from the diffs and test results, then delete the loser’s worktree and branch.
7. Cleanup
git worktree remove ../shop-wt/search # refuses if there are uncommitted changes - good
git branch -d feat/product-search # -d refuses unmerged branches - good
git worktree prune # clears metadata for directories deleted by hand
dropdb shop_search # per-worktree database, after confirming
git worktree remove --force, git branch -D, and dropping databases destroy work.
Show the user what would be lost (git -C <wt> status, git log origin/main..<branch>)
and get explicit confirmation first.
Gotchas
- A branch can be checked out in only one worktree. Create a new branch per worktree.
- The stash, git config, and
.git/hooksare shared by all worktrees. A stash made in one is visible (and poppable) in another. - Deleting a worktree folder with
rm -rfleaves stale metadata; rungit worktree prune. - Two sessions running dev servers on the default port: the second silently fails or hits the first one’s server, so tests pass against the wrong code.
- Shared database: one branch’s migration breaks the other branch’s tests in confusing ways. Isolate databases.
- Nested worktrees inside the repo get picked up by
jest,tsc,eslint ., and file watchers, doubling test runs and type errors. - Long-lived worktrees drift from main. Rebase daily or keep tasks short.
Verification
git worktree listmatches the plan; each worktree’s tests pass on its own before any merge.- Each branch’s
diff --name-onlystays inside its contract scope. - After each merge, main builds and passes the full suite before the next branch is rebased.
- After cleanup,
git worktree listshows only the main checkout and no merged branches remain locally.
Output
| Worktree | Branch | Scope | Port/DB | Status |
|---|---|---|---|---|
| ../shop-wt/search | feat/product-search | api/src/search/** | 3101 / shop_search | PR #412, green |
| ../shop-wt/cart | fix/cart-rounding | api/src/cart/** | 3102 / shop_cart | merged, removed |
**Merge order:** cart -> search (rebased after cart, tests green)
**Cleanup:** 1 worktree remaining (search, awaiting review); prune run; 0 orphan branches About this skill
Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.