JavaRush /Курси /Claude code /Worktree workstreams: запуск і cleanup

Worktree workstreams: запуск і cleanup

Claude code
Рівень 16 , Лекція 0
Відкрита

1. Паралельність не прискорює — вона підсилює

Коли розробник уперше дізнається про паралельні треки, їх дуже хочеться перетворити на універсальний прискорювач: «Зараз запущу три сесії, чотири гілки і, якщо пощастить, до вечора в мене буде готовий продукт, а якщо не пощастить — дуже цікава автобіографія». Паралельність — підсилювач. Добре нарізали задачу — заощаджуєте час. Погано — швидше виробляєте хаос.

Якщо розібратися, що взагалі таке паралельний трек: workstream — окремий трек зі своєю метою, гілкою, worktree, сесією та зрозумілим фіналом. Ключове слово — незалежний. Не можете в одному абзаці сказати, що має вийти, які файли чіпати і за яким сигналом робота завершена, — задачу ще зарано виносити в потік.

Щоб це не звучало абстрактно, подивімося, як виглядає хороший кандидат для окремого треку в нашому Commerce OS: «Винести розрахунок підсумкової суми checkout в окремий сервіс усередині src/checkout/*, не чіпаючи payments і orders, завершити, коли цільові тести зелені й diff лишається компактним». Поганий: «Розібратися, чому іноді ламається замовлення, знижка, податки і взагалі щось дивне в оплаті». Друге — клубок невідомості: розплутайте його в одній основній сесії, а потім діліть.

Паралельність не зменшує невизначеність. Вона робить її дорожчою.

Щоб тримати це в голові, зручно дивитися на життєвий цикл треку як на короткий інженерний конвеєр:

flowchart TD
    A[Задача] --> B[Контракт треку]
    B --> C[Гілка + worktree]
    C --> D[Ізольована сесія]
    D --> E[Diff + перевірки]
    E --> F{Рішення}
    F -->|Прийняти| G[Merge]
    F -->|Взяти частину| H[Cherry-pick]
    F -->|Відхилити| I[Cleanup]
    G --> J[Запис у лог]
    H --> J
    I --> J

Якщо якогось вузла в цьому ланцюжку у вас немає — наприклад, немає явного рішення наприкінці або немає перевірок посередині, — це вже не керований трек, а надія на краще. Надія, звісно, іноді корисна, але Git її не індексує.

2. Чотири рівні не можна змішувати

Найчастіша причина плутанини в паралельній роботі — змішування рівнів. Людина каже «у мене є гілка», а насправді має на увазі сесію Claude. Або каже «агент усе зробив», а потім з’ясовується, що в Git взагалі порожньо. Щоб не потрапляти в такі пастки, корисно чітко розділяти чотири рівні: session, worktree, Git і human.

Зручно думати про них як про окремі ролі в одній інженерній сцені. Сесія або агент виконує задачу. worktree ізолює файли. Git зберігає історію та дає змогу порівнювати стани. Людина ухвалює рішення й відповідає за кінцевий компроміс. Щойно ви починаєте чекати від одного рівня роботу іншого, починається цирк із багами та червоними очима.

Рівень За що відповідає Чого не робить
Сесія / агент Виконує конкретну роботу, збирає контекст, змінює код або аналізує Не зберігає офіційну історію проєкту
worktree Дає окрему папку та файлову ізоляцію для треку Не замінює Git і не ухвалює рішення
Git Показує diff, зберігає коміти, допомагає з merge і rollback Не знає, чи добре у вас архітектурне рішення
Людина Затверджує план, читає diff, вирішує merge / reject / split Не повинна вручну здогадатися про все без артефактів і критеріїв

Хороша робоча аналогія виглядає так: гілка — сюжетна лінія, worktree — окремий стіл у майстерні, сесія — розмова біля цього столу, а людина — редактор, який вирішує, чи ввійде сцена у фінальну версію. Якщо ви посадили двох редакторів за один стіл з одним і тим самим текстом, не дивуйтеся, що потім ніхто не розуміє, хто саме викреслив половину сторінки.

На практиці звідси випливає дуже проста дисципліна. Якщо ви хочете, щоб другий трек справді був окремим, створюйте для нього окрему папку через worktree і запускайте окрему Claude-сесію саме в цій папці. Не треба тримати одну сесію на main, другу — «думками в сусідньому світі», а третю — у режимі «я все пам’ятаю». Пам’ять розробника — річ шляхетна, але в п’ятницю після обіду вона працює як кеш із довільною політикою витіснення.

3. Контракт треку до першого коміту

Перш ніж піднімати новий worktree, корисно зафіксувати дуже маленький документ з відповіддю на питання: що взагалі має робити цей трек. Це не величезна специфікація і не дипломна робота. Це короткий контракт треку. У Workflow Kit такий шаблон зручно зберігати поруч із handoff notes і review-шаблонами, щоб команда щоразу не вигадувала одні й ті самі формулювання.

Ось мінімальний варіант такого контракту:

# track-checkout-refactor.md

Мета: винести розрахунок підсумкової суми checkout в окремий сервіс
Worktree: ../commerce-os.checkout-flow
Входить у scope: src/checkout/*, tests/checkout/*
Не входить: src/payments/*, src/orders/*
Стоп-умова: Checkout-тести зелені, diff до 300 рядків

Тут немає нічого «розумного», і саме в цьому його сила. Цей текст можна відкрити за десять секунд і зрозуміти, що саме дозволено треку, а що заборонено. Якщо пізніше трек раптом починає змінювати src/payments/*, ви не сперечаєтеся з агентом філософськи й не гадаєте: «можливо, так теж нормально». Ви просто бачите, що трек вийшов за межі.

Особливо важливі два рядки: не входить і стоп-умова. Перший захищає від доброго, але небезпечного «раз я вже тут був, я ще трішки поліпшив архітектуру». Другий захищає від безкінечного життя гілки. Трек без стоп-умови — це серіал, який давно треба було закрити, але сценаристи все ще сподіваються на новий сезон.

Для початківця тут правило просте: якщо ви не можете написати рядок «не входить у scope», не запускайте паралельний трек. Отже, ви ще не відокремили задачу від навколишнього туману.

4. Worktree без магії

Слово worktree іноді звучить так, ніби ми зараз будемо вирощувати новий Git із бруньки старого Git. Насправді все значно прозаїчніше й корисніше: worktree створює ще одну робочу директорію для того самого репозиторію, зазвичай на іншій гілці. Це не повна копія проєкту і не окремий .git-світ. Історія та об’єкти в репозиторії спільні, а файли на диску — окремі. Тому ви можете одночасно тримати main в одній папці, а ризикований рефакторинг — в іншій.

Якщо гілки ще немає, зручно створювати її прямо в момент додавання worktree:

git worktree add -b feature/checkout-refactor ../commerce-os.checkout-flow
cd ../commerce-os.checkout-flow
git status
# На гілці feature/checkout-refactor
# нічого комітити, робоче дерево чисте

Якщо гілка вже існує, команда буде трохи коротшою: ви просто додаєте нову папку й прив’язуєте її до вже готової гілки. Для першого знайомства варіант із -b простіший, оскільки робить усе одразу й не змушує тримати в голові зайву розвилку.

Після цього корисно відразу подивитися, які worktree у вас уже існують:

git worktree list
# /repo/commerce-os                  abcd123 [main]
# /repo/commerce-os.checkout-flow    abcd123 [feature/checkout-refactor]

Цей вивід добре протвережує. Ви буквально бачите, що тепер у вас дві робочі директорії: одна живе на main, друга — на новій гілці. Проєкт той самий, але бійки за одні й ті самі файли в одній папці більше немає. Це особливо приємно, коли ви працюєте не самі на самі з кодом, а разом з агентом або окремою Claude-сесією. Запускаєте її з нової директорії — і отримуєте справді ізольований трек, а не «ну я просто зараз акуратно не переплутаю».

Якщо у вас у Claude є окрема панель активних сесій або агентів, використовуйте її, щоб спостерігати за запущеними треками. Назва цього інтерфейсу може відрізнятися від версії до версії. Але навіть якщо інтерфейс дуже красивий і впевнений у собі, джерело істини все одно залишається тим самим: папка worktree, Git-стан і тести.

5. Моніторинг за сигналами, а не за тоном

Коли трек уже запущено, з’являється нова спокуса: стежити за ним за повідомленнями сесії. Агент пише «завершив» — і ви видихаєте. Агент пише «майже готово» — і ви теж видихаєте, але вже трохи тривожніше. Проблема в тому, що впевнений тон не є метрикою прогресу. Для моніторингу потрібні перевірювані сигнали, і вони, на щастя, доволі нудні. А нудне в інженерії часто означає надійне.

Перший сигнал — стан гілки: чи є зміни, скільки їх, закомічені вони чи ні. Другий — розмір diff. Він не доводить якість, але швидко показує, чи не перетворився «маленький рефакторинг checkout» на роман-епопею на півпроєкту. Третій — цільові тести. Четвертий — короткий запис у логу треку: що вже перевірили і до чого зараз дійшли.

Якщо ви сидите в основній папці проєкту, а паралельний трек живе в сусідній, дуже зручний ключ -C, який дає змогу виконувати Git-команди одразу в потрібній директорії:

git -C ../commerce-os.checkout-flow status --short    # порожньо => робоче дерево чисте
git -C ../commerce-os.checkout-flow diff --stat       # дивимося поточний diff
( cd ../commerce-os.checkout-flow && ./gradlew test --tests "*Checkout*" )
# BUILD SUCCESSFUL

Цей набір виглядає майже надто простим, щоб бути корисним, але саме в цьому його краса. Ви не питаєте «ну як там?», ви дивитеся на стан файлів і на результат перевірки. Якщо diff несподівано зріс із 40 рядків до 700, це сигнал. Якщо тести зелені, це інший сигнал. Якщо status --short порожній, а сесія розповідає, що «багато вже зроблено», значить, або все вже закомічено, або поки що нічого немає, і тоді треба перевірити git log.

Трохи докладніше можна подивитися набір комітів, яких ще немає в main:

git -C ../commerce-os.checkout-flow log --oneline main..HEAD
# 3fa12bc винесено розрахунок знижки в CheckoutTotalService
# a20b6de оновлено тести checkout

Такий моніторинг особливо корисний, коли ви ведете кілька треків одразу. Інакше за годину починається гра «а де був той хороший diff, який начебто вже хтось зробив». У певний момент розробка починає нагадувати серіал про детективів, а це поганий знак.

6. Рішення по треку: accept, reject, split

Найважливіший момент у паралельній роботі — не запуск, а фінальне рішення. Трек має завершуватися не фразою «треба потім подивитися», а явним результатом. В інженерній реальності у вас зазвичай є чотири нормальні варіанти: прийняти, взяти частину, розділити або відхилити. Іноді ще потрібен revert, якщо помилку виявили вже після вливання, але це вже виправлення запізнілого рішення, а не базовий сценарій.

Зручно тримати перед очима коротку таблицю:

Рішення Коли підходить Що це означає
Прийняти Scope дотримано, diff зрозумілий, перевірки зелені Трек можна злити цілком
Взяти частину Усередині треку є корисний шматок і зайвий шматок Беріть безпечні коміти, решту залишайте
Розділити Трек вирішив дві задачі одразу Ріжемо на два окремі зміни
Відхилити Трек пішов убік або приніс більше ризику, ніж користі Зберігаємо корисні нотатки, код не вливаємо

Команда cherry-pick особливо корисна, коли трек приніс не «все або нічого», а один хороший коміт усередині невдалої загальної історії:

git switch main
git cherry-pick 3fa12bc   # переносимо лише безпечний коміт
git revert 9ab44de        # якщо вже злитий коміт дав регрес

Тут важливо не соромитися слова «відхилити». Розробники, особливо на початку шляху, часто шкодують уже виконану роботу: «ну агент же старався», «ну diff же красивий». А іноді дешевше викинути трек, ніж потім тиждень розгрібати наслідки. Код не ображається. А продакшен іноді дуже навіть.

Дуже корисно фіксувати рішення в короткому логу, щоб потім не згадувати на пам’ять, чому саме не злити красиву гілку з ще красивішою назвою:

Рішення: cherry-pick лише тести з promo track; відхилити рефакторинг у CartTotal.
Причина: checkout track володіє src/checkout/*, promo track порушив межу scope.

Два рядки — а заощаджують масу часу майбутньому вам. А майбутній ви зазвичай найбуркотливіший reviewer у команді.

7. Cleanup як обов’язкова частина роботи

У розробці є особливий вид самообману — вважати cleanup чимось другорядним. Мовляв, головне — корисні зміни, а прибрати worktree і навести лад можна потім. «Потім» — це або «ніколи», або «через два тижні, коли ніхто не пам’ятає, що це за папка поруч із проєктом». Так з’являються кладовища worktree, старі гілки, хибне відчуття роботи та дивні CI-скрипти, які дивляться не туди.

Хороший cleanup починається не з видалення папки, а з питання: що з треку варто зберегти як артефакт. Навіть відхилений трек дає знахідку — шматок аналізу, план, список ризиків, хороший тест. Їх виносять у лог треку, handoff note поруч із проєктом або, якщо це вже reusable-правило чи шаблон, — в окремий markdown-файл у Workflow Kit. І лише потім прибирають папку.

Коли рішення ухвалено, видалення буденне:

git worktree remove ../commerce-os.checkout-flow
git branch -d feature/checkout-refactor   # якщо гілка вже злита
git worktree prune                        # чистимо службові посилання на видалені worktree

Якщо всередині worktree залишилися незакомічені зміни, Git, найімовірніше, не дасть видалити його мовчки. І це дуже правильна поведінка. Це не «Git вередує», це Git каже: «спочатку вирішіть, ми зберігаємо цю роботу чи свідомо викидаємо». Якщо трек справді треба викинути, робіть це усвідомлено. Не через хаотичне видалення папки мишкою та подальший подив, чому репозиторій тепер дивиться на вас німим докором.

Особливо приємно, коли cleanup вбудований у ритуал завершення треку. Прийняли — прибрали папку, почистили посилання, оновили лог. Відхилили — зберегли корисні нотатки, прибрали папку, позначили рішення. Тоді паралельна робота лишається інструментом, а не починає жити власним життям поруч із проєктом.

8. Артефакт parallel-session-log.md

Щоб паралельні треки не залишалися лише в пам’яті розробника та в глибинах термінала, корисно вести короткий лог. У Workflow Kit зручно зберігати шаблон такого файла, а сам робочий лог — поруч із поточним проєктом і конкретним треком. Він не має бути довгим. Його задача — за хвилину відповісти на питання: який був трек, де він жив, що перевірили, яке рішення ухвалили і чи все прибрали після роботи.

Наприклад, так:

# parallel-session-log.md

## Трек
feature/checkout-refactor

## Сесія
checkout-refactor-2026-05-24

## Worktree
../commerce-os.checkout-flow

## Область змін
src/checkout/*, tests/checkout/*

## Стоп-умова
Checkout-тести зелені, diff менше 300 рядків

## Перевірено
- git diff --stat
- ./gradlew test --tests "*Checkout*"

## Рішення
accept

## Збережені артефакти
- track-checkout-refactor.md
- review-notes.md

## Чистка
- worktree removed: yes
- branch removed: yes

Зверніть увагу: тут немає бюрократії заради бюрократії. Цей файл не дублює Git і не намагається замінити PR. Він просто пов’язує разом контекст треку, сигнали перевірки та рішення людини. Через кілька днів ви відкриваєте його і відразу розумієте, що сталося. Через місяць інший розробник відкриває його — і теж розуміє. У цей момент паралельна робота перестає бути «магією, яку Вася якось наколдував у терміналі», і стає нормальним командним процесом.

Якщо ви зберігаєте шаблони таких логів у Workflow Kit, команда починає краще бачити повторювані патерни. Які треки частіше приймаються цілком, які частіше переходять у cherry-pick, які майже завжди розповзаються по scope. А це вже дуже корисний інженерний зворотний зв’язок, навіть без складних метрик і красивих дашбордів.

Коли у вас є окремий worktree, короткий контракт треку, зрозумілі сигнали моніторингу й виразний parallel-session-log.md, трек перестає бути туманним. І лише після цього вже має сенс розбирати handoff усередині нього: які артефакти мають пережити зміну етапу і що наступний учасник отримує на вході. Паралельна робота стає напрочуд спокійною. Не драматичною, не «agentic», не хайповою — просто спокійною. А в інженерії це зазвичай і є ознака того, що ви все робите правильно.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ