12k
All articles

Git Worktrees: что это, когда и зачем их использовать

Git worktree: чем они отличаются от stash и вторых клонов, когда их использовать и какие команды нужны для управления ими.

OpenReplay Team
OpenReplay Team
Git Worktrees: что это, когда и зачем их использовать

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

Большинство разработчиков сталкиваются с необходимостью в worktree в момент раздражения: stash применился не к той ветке, языковой сервер мучительно переиндексирует проект после checkout, или второй клон того же репозитория никак не удаётся держать в актуальном состоянии. Worktrees решают все три проблемы, причём они поставляются вместе с Git 2.5 с июля 2015 года, так что устанавливать ничего не нужно.

В этой статье разбираемся, чем worktree на самом деле является на диске, какие три команды управляют этой функциональностью, когда worktree выигрывает у stash, когда — у второго клона, и во что он вам обойдётся.

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

  • Git worktree — это второй рабочий каталог, привязанный к тому же репозиторию, со своей извлечённой веткой; связанный каталог содержит небольшой файл .git, указывающий обратно на основной репозиторий, а не полноценную папку .git.
  • Одна команда git worktree add -b hotfix-bug ../hotfix-workspace main заменяет всю последовательность из stash, checkout, создания ветки, исправления и stash-pop.
  • Все worktrees используют одну базу объектов и один набор ссылок, поэтому единственный git fetch обновляет каждый worktree, и история не дублируется на диске.
  • Git отслеживает закоммиченные файлы, а не ваше окружение: установленные зависимости, файлы .env и кеши сборки остаются в исходном каталоге.
  • По умолчанию Git не позволяет извлечь одну и ту же ветку в двух worktrees; создайте worktree с отсоединённым HEAD с помощью git worktree add -d, если вам нужно только собрать или протестировать коммит.

Что такое Git worktree на диске?

Связанный worktree — это каталог с извлечёнными файлами, а не копия вашего репозитория. Его .git верхнего уровня — это обычный файл, а не каталог, и он указывает на небольшую папку с метаданными внутри .git/worktrees/ основного репозитория; полностью эта схема описана в документации по git worktree. Всё «тяжёлое» остаётся в одном месте: одна база объектов, одна история и один набор ссылок обслуживают каждый worktree, и лишь несколько файлов принадлежат конкретному worktree — среди них HEAD и индекс.

Этот единственный факт объясняет всё остальное про worktrees. Создание worktree стоит одного checkout, а не clone. Коммиты, сделанные в любом worktree, немедленно видны из всех остальных, потому что под ними лежит один-единственный репозиторий.

Какой рабочий процесс заменяет worktree?

Без worktrees срочное вмешательство означает необходимость приостановить текущее состояние. Знакомая последовательность, с использованием формы git stash push, чтобы сообщение действительно прикрепилось:

git stash push -m "wip: login form"
git checkout main
git checkout -b hotfix-bug
# fix, commit, push, wait for the merge
git checkout feature-login
git stash pop

Пять команд, два переключения контекста и один шанс применить stash не к той ветке. Вариант с worktree — одна команда:

git worktree add -b hotfix-bug ../hotfix-workspace main

Она создаёт соседнюю папку, создаёт ветку hotfix-bug, отходящую от main, и извлекает её туда. Ваш исходный каталог остаётся нетронутым: та же ветка, те же изменённые файлы, тот же открытый редактор. Когда исправление будет смержено, команда git worktree remove ../hotfix-workspace удалит папку и снимет её с регистрации.

Три команды: add, list, remove

Повседневная работа с worktrees сводится к трём подкомандам. git worktree add <path> <branch> извлекает существующую ветку по новому пути; добавьте -b <new-branch> перед путём, чтобы попутно создать ветку. Укажите в add путь, которого ещё не существует, и Git создаст каталог за вас.

git worktree list показывает каждый worktree, начиная с основного, с его путём, сокращённым хешем коммита и извлечённой веткой в квадратных скобках:

/home/you/project             abc1234 [feature-login]
/home/you/hotfix-workspace    def5678 [hotfix-bug]

git worktree remove <path> удаляет worktree, и правила удаления в Git строги: один неотслеживаемый файл или один изменённый отслеживаемый файл остановят команду, если вы не добавите --force, который эти изменения выбросит. Основной worktree Git не отпустит вообще, а для заблокированного потребуется --force дважды. Если же вы удалите папку worktree вручную, git worktree prune подчистит оставшиеся после неё метаданные.

Когда worktree выигрывает у stash?

Stash приостанавливает вашу работу; worktree позволяет ей продолжаться. Это различие и определяет выбор. Stash хорош, чтобы отложить дифф в две строки на десять минут. Он не подходит, когда работа в вашем каталоге всё ещё «в полёте»: запущенный набор тестов или долгая сборка, dev-сервер, следящий за файлами, или редактор, языковой сервер которого переиндексировал бы весь проект после переключения ветки.

С worktree ничто из этого состояния не нарушается, потому что вы вообще не трогаете исходный каталог. Вы открываете новую папку во втором окне редактора, выполняете там прерывающую задачу и возвращаетесь к тому, что оставили ровно в том же виде. Та же изоляция объясняет, почему инструменты, запускающие AI-агентов для написания кода параллельно, взяли worktrees за основу своей модели работы. Более субъективный взгляд предлагает заметка matklad: в ней описан фиксированный набор из пяти worktrees одного разработчика, сопоставленных с параллельными видами деятельности, а не с ветками; воспринимайте это как личную настройку, а не как общепринятую практику.

Worktree или второй клон?

Worktree выигрывает у второго клона всегда, когда оба каталога должны отслеживать один и тот же репозиторий. Поскольку каждый worktree использует одно хранилище объектов и один набор ссылок, единственный git fetch обновляет их все, ветка, отправленная из одного, мгновенно видна в остальных, а добавление worktree не дублирует историю на диске. Второй клон не даёт ничего из этого: два хранилища объектов, в которые нужно делать fetch, два набора ссылок, расходящихся между собой, и удвоенный расход диска.

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

StashWorktreeВторой клон
Работа продолжаетсяНетДаДа
Стоимость настройкиМгновенноОдин checkoutПолный clone
История на дискеОбщаяОбщаяДублируется
Один fetch обновляетДаДаНет

Во что обходятся worktrees?

Git отслеживает закоммиченные файлы, а не ваше окружение. Это основной «налог» на каждый новый worktree:

  • Установленные зависимости не переносятся. Свежему worktree проекта на npm или pip обычно нужен собственный шаг установки, прежде чем он соберётся.
  • Неотслеживаемые локальные файлы остаются на месте: файлы .env, локальная конфигурация и кеши сборки живут в исходном каталоге, потому что у Git нет о них никаких записей.
  • Папки worktree, созданные внутри репозитория, отображаются как неотслеживаемый мусор и требуют записи в .gitignore. Соседние каталоги (../hotfix-workspace) полностью снимают эту проблему.
  • По умолчанию одна ветка может быть извлечена только в одном worktree одновременно. Обходные пути существуют (--force для add, --ignore-other-worktrees для switch), но более чистое решение, когда вам нужно лишь собрать или протестировать коммит, — worktree с отсоединённым HEAD:
git worktree add -d ../build-check 1a2b3c4

Флаг -d оставляет HEAD в новой папке отсоединённым, поэтому ни одна ветка не занимается и ограничение никогда не срабатывает. Команда git switch -d <commit> внутри существующего worktree делает то же самое.

Достаточно ли у вас параллельных задач?

Тест на целесообразность короток. Регулярно ли вас прерывают, когда у вас есть реальная незакоммиченная работа? Приводит ли переключение ветки к переустановке зависимостей или переиндексации языковым сервером, которую вы явно ощущаете? Поддерживаете ли вы уже второй клон того же репозитория? Два «да» — и worktrees окупятся за первую же неделю. Ноль — и stash вместе с ветками вполне достаточно. Начните с одного: в следующий раз, когда срочное исправление свалится посреди работы над фичей, выполните git worktree add вместо git stash, а папку удалите, когда исправление будет смержено.

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

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

Частично. В собственном руководстве Git поддержка сабмодулей помечена как незавершённая в разделе BUGS, и там же не рекомендуется извлекать суперпроект более чем в одном месте одновременно. На практике связанный worktree с сабмодулями внутри нельзя переместить с помощью git worktree move, а для его удаления через git worktree remove требуется флаг force. Если ваш репозиторий сильно опирается на сабмодули, второй клон будет более безопасным выбором.

Общие ли stash и ветки между git worktrees?

Да. Всё, что лежит под refs/, является общим для каждого worktree, поэтому ветки, теги и stash выглядят одинаково, где бы вы ни находились. Исключение составляют три пространства имён, остающиеся локальными для одного worktree: refs/bisect, refs/worktree и refs/rewritten. Помимо них, приватными являются только собственные указатели worktree, среди которых HEAD и его индекс. Таким образом, stash, созданный в одном worktree, можно увидеть в списке и применить из любого другого worktree того же репозитория.

Можно ли переместить worktree в другую папку после создания?

Да. Передайте git worktree move сам worktree и путь, по которому вы хотите его видеть, и Git за один раз переместит папку и перепишет её метаданные. Два случая, с которыми команда не справится: основной worktree и любой связанный worktree с сабмодулями внутри. Для заблокированного worktree потребуется флаг force дважды. Если вы уже сами перетащили папку в другое место, git worktree repair восстановит связь.

Что произойдёт, если запустить git worktree add только с путём, без ветки?

Git возьмёт последнюю часть пути как имя ветки, создаст эту ветку от HEAD и извлечёт её в новую папку. Так, git worktree add ../hotfix оставит вас с веткой hotfix, извлечённой в ../hotfix. Если такое имя уже занято, Git вместо этого извлечёт существующую ветку — при условии, что её сейчас не удерживает другой worktree.

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.