Przejdź do głównej zawartości

Uruchamiaj równoległe agenty w izolowanych worktree

Worktree Gita daje każdemu równoległemu zadaniu agenta osobny katalog i branch, a wszystkie zadania dzielą jedną historię repozytorium. Worktree izoluje tylko pliki. Przy dwóch do czterech równoległych strumieniach potrzebujesz też bloku portów i lokalnego stanu na strumień, allowlisty lokalnej konfiguracji, bramki zaliczanej przez każdy strumień osobno i sprzątania, które zachowuje niewypchniętą pracę.

Ta strona jest dla deweloperów oraz tech leadów, którzy konfigurują repozytoria zespołu, i odpowiada na pytanie Q13 scorecardu. Uruchamiasz trzy agenty w trzech terminalach tego samego checkoutu. Formatter pierwszego przepisuje plik, który edytuje drugi, serwer deweloperski drugiego po cichu zajmuje następny wolny port, a testy end-to-end trzeciego przechodzą na serwerze drugiego. Każdy raport mówi „gotowe”. Żaden nie dowodzi, który kod był testowany.

Pytanie Q13 scorecardu: Jak uruchamiasz równoległe sesje agentów bez kolizji plików?

Dowód na maksymalną ocenę: skrypt, a nie nawyk, tworzy i usuwa dwa do czterech izolowanych strumieni, z których każdy ma jawną rewizję bazową, własne zasoby runtime i własne zaliczone bramki.

  • Natywne polecenie worktree dla Claude Code, Codeksa i Cursora oraz informację, co każde z nich przenosi do nowego checkoutu, a czego nie.
  • Dwa przetestowane skrypty repozytorium: jeden tworzy strumień z blokiem portów i konfiguracją wyłącznie deweloperską, drugi usuwa strumień tylko wtedy, gdy nic nie przepadnie.
  • Procedurę dowodową, która pokazuje, z którego checkoutu korzystał działający serwer i przebieg testów oraz które pliki zmieniły dwa strumienie, bez czytania diffów.
  • Trzy prompty do skopiowania: podział pracy, start strumienia i raport gotowości do review.

Równoległe strumienie się opłacają, gdy zadania są niezależne i każde ma sprawdzenie, które uruchomi maszyna. Kosztują nadzór: każdy strumień kończy się diffem, który ktoś musi zaakceptować, więc limitem jest zwykle twoja przepustowość review, a nie narzędzie. Przy dwóch do czterech strumieniach jeden deweloper wciąż sprawdzi każdy wynik względem jego bramki. Dziesięć i więcej agentów z terminalem nadzorczym i merge trainem opisuje strona dziesięć agentów naraz.

Twoja sytuacjaUruchom jakoDlaczego
Dwie lub trzy poprawki w różnych modułach, każda z nieprzechodzącym testemRównoległe strumienie, jeden worktree na zadanieOsobne pliki, osobne bramki
Jedno trudne zadanie z kilkoma sensownymi projektami rozwiązaniaTo samo zadanie w dwóch worktree; zostaw to z mniejszym zaliczonym diffemPorównanie podejść na tych samych testach
Dwa zadania zmieniające to samo API, schemat lub plik konfiguracjiJeden strumień, po koleiPraca równoległa gwarantuje tu konflikt i drugie review
Poboczne rozpoznanie lub review tylko do odczytuSubagent w jednej sesjiDrugi checkout nie jest potrzebny; zobacz subagenci zakresowi

Szerszy wybór między worktree, agentami w tle, subagentami i skryptowym fan-outem opisuje strona wzorce orkiestracji pracy agentów.

Worktree ma własne pliki robocze, indeks i bieżący branch. Katalog .git (obiekty, refy, git config) dzieli ze wszystkimi innymi worktree repozytorium. Wszystko poza Gitem jest wspólne, dopóki sam tego nie rozdzielisz:

ZasóbOsobny dla worktree?Co się psuje, gdy jest wspólny
Śledzone pliki i branchTakNic: to właśnie rozwiązuje worktree
Pliki ignorowane przez Gita (.env, node_modules/)Brak w nowym worktreeTesty padają na braku konfiguracji albo agent wymyśla wartości
Porty serwera deweloperskiego i testówNieSerwer przechodzi na następny wolny port; testy trafiają w serwer innego strumienia
Lokalna baza, cache, kolejkaNieDwa strumienie migrują lub seedują te same dane
git configNieZapis konfiguracji w jednym worktree zmienia wszystkie
Zgody na uprawnienia w Claude CodeNie„Yes, and don’t ask again” dla polecenia Bash w jednym worktree trafia do .claude/settings.local.json głównego checkoutu i działa wszędzie (Claude Code v2.1.211 i nowsze; w Windowsie reguła zostaje w danym worktree)
Dane produkcyjne, deploye, sekrety, zewnętrzne APINie„Szybkie sprawdzenie” jednego strumienia zapisuje dane na żywo

Wszystkie trzy narzędzia potrafią same utworzyć worktree. Różnią się tym, gdzie go umieszczają, jaki branch mu dają i co kopiują.

Okno terminala
# Terminal, w katalogu głównym repozytorium. Jeden terminal na strumień.
claude --worktree fix-auth # albo: claude -w fix-auth
claude --worktree csv-export --tmux # to samo, otwarte w sesji tmux
claude --worktree "#1234" # worktree .claude/worktrees/pr-1234 na najnowszym commicie pull requesta 1234

Claude Code tworzy worktree w .claude/worktrees/<name>/ na nowym branchu worktree-<name>. Domyślnie odgałęzia się od domyślnego brancha na remote (worktree.baseRef: "fresh"); ustaw "worktree": { "baseRef": "head" } w ustawieniach, żeby startować od bieżącego lokalnego HEAD. Przed pierwszym uruchomieniem:

  • Dodaj .claude/worktrees/ do .gitignore.

  • Utwórz .worktreeinclude w katalogu głównym repozytorium, w składni .gitignore. Claude Code kopiuje tylko pliki, które pasują do wzorca i są ignorowane przez Gita, więc wpisz wyłącznie pliki deweloperskie:

    .env.development
    .env.test

Przy wyjściu Claude Code sprawdza worktree pod kątem zmian i nowych commitów: czysty worktree sesji bez nazwy jest usuwany razem z branchem, a przy worktree z pracą dostajesz pytanie, czy go zachować. Uruchomienia headless claude -p --worktree nie mają pytania przy wyjściu i zostawiają swoje worktree. Własny subagent z isolation: worktree we frontmatterze zawsze działa we własnym tymczasowym worktree. Sprawdzone w claude --help 2.1.283 i w dokumentacji worktree Claude Code 26 września 2026 r. Aplikacja desktopowa ma tę samą opcję dla każdej sesji; zobacz Claude Code Desktop.

Natywne polecenia dają osobny checkout. Nie dają portów, bazy na strumień ani zapisu rewizji bazowej. To zadanie repozytorium.

Maksimum w Q13 wymaga automatyzacji, którą każdy agent i każda osoba z zespołu uruchamia tak samo. Zacommituj dwa skrypty. Pierwszy tworzy strumień z jawnej bazy, przydziela najniższy wolny blok portów (co 10, więc serwer, który przejdzie na następny port, zostaje we własnym bloku), zapisuje blok w ignorowanym przez Gita pliku .wt-env i kopiuje allowlistę plików deweloperskich. Najpierw dodaj .wt-env i każdy plik z allowlisty do .gitignore; w przeciwnym razie wt-rm.sh widzi je jako nieśledzone i odmawia usunięcia każdego strumienia:

#!/usr/bin/env bash
# scripts/wt-new.sh SLUG [BASE]: one agent stream = worktree + branch + port block + local config
set -euo pipefail
slug="${1:?usage: scripts/wt-new.sh SLUG [BASE]}"
base="${2:-origin/main}"
main="$(git worktree list --porcelain | awk 'NR==1 {print $2}')" # the main checkout is listed first
dir="$(dirname "$main")/$(basename "$main")-$slug"
# Lowest index no other worktree holds; index 0 is the main checkout
used="$(git worktree list --porcelain | awk '/^worktree /{print $2}' |
while read -r w; do sed -n 's/^WT_INDEX=//p' "$w/.wt-env" 2>/dev/null || true; done)"
i=1; while grep -qx "$i" <<<"$used"; do i=$((i + 1)); done
git fetch --quiet origin
git worktree add --quiet --no-track -b "agent/$slug" "$dir" "$base" # fails if the branch exists: pick a new slug
cat > "$dir/.wt-env" <<ENV
WT_INDEX=$i
WT_SLUG=$slug
WT_BASE=$(git rev-parse "$base")
APP_PORT=$((3000 + i * 10))
DB_PORT=$((5432 + i * 10))
ENV
for f in .env.development .env.test; do # allowlist: development files only
if [ -f "$main/$f" ]; then cp "$main/$f" "$dir/$f"; fi
done
echo "ready: $dir on agent/$slug from $(git rev-parse --short "$base"), APP_PORT=$((3000 + i * 10))"

Drugi usuwa strumień tylko wtedy, gdy worktree jest czysty, a każdy commit jego brancha istnieje na origin. Uruchamiaj go z głównego checkoutu:

#!/usr/bin/env bash
# scripts/wt-rm.sh SLUG: remove a stream only when nothing would be lost
set -euo pipefail
slug="${1:?usage: scripts/wt-rm.sh SLUG}"
main="$(git worktree list --porcelain | awk 'NR==1 {print $2}')"
dir="$(dirname "$main")/$(basename "$main")-$slug"
if [ -n "$(git -C "$dir" status --porcelain)" ]; then
echo "refusing: uncommitted or untracked files in $dir" >&2; exit 1
fi
git fetch --quiet origin
if [ -n "$(git rev-list "agent/$slug" --not --remotes=origin)" ]; then
echo "refusing: agent/$slug has commits that exist on no origin branch; push them first" >&2; exit 1
fi
git worktree remove "$dir"
git branch -d "agent/$slug" 2>/dev/null || echo "kept branch agent/$slug (not merged; delete it after the PR lands)"

Oba skrypty uruchomiliśmy 26 września 2026 r. na testowym repozytorium: dwa strumienie dostały porty 3010 i 3020, zwolniony indeks został użyty ponownie, a usuwanie odmówiło brancha z niewypchniętym commitem, dopóki go nie wypchnięto. Zastąp origin/main swoim domyślnym branchem, a porty portami swojego stosu, i dopisz po kroku kopiowania instalację zależności, której wymaga twój projekt.

Potem niech narzędzia same czytają ten plik, żeby nikt nie musiał pamiętać o eksporcie. Projekt z Vite i Playwright wyprowadza na przykład każdy URL z jednej wartości i odrzuca port zastępczy:

playwright.config.ts
import { readFileSync } from 'node:fs';
import { defineConfig } from '@playwright/test';
const wtEnv = (() => {
try { return readFileSync('.wt-env', 'utf8'); } catch { return ''; }
})();
const port = /^APP_PORT=(\d+)$/m.exec(wtEnv)?.[1] ?? '5173'; // main checkout keeps the default
const baseURL = `http://localhost:${port}`;
export default defineConfig({
use: { baseURL },
webServer: {
command: `npx vite --port ${port} --strictPort`, // fail instead of moving to another port
url: baseURL,
reuseExistingServer: !process.env.CI,
},
});

Najważniejsze jest powiązanie webServer.url z portem strumienia: przy zaszytym na sztywno URL-u reuseExistingServer podłącza się do tego, co akurat nasłuchuje na porcie, czyli czasem do serwera innego strumienia, i przebieg raportuje zielony wynik dla kodu, którego nigdy nie testował.

Poprowadź dwa do czterech strumieni od podziału do merge’a

Dział zatytułowany „Poprowadź dwa do czterech strumieni od podziału do merge’a”
  1. Podziel pracę i sprawdź niezależność. Wklej prompt planistyczny poniżej do jednej sesji w głównym checkoucie. Zostaw tylko zadania, które zmieniają rozłączne pliki i mają własny nieprzechodzący test lub kryterium akceptacji; resztę uszereguj.

  2. Utwórz jeden strumień na zadanie. Uruchom scripts/wt-new.sh fix-auth, scripts/wt-new.sh csv-export i tak dalej z głównego checkoutu. Rewizja bazowa jest teraz zapisana w każdym .wt-env.

  3. Uruchom jednego agenta na worktree. Otwórz terminal (lub okno Cursora) w każdym katalogu i uruchom tam agenta z promptem strumienia poniżej. W Claude Code możesz zamiast tego użyć claude --worktree NAME, o ile .worktreeinclude i przydział portów pokrywają to, co robi skrypt. Taki strumień działa na branchu worktree-NAME; sprawdzenie nakładania się poniżej obejmuje już branche worktree-*. Taki strumień usuwaj przy wyjściu z sesji albo przez git worktree remove .claude/worktrees/NAME, nie skryptem wt-rm.sh.

  4. Niech każdy strumień oceniają bramki, nie ty. Agent kończy dopiero wtedy, gdy type check, lint i testy projektu przechodzą w jego worktree. Hooki agenta mogą to wymuszać na końcu każdej tury.

  5. Udowodnij każdy strumień przed review. Wykonaj sprawdzenia z następnej sekcji. Strumień, który nie pokaże dowodów, wraca do swojego agenta, a nie do recenzenta.

  6. Integruj po jednym strumieniu. Wypchnij branch poleceniem git push -u origin agent/SLUG, otwórz pull request i pozwól działać CI. Gdy pierwszy pull request zostanie zmergowany, zrób rebase następnego brancha na nowy domyślny branch i uruchom ponownie jego bramki przed merge’em. Kolejka review utrzymuje tę kolejność, gdy robi to kilka osób.

  7. Usuwaj każdy strumień skryptem. scripts/wt-rm.sh fix-auth odmawia usunięcia brudnej lub niewypchniętej pracy. Od czasu do czasu uruchom git worktree prune, żeby usunąć wpisy katalogów worktree skasowanych ręcznie.

Poproś o dowody wytworzone przez maszynę, a potem czytaj tylko to, co one wskażą. Cztery sprawdzenia pokrywają sposoby, w jakie równoległe strumienie wprowadzają w błąd:

PytanieSprawdzenie (w terminalu)Zaliczone, gdy
Czy strumień wystartował tam, gdzie myślisz?git -C ../myapp-csv-export merge-base HEAD origin/main porównane z WT_BASE w .wt-envBaza to zapisana rewizja albo późniejsza, na którą świadomie zrobiono rebase
Czy bramki działały w tym checkoucie?Raport agenta wymienia każde polecenie z kodem wyjścia; sam uruchom ponownie polecenie testów w tym kataloguKażdy kod wyjścia to 0, a twój przebieg daje to samo
Czy działający serwer należy do tego checkoutu?. ../myapp-csv-export/.wt-env; lsof -a -d cwd -p "$(lsof -tiTCP:"$APP_PORT" -sTCP:LISTEN | paste -sd, -)"Pokazany cwd to katalog tego strumienia
Czy dwa strumienie zmieniły te same pliki?Sprawdzenie nakładania się poniżej, z głównego checkoutuNic nie wypisuje
Okno terminala
# Files changed by two or more stream branches since they left main
# (agent/* from the script, worktree-* from claude --worktree)
for b in $(git for-each-ref --format='%(refname:short)' refs/heads/agent/ 'refs/heads/worktree-*'); do
git diff --name-only "origin/main...$b"
done | sort | uniq -d

Każdy wypisany plik oznacza, że dwa strumienie zmieniły ten sam plik. Zatrzymaj jeden z nich, zmerguj drugi, a przed wznowieniem zatrzymanego strumienia zrób rebase jego brancha na nowy domyślny branch. Przed pull requestem poproś każdego agenta o raport gotowości poniżej i dołącz go; pull request niesie wtedy własny dowód, jak w pakiecie dowodów. Kto zatwierdza, zostaje bez zmian względem pracy ludzi: recenzent wskazany przez twoje warstwowe review pull requestów, który ocenia dowody i pliki, które one wskazują.

Co się psuje przy agentach w równoległych worktree?

Dział zatytułowany „Co się psuje przy agentach w równoległych worktree?”

Testy przechodzą na serwerze innego strumienia. Serwer deweloperski przeszedł na wolny port albo reuseExistingServer podłączył się do sąsiada. Wyjście: zatrzymaj wszystkie serwery deweloperskie, dodaj --strictPort (lub odpowiednik w twoim frameworku), wyprowadź URL testów z .wt-env i ponownie uruchom bramki strumienia. Każdy wcześniejszy zielony przebieg tego strumienia traktuj jako niedowiedziony.

Nowy worktree się nie buduje. Pliki ignorowane przez Gita i zależności nie istnieją w świeżym checkoucie. Wyjście: dodaj plik do .worktreeinclude lub allowlisty skryptu i zainstaluj zależności w worktree. Nigdy nie poszerzaj allowlisty o pliki produkcyjne, żeby „zadziałało”.

Commity Codeksa znikają po sprzątaniu. Commity zrobione na odłączonym HEAD nie należą do żadnego brancha. Wyjście: przed usunięciem worktree uruchom git -C DIR reflog -5, a potem z głównego checkoutu git branch rescue/csv-export SHA. Zapobiega temu linia git switch -c w prompcie strumienia.

Git zgłasza, że branch jest już używany w innym worktree. Git nie pozwala mieć tego samego brancha wybranego (checkout) w dwóch worktree naraz. Wyjście: uruchom git worktree list, żeby znaleźć właściciela; jeśli jego katalog skasowano ręcznie, uruchom git worktree prune i spróbuj ponownie.

Worktree nie daje się usunąć. Uruchomienia headless claude -p --worktree nie mają pytania przy wyjściu i zostawiają swój worktree oraz blokadę, którą Claude Code na nim założył (blokadę zwalnia też przegląd nieaktualnych blokad przy kolejnej sesji Claude Code). Wyjście: potwierdź przez git -C .claude/worktrees/NAME status, że nie ma nic do zachowania (commity, które chcesz zachować, najpierw wypchnij), potem uruchom git worktree unlock .claude/worktrees/NAME, git worktree remove .claude/worktrees/NAME i git branch -d worktree-NAME. Strumień utworzony skryptem usuwaj przez scripts/wt-rm.sh SLUG.

Zgoda udzielona w jednym strumieniu działa we wszystkich. Claude Code zapisuje reguły „don’t ask again” w .claude/settings.local.json głównego checkoutu. Wyjście: po sesji równoległej przejrzyj ten plik, a reguły, które chcesz zachować, przenieś do commitowanego .claude/settings.json.

Dwa strumienie zmieniły ten sam kontrakt. Niezależne testy przechodzą, ale wynik po merge’u już nie. Wyjście: zmerguj jeden, zrób rebase drugiego, uruchom ponownie jego pełną bramkę, a następnym razem dopisz ten kontrakt do listy „must run in sequence” w prompcie planistycznym.

Worktree należą do etapu Build w cyklu życia AI-native; mapa narzędzi porównuje funkcje równoległości w poszczególnych narzędziach. Poprzedni playbook harnessu to subagenci zakresowi, a następne pytanie scorecardu, Q14, to pętla zwrotna dla sesji. Wszystkie playbooki znajdziesz w przewodniku po scorecardzie dewelopera.