Przejdź do głównej zawartości

Operacje wsadowe: jedna zmiana w setkach plików

Operacje wsadowe w Claude Code wprowadzają jedną zmianę, na przykład migrację biblioteki, zmianę nazwy albo usunięcie wersji API, w dziesiątkach lub setkach plików. Wbudowany skill /batch planuje zmianę, dzieli ją na 5–30 niezależnych jednostek i uruchamia każdą w osobnym worktree Gita jako agenta w tle, który otwiera pull request.

Ta strona jest dla programistów, którzy odpowiadają za szeroką zmianę, i dla tech leadów, którzy muszą potem scalić jej wynik. Sytuacja: zespół przechodzi z moment.js na date-fns, moment importuje 147 plików, a każdy korzysta z innego wycinka API. „Znajdź i zamień” nie zadziała, bo moment().format('YYYY-MM-DD') zamienia się w format(new Date(), 'yyyy-MM-dd'), a nikt nie chce czytać 147 diffów linijka po linijce.

Wszystko poniżej sprawdzono 2026-09-26 na Claude Code v2.1.283 (kanał latest).

  • Tabelę decyzyjną: jedna sesja, /batch, skrypt claude -p czy dynamiczny workflow, zanim wydasz pierwsze tokeny.
  • Prompt, w którym Claude pisze codemod do przejrzenia w 30 liniach zamiast 300 zmienionych plików.
  • Prompt „najpierw plan”, który zwraca tabelę migracji plik po pliku do zatwierdzenia, zanim cokolwiek się zmieni.
  • Prompt /batch, który wnosi własną procedurę weryfikacji do każdego wykonawcy.
  • Pętlę headless z limitem wydatków, wąską listą dozwolonych narzędzi i testami, których agent nie może edytować.
  • Skrypt weryfikacyjny, który dowodzi zakresu, kompletności i zachowania bez czytania każdego diffu.
  • Sposoby wyjścia z konfliktów między jednostkami, osłabionych testów, zatrzymań na budżecie i przebiegów bez pull requesta.

Wybieraj według tego, jak niezależne są części zmiany, a nie tylko według liczby plików.

PodejścieKiedy go użyćCo dostajeszGdzie działa weryfikacja
Jedna sesja: plan, potem wykonanieMniej niż około 20 plików albo edycje, które muszą wejść w kolejności zależnościJedną gałąź, przeglądaną partia po partiiTesty, które Claude uruchamia po każdej partii
/batchZmiana dzieli się na niezależne jednostki, każdą do scalenia osobno5–30 pull requestów, po jednym na jednostkęW każdym wykonawcy, potem w CI na każdym PR
Pętla claude -pPowtarzasz tę samą zmianę per katalog, pakiet lub repozytorium albo uruchamiasz ją z CIWyniki JSON z każdego przebiegu i commity, które robisz samW twoim skrypcie, poza agentem
Dynamiczny workflowAudyty lub zmiany wymagające dziesiątek do setek agentów i skryptu do ponownego uruchomieniaZapisany workflow i jego raportW fazie weryfikacji samego workflow
Codemod napisany przez agentaPrzekształcenie jest czysto składniowe (ścieżka importu, nowa nazwa symbolu)Deterministyczny skrypt do ponownego uruchomieniaW próbnym przebiegu codemodu i w twoich testach

Ostatni wiersz zespoły najczęściej pomijają. Gdy każde miejsce wywołania zmienia się tak samo, poproś Claude o regułę ast-grep albo transformację jscodeshift i przejrzyj 30 linii transformacji zamiast 300 zmienionych plików. Oba narzędzia uruchomisz przez npx bez instalacji w projekcie: npx -p @ast-grep/cli ast-grep oraz npx jscodeshift, który ma flagę --dry. Pakiet ast-grep dostarcza pliki wykonywalne o nazwach ast-grep i sg, więc samo npx @ast-grep/cli kończy się błędem „could not determine executable to run” (sprawdzone 2026-09-26 na @ast-grep/cli 0.45.3 i jscodeshift 17.4.0). Edycje agenta zostaw dla miejsc, których codemod nie wyrazi.

Zaplanuj zmianę, zanim agent dotknie pierwszego pliku

Dział zatytułowany „Zaplanuj zmianę, zanim agent dotknie pierwszego pliku”

Każde podejście zaczyna się tak samo: od pełnej inwentaryzacji, którą zatwierdzasz. Uruchom sesję w trybie planowania (/plan albo Shift+Tab, aż wskaźnik trybu pokaże plan), żeby Claude mógł czytać i szukać, ale nie edytować.

  1. Zinwentaryzuj każde miejsce wywołania. Wklej poniższy prompt. Claude przeszukuje kod i zwraca jeden wiersz na plik.

  2. Czytaj oznaczone wiersze, nie wszystkie. Wiersze oznaczone jako NO DIRECT EQUIVALENT (brak bezpośredniego odpowiednika) to miejsca, w których migracja może zmienić zachowanie. Każde rozstrzygnij sam: zostaw shim, przepisz ręcznie albo zaakceptuj zmianę zachowania i ją zapisz.

  3. Najpierw wprowadź wspólne warunki wstępne. Dodaj date-fns do package.json, utwórz wspólne helpery, na przykład src/lib/dates.ts, i scal to jako osobny, mały pull request. Bez tego każda jednostka doda zależność osobno, a pull requesty wejdą w konflikt na lockfile.

  4. Utrwal obecne zachowanie w testach. Tam, gdzie pokrycie jest słabe, dodaj testy charakteryzacyjne, które zapisują dzisiejszy wynik, zanim ruszy jakakolwiek jednostka. Te testy są wyrocznią dla całej migracji.

  5. Wybierz sposób wykonania z tabeli powyżej i przekaż zatwierdzoną tabelę jako plan.

/batch to wbudowany skill, który możesz uruchomić tylko ty: Claude nie wywołuje go sam (sprawdzone w v2.1.283). Wpisz /batch i po nim polecenie. Skill działa w trzech fazach.

  1. Rozpoznanie i plan, w trybie planowania. Subagenci badawczy znajdują każdy plik i każde miejsce wywołania. Claude dzieli pracę na 5–30 samodzielnych jednostek, najchętniej po jednej na katalog lub moduł, i pisze procedurę testu end-to-end, którą każdy wykonawca uruchomi sam. Jeśli jej nie znajdzie, pyta cię, jak zweryfikować zmianę. Zatwierdzasz plan, zanim cokolwiek ruszy.
  2. Uruchomienie wykonawców. Jeden agent w tle na jednostkę, każdy w odizolowanym worktree Gita. Każdy wykonawca wdraża swoją jednostkę, uruchamia skill /code-review i poprawia znalezione błędy, uruchamia testy i procedurę end-to-end, po czym robi commit, push i otwiera pull request przez gh pr create.
  3. Śledzenie postępu. Claude prowadzi tabelę statusów ze stanem każdej jednostki i linkiem do jej pull requesta, a na koniec podaje jednolinijkowe podsumowanie: ile jednostek trafiło do pull requestów.

Przed uruchomieniem sprawdź trzy warunki. Katalog musi być repozytorium Gita (tryb worktree bez niego nie działa, chyba że skonfigurujesz hooki WorktreeCreate). GitHub CLI musi być zainstalowane i zalogowane z prawem do push; bez tego wykonawcy kończą pracę, ale nie otwierają pull requesta. Polecenie testów musi być łatwe do znalezienia, najlepiej zapisane w CLAUDE.md, bo szuka go każdy wykonawca.

Najważniejsza jest ostatnia reguła. Wbudowane instrukcje wykonawcy każą mu naprawiać oblewane testy (sprawdzone w v2.1.283), więc bez tej linii wykonawca może przepisać oczekiwany wynik. Wykonawca, który może edytować oblewany test, prędzej czy później „naprawi” go właśnie w ten sposób. Prompt tego zabrania, a skrypt weryfikacyjny poniżej to wykrywa. Jeśli chcesz twardej blokady, dodaj do .claude/settings.json regułę Edit typu deny dla plików testów, tak jak opisuje ochrona wyroczni.

Dla tech leada /batch zamienia jedną zmianę w nawet 30 pull requestów naraz. Przed uruchomieniem ustalcie, kto je scala i w jakiej kolejności, i upewnij się, że CI uruchamia pełny zestaw testów na każdym z nich. Jak rozłożyć to obciążenie, opisuje przewodnik po kolejce review.

Pętla w trybie print pasuje wtedy, gdy powtarzasz tę samą zmianę w wielu pakietach lub repozytoriach albo gdy musi działać w CI. Rozstrzygające sprawdzenia uruchamia skrypt, nie agent, i skrypt zatrzymuje się na pierwszym błędzie.

#!/usr/bin/env bash
# migrate-moment.sh: run in the terminal from the repo root, on a fresh branch
set -euo pipefail
results=$(mktemp -d) # keep run logs out of the repo, or git add would commit them
for dir in src/utils src/components src/api src/services; do
out="$results/$(echo "$dir" | tr / _).json"
claude -p "Migrate every moment import in $dir/ to date-fns, following the \
approved plan in docs/migration/moment-to-date-fns.md. Touch only files under $dir/. \
When done, run npx tsc --noEmit and npx jest $dir --ci and report the results." \
--permission-mode acceptEdits \
--allowedTools "Bash(npx tsc *)" "Bash(npx jest *)" \
--disallowedTools "Edit(**/*.test.ts)" \
--permission-prompts none \
--max-budget-usd 5 \
--output-format json > "$out" || true
status=$(jq -r '.subtype // "missing"' "$out")
if [ "$status" != "success" ]; then
echo "Stopped at $dir: $status"; exit 1
fi
# The script, not the agent, decides whether the batch is good.
if git status --porcelain | grep -Ev " $dir/"; then
echo "Changes outside $dir"; exit 1
fi
if git status --porcelain -- "$dir" | grep -E '\.test\.ts$|__snapshots__/'; then
echo "Test files changed in $dir"; exit 1
fi
npx tsc --noEmit
npx jest "$dir" --ci
git add -- "$dir" && git commit -m "refactor($dir): migrate moment to date-fns"
done
echo "Run logs: $results"

Co robi każda flaga według claude --help w v2.1.283:

  • --permission-mode acceptEdits pozwala Claude edytować pliki bez pytania. Tryb print nie startuje w trybie auto, więc bez tej flagi każda edycja czekałaby na zgodę, której nikt nie udzieli.
  • --allowedTools z góry zatwierdza tylko sprawdzanie typów i uruchamianie testów. --disallowedTools "Edit(**/*.test.ts)" trzyma wyrocznię poza zasięgiem agenta.
  • --permission-prompts none odrzuca wszystko, co w innym razie wymagałoby zgody, zamiast czekać.
  • --max-budget-usd 5 zatrzymuje przebieg, który wymknął się spod kontroli. Wynik JSON ma wtedy podtyp error_max_budget_usd zamiast success, co wyłapuje sprawdzenie jq.

Reguła deny obejmuje narzędzia Claude do edycji plików, a nie każdy sposób, w jaki proces może zapisać plik. Dlatego skrypt sam sprawdza drzewo robocze: każda zmiana poza $dir albo w teście lub snapshocie zatrzymuje pętlę przed commitem.

Ten sam wzorzec obsługuje większość szerokich zmian. Zmienia się tylko sprawdzenie kompletności, czyli polecenie, które dowodzi, że niczego nie pominięto:

ZmianaSprawdzenie kompletności
Migracja bibliotekigit grep starego importu nic nie zwraca
Zmiana nazwy klasy lub moduługit grep -w OldName nic nie zwraca, a npx tsc --noEmit przechodzi
Przeniesienie kataloguKażdy import się rozwiązuje (npx tsc --noEmit), a starej ścieżki nie ma w żadnym pliku konfiguracyjnym
Usunięcie wersji APIKażda usunięta trasa miała następcę, a żądania do starych tras kończą się błędem w testach integracyjnych
Dodanie szablonu do każdego handleraReguła lintera albo git grep -L nie wskazuje żadnego handlera bez niego

Jak zweryfikować zmianę wsadową bez czytania każdego diffu?

Dział zatytułowany „Jak zweryfikować zmianę wsadową bez czytania każdego diffu?”

Przy 150 plikach przegląd linijka po linijce przestaje być uczciwy. Zastąp czytanie sprawdzeniami, które kończą się wyraźnym błędem, i czytaj tylko tam, gdzie one wskażą.

  1. Zakres: każdy zmieniony plik leży w katalogach wskazanych w planie.
  2. Kompletność: stary wzorzec nie występuje nigdzie.
  3. Nienaruszona wyrocznia: żaden plik testów nie zmienił się w tej samej jednostce, co kod.
  4. Zachowanie: sprawdzanie typów, testy jednostkowe i testy charakteryzacyjne przechodzą, a CI uruchamia pełny zestaw na każdym pull requeście.
  5. Czytanie celowane: czytasz tylko miejsca oznaczone jako NO DIRECT EQUIVALENT i pliki wskazane przez sprawdzenia.

Uruchom ten skrypt na gałęzi każdej jednostki, lokalnie albo jako zadanie CI, z katalogami jednostki jako argumentami (./verify-batch.sh src/utils albo ./verify-batch.sh src/utils src/reports dla jednostki obejmującej dwa katalogi):

#!/usr/bin/env bash
# verify-batch.sh DIR [DIR...]: run from the repo root on the unit's branch
set -euo pipefail
[ $# -gt 0 ] || { echo "usage: verify-batch.sh src/utils [src/other ...]"; exit 2; }
UNIT_DIRS=("$@")
BASE=${BASE:-origin/main}
changed=$(git diff --name-only "$BASE"...HEAD)
# 1. Scope: nothing outside this unit's directories changed
pattern="^($(IFS='|'; echo "${UNIT_DIRS[*]}"))/"
outside=$(echo "$changed" | grep -vE "$pattern" || true)
[ -z "$outside" ] || { echo "Out of scope:"; echo "$outside"; exit 1; }
# 2. Completeness: no moment import is left in this unit
if git grep -nE "from ['\"]moment['\"]|require\(['\"]moment['\"]\)" -- "${UNIT_DIRS[@]}"; then
echo "moment is still imported in ${UNIT_DIRS[*]}"; exit 1
fi
# 3. Oracle intact: no test or snapshot changed
if echo "$changed" | grep -E '\.test\.ts$|__snapshots__/'; then
echo "Test files changed: review these by hand before merging"; exit 1
fi
# 4. Behaviour: the whole suite, not only this unit's tests
npx tsc --noEmit
npx jest --ci

Sprawdzenie kompletności celowo obejmuje tylko jednostkę. Na gałęzi jednostki pozostałe katalogi nadal importują moment, więc git grep po całym repozytorium oblałby każdą jednostkę. Wersję dla całego repozytorium uruchom raz na main, po scaleniu ostatniej jednostki: pusty wynik git grep -nE "from ['\"]moment['\"]" -- src oznacza, że migracja jest skończona, i dopiero wtedy usuwasz moment z package.json. Jednostki z miejscami NO DIRECT EQUIVALENT mogą obejmować kilka katalogów: przekaż skryptowi każdy katalog, który plan przypisuje tej jednostce, a ich diffy i tak przeczytaj.

Podział odpowiedzialności jest prosty. Programista, który uruchomił partię, zatwierdza tabelę planu i oznaczone wiersze. CI odpowiada za zielone sprawdzenia na każdej jednostce. Recenzent każdego pull requesta czyta oznaczone miejsca wywołań i wynik sprawdzeń, a nie cały diff. Jak wzmocnić sprawdzanie typów i testy jako bramki, opisują strony testowanie z Claude Code i funkcje dopasowania architektury.

Co psuje się w operacji wsadowej i jak z tego wyjść?

Dział zatytułowany „Co psuje się w operacji wsadowej i jak z tego wyjść?”

Objaw: kilka pierwszych pull requestów z /batch się scala, a reszta ma konflikty na pliku barrel, konfiguracji routera albo lockfile. Przyczyna: jednostki nie były niezależne, bo wspólny plik należał do kilku z nich. Wyjście: zamknij konfliktowe pull requesty, przenieś wspólny plik do osobnego, pierwszego pull requesta, scal go i uruchom /batch ponownie z zaktualizowanej gałęzi main dla pozostałych katalogów. Zapobiega temu punkt 5 promptu inwentaryzacyjnego.

Wykonawca kończy pracę, ale nie otwiera pull requesta

Dział zatytułowany „Wykonawca kończy pracę, ale nie otwiera pull requesta”

Objaw: tabela statusów pokazuje jednostkę jako gotową bez linku, a wynik wykonawcy brzmi PR: none z podaniem przyczyny. Przyczyna: zwykle brak GitHub CLI, brak logowania albo odrzucony push. Wyjście: napraw gh auth status, wypchnij gałąź z worktree wykonawcy i otwórz pull request ręcznie. Kod jest tam już zacommitowany.

Objaw: zielona jednostka, której diff dotyka plików *.test.ts albo snapshotów. Przyczyna: wykonawca trafił na oblany test i „poprawił” oczekiwanie. Wyjście: cofnij zmiany w testach, uruchom je ponownie i każde niepowodzenie traktuj jako prawdziwą różnicę w zachowaniu do rozstrzygnięcia. Zapobiegają temu reguła deny dla Edit i sprawdzenie 3 w skrypcie weryfikacyjnym.

Objaw: sprawdzenie zakresu wymienia pliki w src/core/ albo w konfiguracji. Przyczyna: agent szedł za błędem typów coraz dalej. Wyjście: cofnij te pliki, a zależność dodaj do planu jako osobną jednostkę albo warunek wstępny. Edycje poza zakresem zwykle znaczą, że plan przeoczył wspólny plik.

Objaw: w długiej sesji obejmującej dziesiątki plików odpowiedzi stają się mgliste, a wcześniejsze decyzje giną. Wyjście: zacommituj to, co przechodzi, wykonaj /clear i zacznij od tabeli planu z ukończonymi katalogami oznaczonymi jako gotowe. Powyżej około 20 plików przejdź na /batch albo własnych subagentów, z których każdy ma własne okno kontekstu.

Objaw: pętla kończy się z error_max_budget_usd. Przyczyna: katalog był większy lub trudniejszy od pozostałych. Wyjście: podziel ten katalog na liście w pętli i uruchom ją od niego; katalogi już zacommitowane pozostają gotowe. Jak śledzić koszt przebiegów, opisuje kontrola kosztów.

Objaw: te same dwa lub trzy pliki na zmianę oblewają i przechodzą. Przyczyna: kolejność zależności, którą plan pominął. Wyjście: zatrzymaj przebieg, poproś w trybie planowania o kolejność zależności i wykonaj te pliki jako jedną sekwencyjną partię, zanim rozdzielisz resztę.

  • Przepływy wieloplikowe obejmują skoordynowane zmiany, w których pliki zależą od siebie, czyli przypadek, do którego /batch nie służy.
  • Migracje baz danych i kodu stosują to samo podejście „najpierw plan” do schematów i aktualizacji frameworków.
  • Dynamiczne workflow przejmują zadania, które wymagają dziesiątek do setek agentów i skryptu uruchamianego ponownie.
  • Agent view pokazuje agentów w tle na jednym ekranie, gdy działa /batch.
  • Automatyzacja review stawia automatycznego recenzenta przy pull requeście każdej jednostki.
  • Zmiany masowe w Codex to siostrzana strona o zadaniach w chmurze i worktree w Codex.