Git worktrees существуют с 2015 года. Большую часть этого времени они были диковинкой — тем, чем пользовались разработчики ядра, что всплывало в малоизвестных ответах на Stack Overflow, о чём большинство разработчиков никогда не слышали.
Теперь у них настал звёздный час. ИИ-агентам для написания кода нужны изолированные окружения. Разработчики работают над несколькими фичами одновременно. Культура код-ревью требует быстрых переключений контекста. Рабочие процессы, которые делают worktrees ценными, наконец-то догнали саму фичу.
Это история о том, как worktrees появились, как они на самом деле устроены под капотом и почему вдруг стали важны.
Часть I. Проблема до worktrees
Боль переключения контекста
Каждый разработчик знает этот сценарий:
Трение тут не только в командах — оно в умственных издержках. Твой редактор перезагружает файлы. Языковой сервер переиндексирует. node_modules, возможно, придётся переустановить. Твоему мозгу приходится дважды переключать контекст.
Годами разработчики обходили это разными костылями:
Несколько клонов: клонируешь репозиторий дважды. Работаешь в одном, переключаешься в другом. Но теперь у тебя две копии всей истории, два набора remote'ов для настройки, а изменения в одном не появляются в другом без push и pull.
Гимнастика с git stash: спрятал всё, переключился, поработал, переключился обратно, достал из стэша. Работает, пока у тебя не накопится несколько стэшей и ты не забудешь, где какой. Или пока ты не осознаешь, что спрятал в стэш то, что на самом деле хотел закоммитить.
Просто не переключайся: доделай то, что делаешь, прежде чем браться за что-то ещё. Работает, пока коллеге не понадобится срочное ревью или пока прод не загорится.
Скрипт git-new-workdir
До официальных worktrees в составе git поставлялся сторонний скрипт под названием git-new-workdir. Он лежал в contrib/workdir/git-new-workdir и делал нечто хитроумное, но костыльное: создавал новую рабочую директорию и через symlink ссылался на внутренности .git.
Под капотом он:
- Создавал новую директорию
- Делал symlink на
.git/objects,.git/refs,.git/configи т. д. - Создавал отдельные
HEADиindexдля новой директории
Это работало, в основном. Но symlink'и хрупки. Скрипт официально не поддерживался. Он не обрабатывал все граничные случаи. Это был костыль, и все это понимали.
Сообществу git хотелось чего-то получше.
Часть II. Worktrees появляются в Git 2.5
Июль 2015: фича прибывает
Git 2.5, вышедший 29 июля 2015 года, представил git worktree как полноценную фичу. Главным автором был Nguyễn Thái Ngọc Duy, который работал над этой концепцией не один год.
Анонс в блоге GitHub описывал новую возможность так:
«Каждое связанное рабочее дерево — это псевдорепозиторий со своей собственной выгруженной рабочей копией. Его
.gitна самом деле является файлом, который ссылается на историю и ссылки из основного репозитория».
Примечательно, что фича вышла с предупреждением: она была помечена как экспериментальная, с оговорками о возможных багах и рекомендацией не использовать её с сабмодулями. Десять лет спустя эти шероховатости сгладились.
В сообщении первого коммита изложили видение:
«Репозиторий git может поддерживать несколько рабочих деревьев, позволяя выгружать больше одной ветки за раз».
Ключевая идея в том, что репозиторий git на самом деле — это две вещи:
- Хранилище объектов — все твои коммиты, деревья и blob'ы (директория
.git/objects) - Рабочее состояние — то, что сейчас выгружено, проиндексировано и т. д.
Они не обязаны жить в одном месте. Worktrees формализовали это разделение.
Реализация
Когда ты создаёшь worktree, git делает следующее:
- Создаёт новую директорию по указанному тобой пути
- Создаёт файл
.git(не директорию) в этом месте, ссылающийся обратно на основной репозиторий - Создаёт запись в
.git/worktrees/<name>/в основном репозитории - Выгружает ветку в новую рабочую директорию
Файл .git новой директории — это просто файл, содержащий:
А в основном репозитории .git/worktrees/feature-branch/ содержит:
Эта архитектура означает:
- Общие объекты — коммиты, деревья, blob'ы существуют один раз
- Общие ссылки — ветки и теги видны из всех worktrees
- Отдельное рабочее состояние — у каждого worktree свои HEAD, index и рабочая директория
Правило одной ветки
Git накладывает ограничение: ветка может быть выгружена только в одном worktree за раз. Попробуй выгрузить ту же ветку дважды — и получишь:
Это предотвращает целый класс запутанных багов. Если бы в двух worktrees была одна ветка и ты сделал коммит в одном, у другого ни с того ни с сего появился бы грязный diff.
Это можно обойти через detached HEAD или создав новую ветку, но защита здесь намеренная.
Часть III. Анатомия worktree
Что где живёт
Понимание раскладки файлов помогает развеять туман вокруг worktrees:
Что общее, а что нет
| Общее для всех worktrees | Отдельное для каждого worktree | |-------------------------|----------------------| | Хранилище объектов (коммиты, blob'ы) | Файлы рабочей директории | | Ссылки на ветки | HEAD (текущая ветка) | | Ссылки на теги | Индекс (область индекса) | | Конфигурация remote'ов | Неотслеживаемые файлы | | Хуки | Локальные изменения | | Конфиг (в основном) | MERGE_HEAD, REBASE_HEAD и т. д. |
Это означает:
- Коммиты, сделанные в одном worktree, сразу видны в других
- Но файлы на диске полностью независимы
- В каждом worktree могут быть разные незакоммиченные изменения
Сборка мусора и очистка
Git отслеживает, какие worktrees валидны. Если ты удалишь директорию worktree без git worktree remove, git об этом сразу не узнает. Метаданные в .git/worktrees/ сохраняются.
Это проверяет каждую запись в .git/worktrees/ и удаляет все, чей gitdir указывает на несуществующую директорию.
Git также запускает это автоматически при сборке мусора, так что осиротевшие метаданные не накапливаются вечно.
Часть IV. Почему worktrees оставались нишевыми
Почти десятилетие worktrees оставались фичей для продвинутых пользователей. Большинство разработчиков о них никогда не слышали. Почему?
1. Доминировал однобранчевый рабочий процесс
Большинство команд следовали простому шаблону:
- Создать ветку фичи
- Работать до завершения
- Открыть PR
- Смержить
- Удалить ветку
Это линейно. Ты доделываешь одно, прежде чем начать другое. Worktrees решают проблему параллельной работы, но большинство людей в параллель не работали.
2. Git-интерфейсы их не поддерживали
Популярные git-интерфейсы — GitKraken, SourceTree, GitHub Desktop, git-панель VS Code — либо не поддерживали worktrees, либо относились к ним как ко второсортным. Если твой инструмент не показывает фичу, ты ею не пользуешься.
3. Команды были малопонятными
Сравни:
Команда worktree длиннее, требует аргумента-пути, а ментальная модель (несколько рабочих директорий) непривычна. Без принуждающего фактора люди держатся за то, что знают.
4. Опасения по поводу места на диске
Каждый worktree — это полная выгрузка репозитория. Для больших репозиториев это накапливается. В эпоху жёстких дисков и небольших SSD это имело большее значение, чем сейчас.
Часть V. Почему у worktrees настал звёздный час
Несколько сдвигов сделали worktrees внезапно актуальными:
1. Культура код-ревью
Современная разработка управляется прерываниями. Ты работаешь над фичей A, когда:
- Кто-то просит ревью фичи B
- Тебе нужно проверить, есть ли баг на main
- Хотфикс требует немедленного внимания
Раньше каждое прерывание означало stash/switch/pop. С worktrees ты просто открываешь другую директорию. Твой контекст по фиче A остаётся нетронутым.
2. CI/CD и локальное тестирование
Сложным проектам часто нужно тестирование против разных веток. Ломается ли этот PR при слиянии с тем другим PR? С worktrees можно держать оба выгруженными и тестировать их взаимодействие без ребейза.
3. Монорепозитории
Большие монорепозитории делают клонирование дорогим. Если твой репозиторий весит 10 ГБ, клонировать его дважды ради параллельной работы — потратить 10 ГБ. Worktrees делят хранилище объектов — каждый дополнительный worktree стоит только размера рабочих файлов.
4. ИИ-агенты для кода
Вот это — самое главное.
Когда ИИ-агент меняет код, ему нужно где-то работать. Если он работает в твоей директории, у тебя проблема:
- Твои файлы меняются, пока ты их редактируешь
- Ты не можешь легко сравнить изменения агента со своими
- Эксперименты агента засоряют твоё рабочее дерево
Worktrees решают это элегантно:
Агент может:
- Свободно вносить изменения
- Коммитить в свою ветку
- Запускать сборки и тесты
- Итерировать, не задевая тебя
Когда он закончит, ты смотришь diff и мержишь. Это тот же рабочий процесс, что и ревью PR коллеги, только коллега — это ИИ, и работает он в worktree, а не в форке.
Этот паттерн — параллельная работа человека и ИИ над одной кодовой базой — провоцирует возрождение использования worktrees, которого разработчики git, вероятно, никогда не предвидели.
Часть VI. Worktrees под капотом
Для тех, кто хочет разобраться во внутренностях:
Как git находит репозиторий
Когда ты запускаешь команду git, git нужно найти директорию .git. Алгоритм поиска такой:
- Ищем
.gitв текущей директории - Если
.git— файл, читаем из него путьgitdir: - Следуем по этому пути
- Если по этому пути есть файл
commondir, общая директория git находится в другом месте
Эта косвенность и есть то, как работают worktrees. У связанного worktree есть файл .git, а не директория, и git следует по цепочке.
Механизм commondir
Директория git каждого связанного worktree (например, .git/worktrees/feature/) содержит файл commondir, указывающий на основную директорию .git.
Когда git'у нужно что-то общее (объекты, ссылки), он использует commondir. Когда нужно что-то специфичное для worktree (HEAD, index), он использует директорию worktree.
Код, который этим занимается, лежит в setup.c и path.c в исходниках git. Функция get_common_dir() разрешает путь для общих ресурсов.
Lock-файлы и одновременный доступ
Несколько worktrees могут выполнять команды git одновременно. Git использует lock-файлы, чтобы не допустить повреждения:
.git/index.lock— предотвращает одновременные изменения индекса.git/refs/heads/<branch>.lock— предотвращает одновременные обновления ссылки.git/worktrees/<name>/locked— помечает worktree как заблокированный (не будет удалён очисткой)
Специфичный для worktree lock полезен, когда worktree лежит на съёмном носителе или сетевом диске, который может временно стать недоступен.
Часть VII. Как эффективно использовать worktrees
Если ты убеждён, что worktrees стоит взять на вооружение, вот как использовать их правильно:
Организуй свои worktrees
Держи worktrees в предсказуемом месте:
Или держи их рядом с основным репозиторием:
Выбери соглашение и держись его.
Называй worktrees по веткам
Снижает путаницу:
Теперь имя директории совпадает с именем ветки.
Создай вспомогательную функцию
Добавь в конфиг своей оболочки:
Подчищай по завершении
Worktrees дёшево создавать, и они должны так же дёшево выбрасываться:
Не позволяй старым worktrees накапливаться.
Помни об ограничениях
- Нельзя выгрузить одну и ту же ветку в несколько worktrees
- Нельзя вкладывать worktrees друг в друга
- Сабмодулям нужна отдельная инициализация в каждом worktree
- Некоторые возможности IDE могут не понимать worktrees
Заключение
Git worktrees — фича десятилетней давности, чьё время наконец-то пришло. Они решают проблему параллельной работы — то, что мало что значило, пока разработчики работали линейно, но что имеет огромное значение теперь, когда ИИ-агенты пишут код вместе с нами.
Реализация элегантна: дели дорогое (хранилище объектов), разделяй дешёвое (рабочую директорию). Это та же идея, которая делает контейнеры эффективными — дели базу, изолируй различия.
Ревьюишь ли ты PR'ы, тестируешь ветки или даёшь ИИ-агенту работать в параллель — worktrees обеспечивают изоляцию без дублирования. Это не новая технология. Это старая технология, которая внезапно подошла под момент.
Если ты прятал изменения в стэш ради переключения веток — может быть, перестань. Есть способ получше, и он был тут всё это время.
Похожие материалы
Терминал, который (почти) никогда не умирает: как мы построили постоянный терминальный демон для Electron
Как мы построили изолированный по процессам хост терминала, который переживает перезапуски приложения, изящно справляется с backpressure и умеет холодное восстановление с диска.

Как получать по лицу (скорее всего по лицу, но и по другим местам тоже сойдёт)
У меня закончились технические темы для блога, так что вот кое-что другое, что мне интересно.
