git worktree: несколько веток одновременно
Как держать несколько веток одного репозитория открытыми в разных папках одновременно — без stash, без второго clone.
git worktree — механизм, позволяющий одному репозиторию иметь несколько рабочих деревьев: каждая дополнительная папка-worktree держит свою ветку и свой набор файлов, но все они делят одну общую базу объектов в
.git/.
Зачем это нужно на практике
Вы пишете большую фичу, рабочее дерево забито недоделанными правками — и тут прилетает срочный баг на проде. Классика: git stash, переключение на main, фикс, обратное переключение, git stash pop и молитва, что ничего не конфликтует. Или второй git clone — но это полная копия истории, лишние гигабайты и рассинхрон веток.
Worktree решает это чисто: вы создаёте отдельную папку для хотфикса, чините баг там, а основная папка с фичей остаётся нетронутой. Обе папки видят одни и те же коммиты, ветки и stash — потому что объектная база общая. Переключение между задачами — это просто cd в другую директорию.
Создание и список worktree
Основная команда — git worktree add. Ей нужны путь к новой папке и ветка, которую туда выложить.
# создать worktree для существующей ветки
git worktree add ../proj-hotfix hotfix/login
# создать НОВУЮ ветку и worktree одной командой
git worktree add -b feature/export ../proj-export origin/main
Флаг -b feature/export заводит новую ветку от origin/main и сразу выкладывает её в папку ../proj-export. После этого у вас две полноценные рабочие папки: исходная и новая. Посмотреть все деревья и их ветки:
git worktree list
# /home/me/proj a1b2c3d [feature/big]
# /home/me/proj-hotfix d4e5f6a [hotfix/login]
# /home/me/proj-export 0099aab [feature/export]
Типичный сценарий с хотфиксом целиком:
git worktree add ../proj-hotfix -b hotfix/crash origin/main
cd ../proj-hotfix
# ... правим, коммитим, пушим ...
git commit -am "fix: null pointer on logout"
git push -u origin hotfix/crash
cd ../proj # вернулись к фиче — она нетронута
Удаление и уборка
Закончив с веткой, удалите её дерево. Сначала уберите папку через Git (он почистит служебные ссылки), затем при желании удалите саму ветку:
git worktree remove ../proj-hotfix # удалить дерево
git branch -d hotfix/crash # удалить слитую ветку
Если папку случайно удалили вручную (через rm -rf), у Git останутся «висячие» записи. Подчистить их:
git worktree prune # убрать ссылки на исчезнувшие деревья
git worktree list # проверить, что мусора не осталось
Полезный флаг для долгоживущих деревьев — lock: он защищает worktree на съёмном диске или сетевой шаре от автоматической очистки prune:
git worktree lock ../proj-on-usb --reason "review build"
git worktree unlock ../proj-on-usb
Как это работает под капотом
Главный репозиторий — это папка с подкаталогом .git/. Когда вы добавляете worktree, Git создаёт в новой папке не каталог, а файл .git с одной строкой gitdir: /путь/к/основному/.git/worktrees/proj-export. Внутри .git/worktrees/<имя>/ лежат отдельные HEAD, индекс и ссылки этого дерева. А вот сама база объектов (коммиты, деревья, блобы) и большинство ссылок — общие. Отсюда два следствия.
Во-первых, дисковая экономия: новый worktree весит ровно как выложенные файлы плюс крошечные служебные данные, а не как вся история. Во-вторых, важное ограничение: одну и ту же ветку нельзя выложить в два дерева сразу. Если ветка main уже занята основным деревом, git worktree add ../x main вернёт ошибку — иначе два дерева могли бы двигать один и тот же указатель ветки и конфликтовать. Обходится созданием отдельной ветки (-b) или флагом --detach для одноразового detached-дерева.
git worktree add --detach ../proj-ci v2.0.0 # одноразовое дерево на теге
Типичные сценарии
Worktree окупается в нескольких повторяющихся ситуациях. Срочный хотфикс посреди фичи — отдельное дерево от origin/main, починили, запушили, вернулись; недоделанная фича всё это время лежит нетронутой в своей папке. Ревью чужого PR без потери контекста — выложили ветку коллеги в ../proj-review, собрали и погоняли её локально, пока ваша работа открыта рядом. Долгая сборка или прогон тестов — пока CI-дерево на теге компилирует релиз, вы спокойно пишете код в основном дереве, не дожидаясь окончания. Сравнение двух версий бок о бок — открыли v1 и v2 в соседних папках и сверяете поведение в двух запущенных экземплярах приложения. Во всех случаях выигрыш один: переключение задачи — это cd, а не «спрячь-переключись-восстанови».
Под несколько активных деревьев удобна общая схема именования папок: проект-фича, проект-hotfix, проект-review рядом с основной директорией. Тогда git worktree list читается с одного взгляда, а сборочные скрипты находят нужное дерево по предсказуемому пути.
Частые ошибки
- Попытка выложить занятую ветку. «
fatal: 'main' is already checked out» — ветка уже в другом дереве. Сделайте новую ветку через-bили используйте--detach. - Удаление папки через
rmвместоgit worktree remove. Останутся висячие ссылки; лечитсяgit worktree prune, но лучше удалять штатно. - Ожидание изолированных коммитов. Все деревья делят историю и stash. Коммит, сделанный в одном дереве, моментально виден в
git logдругого — это фича, а не баг. - Пути внутри основного дерева. Не создавайте worktree внутри рабочей папки проекта — кладите рядом (
../proj-x), иначе Git и сборщики запутаются. - Забытые деревья на CI. Долгоживущие сборочные worktree копятся; периодически
git worktree listи уборка, иначе диск засоряется.
Итоги
git worktree add <путь> <ветка>создаёт вторую рабочую папку;-bзаодно заводит новую ветку.- Все деревья делят базу объектов в одном
.git/— это дёшево по диску и держит ветки синхронными. - Одну ветку нельзя выложить в два дерева; для разовых задач есть
--detach. git worktree listпоказывает все деревья,removeиpruneубирают их.- Worktree заменяет связку «stash + переключение» и второй
cloneпри параллельной работе над ветками.