12k
All articles

Использование Git Worktrees с ИИ-агентами для написания кода

Используйте git worktrees с ИИ-агентами, чтобы изолировать ветки, избежать конфликтов файлов и безопасно управлять портами, БД и слияниями.

OpenReplay Team
OpenReplay Team
Использование Git Worktrees с ИИ-агентами для написания кода

Надёжный способ запускать несколько ИИ-агентов на одном репозитории — придерживаться схемы «одна задача, одна ветка, один worktree, один агент»: каждый агент получает собственный каталог, созданный через git worktree add, работает в собственной ветке и никогда не трогает файлы, которые редактирует другой агент.

Большинство разработчиков приходят к этому паттерну на собственном горьком опыте. Два агента в одном рабочем каталоге незаметно перезаписывают друг другу недоделанные правки, или один из них намертво зависает при попытке переключиться на ветку, уже извлечённую в другом месте. Эта статья — именно про рабочий процесс с агентами: что паттерн изолирует, что он сознательно не изолирует и что делать, когда три агента заканчивают работу одновременно.

Ключевые выводы

  • Запускайте по одному агенту на worktree: git worktree add ../task-a -b agent/task-a main даёт каждому агенту изолированный каталог и ветку.
  • Worktrees изолируют файлы, но не среду выполнения: порты, базы данных и Docker-тома принадлежат машине, поэтому назначьте каждому worktree отдельный порт и отдельную базу данных.
  • Новый worktree содержит только отслеживаемые файлы; выполните npm ci и скопируйте .env перед запуском агента.
  • Ветка может быть извлечена только в одном worktree, поэтому укажите агентам никогда не выполнять git checkout или git switch.
  • Сливайте готовые ветки по одной, каждый раз выполняя rebase на обновлённый main перед слиянием.

Паттерн Git Worktree для ИИ-агентов

Паттерн «один агент — один worktree» требует двух команд на задачу. Создайте worktree с новой веткой на основе main, а затем запустите внутри него агента:

git worktree add ../task-a -b agent/task-a main
git worktree add ../task-b -b agent/task-b main

Направьте одного агента в ../task-a, а другого — в ../task-b. У каждого будет свой рабочий каталог, свой индекс и свой HEAD, при этом все worktrees используют общую базу объектов и общие ссылки (refs), поэтому коммиты, сделанные в одном, сразу видны из остальных. Привязывайте worktree к задаче, а не к агенту: создавайте его в начале работы и удаляйте, когда ветка слита. Anthropic описывает ту же последовательность действий вручную в руководстве по worktrees для Claude Code, а Cursor запускает агентов в изолированных worktrees из окна Agents Window; Codex работает точно так же, если указать ему каталог.

Почему один общий каталог не работает?

Два агента в одном каталоге дают сбой молча: ни git, ни сами агенты не выдают ошибку, когда один перезаписывает незакоммиченные правки другого, поэтому ущерб обнаруживается только на этапе ревью. Механизм обнаружения конфликтов в git сравнивает коммиты; параллельные записи в одно и то же рабочее дерево до него просто не доходят.

Второй тип сбоя заметнее, но хуже. Параллельные операции git в общем каталоге сталкиваются на .git/index.lock, и если агент падает, удерживая блокировку, оставшийся файл блокирует git-команды всех остальных агентов, пока кто-нибудь не удалит его вручную. Одни агенты повторяют попытку; другие бросают коммитить и продолжают генерировать код поверх неограниченно растущего незакоммиченного состояния. Отдельные worktrees устраняют обе проблемы, поскольку каждый worktree индексирует изменения в собственный индекс, а не в общий.

Чего не содержит новый worktree

Новый worktree содержит только отслеживаемые файлы, поэтому node_modules, .env, кэши сборки и всё остальное, что перечислено в gitignore, отсутствует, пока вы это не создадите. Агент, запущенный в «голом» worktree, провалит первый же прогон тестов или, что хуже, «услужливо» перепишет конфигурацию, чтобы это компенсировать. Подготавливайте каждый worktree до запуска агента:

cd ../task-a
npm ci
cp ../main-repo/.env .env

npm ci — правильный выбор для установки здесь: команда создана для чистых окружений и устанавливает ровно то, что указано в lock-файле. Если ваш агент — Claude Code, файл .worktreeinclude может переносить gitignored-файлы вроде .env в worktrees, которые Claude Code создаёт сам, но он не действует на worktrees, созданные вручную через git worktree add, — поэтому ручное копирование работает с любым инструментом.

Что worktrees не изолируют

Worktrees изолируют файлы, но не среду выполнения: порты, базы данных, Docker-тома и общие кэши принадлежат машине, поэтому два dev-сервера, запущенные из двух worktrees, всё равно будут конкурировать за порт 3000. Граница каталога ничего не значит для всего, что адресуется по имени хоста или порту.

Изолировано в каждом worktreeОбщее для всей машины
Рабочие файлы, незакоммиченные правкиTCP-порты
Индекс (staging area)Базы данных
Извлечённая ветка / HEADDocker-тома и демон
Результаты сборки внутри каталогаГлобальные кэши пакетов

Выделите каждому worktree собственный порт и собственную базу данных до запуска агента, который выполняет миграции, потому что изменение схемы, сделанное из одного worktree, попадёт в любую базу, которую используют остальные. Задайте оба параметра в скопированном .env:

# ../task-a/.env
PORT=3001
DATABASE_URL=postgres://localhost:5432/app_agent_task_a

Именование базы по названию ветки упрощает поиск и последующее удаление устаревших. Контейнеры тоже могут изолировать уровень выполнения, но связанные с этим компромиссы тянут на отдельную статью.

Как сообщить агенту, что он находится в worktree?

Ветка может быть извлечена только в одном worktree одновременно, поэтому агент, пытающийся синхронизироваться командой git checkout main, получает ошибку и часто зависает. Руководство по git checkout описывает это поведение и указывает --ignore-other-worktrees как способ его обойти. Не позволяйте агенту выяснять это во время работы; пропишите правило в файле инструкций, который агент читает (AGENTS.md, CLAUDE.md или аналогичный):

You are working inside a git worktree.
Stay on the current branch. Never run `git checkout` or `git switch`.
To sync with main, run `git fetch origin` and `git rebase origin/main`.

Когда агенту нужно только прочитать или собрать конкретный коммит, ветки не нужны вовсе: git worktree add --detach создаёт worktree с отсоединённым HEAD, что полностью обходит правило исключительности.

git worktree add --detach ../review-b1a2c3 b1a2c3

Как сливать то, что вернулось?

Worktrees не устраняют конфликты слияния; они переводят их из разряда молчаливых перезаписей во время выполнения в разряд явных конфликтов на этапе слияния, где с ними справляется обычный инструментарий git. Когда несколько агентов заканчивают одновременно, интегрируйте результаты последовательно: слейте одну ветку, выполните rebase следующей на обновлённый main, слейте её и повторите.

cd ../main-repo
git merge agent/task-a

cd ../task-b
git rebase main
cd ../main-repo
git merge agent/task-b

Каждый rebase выявляет конфликты со всем, что уже слито, по одной ветке за раз, вместо того чтобы накапливать трёхсторонние сюрпризы. Правило упорядочивания находится выше по потоку, чем само слияние: задачи, которые затрагивают одни и те же файлы или где одна потребляет результат другой, нужно выполнять последовательно, а не параллельно. Никакая организация worktrees не исправит декомпозицию задач, которая изначально не была независимой.

Сколько агентов и когда убирать за собой

Практический потолок задаёт не git и не диск, а ваша пропускная способность на ревью, поскольку каждый параллельный агент производит ветку, которую нужно прочитать, протестировать и слить. Команды, публикующие материалы об этом процессе, например инженерная команда incident.io, описывают одновременный запуск четырёх-пяти агентов, но большинству разработчиков хватает и меньшего числа. Когда ветка слита, выполните git worktree remove ../task-a; поскольку при подготовке появились неотслеживаемые файлы, скорее всего понадобится --force — его git worktree remove требует для «грязных» worktrees. Если каталог был удалён через rm -rf, команда git worktree prune очистит устаревшие метаданные, которые git всё ещё хранит.

Начните с двух агентов

Схема «одна задача, одна ветка, один worktree, один агент» превращает параллельных агентов из источника незаметных повреждений в набор веток, пригодных для ревью. Начните с двух: создайте worktrees, подготовьте каждый с помощью npm ci и отдельного .env для задачи, добавьте инструкцию «оставайся в своей ветке» и отработайте последовательность rebase-затем-merge, прежде чем масштабироваться сверх того, что вы реально способны отревьюить.

Часто задаваемые вопросы

Что использовать для параллельного запуска ИИ-агентов: git worktrees или отдельные клоны?

Worktrees обычно предпочтительнее, потому что они используют общую базу объектов: коммит, сделанный в одном worktree, сразу виден из остальных без push и fetch, а история хранится на диске в единственном экземпляре. Отдельные клоны дублируют всю историю и требуют push и fetch для обмена коммитами. Клоны выигрывают только тогда, когда нужна полная изоляция — например, в репозиториях с сабмодулями.

Работают ли git worktrees с репозиториями, использующими сабмодули?

Лишь частично. Собственное руководство git по worktree относит поддержку сабмодулей к разделу BUGS, называет множественное извлечение экспериментальным и не рекомендует извлекать суперпроект более чем в одном месте одновременно. Кроме того, worktree с сабмодулями нельзя переместить командой git worktree move. Для параллельной работы агентов над репозиторием с сабмодулями отдельные полные клоны — более безопасный механизм изоляции, даже несмотря на дублирование истории и необходимость push для обмена коммитами между рабочими копиями.

Используют ли все git worktrees одну и ту же конфигурацию git?

Да. Каждый worktree читает одну и ту же конфигурацию репозитория, если вы явно не откажетесь от этого. Чтобы задать отдельному worktree собственные настройки, выполните git config extensions.worktreeConfig true, а затем записывайте значения через git config --worktree — они попадут в файл config.worktree этого worktree. Компромисс: старые версии Git не смогут открыть репозиторий после включения этого расширения.

Удаляет ли удаление worktree ветку агента?

Нет. Ветки — это ссылки (refs), общие для всего репозитория, поэтому git worktree remove удаляет рабочий каталог и его метаданные, но оставляет ветку и все её коммиты нетронутыми. Теряются только незакоммиченные изменения в этом каталоге — именно поэтому remove отказывается удалять «грязные» worktrees без флага --force. Ветку удаляйте отдельно командой git branch -d после слияния.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — self-hosted, with full data ownership.

Star on GitHub

We use cookies to improve your experience. By using our site, you accept cookies.