Skip to Content
Руководство для пользователейВозможностиWorktrees

Worktrees

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

Быстрый старт

Запуск сессии внутри worktree (флаг --worktree)

Если вы заранее знаете, что вся сессия должна выполняться внутри worktree, передайте --worktree при запуске:

# Автоматически сгенерированный slug (например, tender-jemison-037f0a) qwen --worktree # Явно указанное имя qwen --worktree my-feature # Форма с `=` (рекомендуется, если также передаётся позиционный промпт — см. подсказку ниже) qwen --worktree=my-feature # Ссылка на PR — извлекает refs/pull/<N>/head из `origin` qwen --worktree=#4174 qwen --worktree https://github.com/QwenLM/qwen-code/pull/4174 # Продолжить предыдущую сессию --worktree — переподключается к существующему каталогу qwen --resume <session-id> --worktree=my-feature

Подсказка — голый --worktree с последующим позиционным промптом неоднозначен. Поскольку --worktree принимает необязательное значение, qwen --worktree "say hi" заставляет yargs воспринять "say hi" как slug (и отклонить его из-за пробела). Используйте один из вариантов:

  • qwen --worktree=my-feature "say hi" (всегда работает — явный slug через =)
  • qwen "say hi" --worktree (позиционный промпт первым, флаг в конце → авто-slug)
  • qwen --worktree --approval-mode yolo "say hi" (любой флаг между ними фиксирует голую форму)

Подсказка — qwen --resume --worktree foo (без ID сессии) при первом использовании показывает пустой список выбора. Список ограничивается хранилищем сессий выбранного worktree; сессии, запущенные вне этого worktree, не отображаются. Чтобы возобновить сессию, которая была запущена внутри foo, используйте qwen --resume <id> --worktree foo напрямую — CLI переподключается к существующему каталогу foo/, не создавая его заново.

process.cwd() и рабочее пространство модели переключаются на worktree до выполнения первого шага. Выйдите дважды с помощью Ctrl+C, и Диалог выхода предложит сохранить или удалить worktree.

Флаг --worktree нельзя комбинировать с --acp/--experimental-acp — для ACP-хостов (например, Zed) передавайте путь к worktree как cwd в запросе loadSession/newSession.

Или попросите mid-session

Альтернативно, попросите Qwen Code на естественном языке создать worktree из текущей сессии:

> создай worktree с именем experiment-a Worktree experiment-a создан на ветке worktree-experiment-a .qwen/worktrees/experiment-a

Начиная с этого момента модель будет направлять все редактирования файлов и команды оболочки через .qwen/worktrees/experiment-a/. Ваш исходный рабочий каталог остаётся нетронутым.

Когда закончите:

> выйди из worktree и удали его Worktree experiment-a удалён (ветка worktree-experiment-a)

Если вы хотите вернуться позже, попросите выйти, оставив worktree на диске:

> выйди из worktree, но сохрани его Worktree experiment-a сохранён по пути .qwen/worktrees/experiment-a

Когда Worktrees используются

Worktrees активируются по четырём независимым сценариям:

ТриггерЧто происходит
Запуск с --worktreeCLI создаёт worktree до первого шага модели и переключает сессию в него. PR-формы (#N, полный URL) сначала выполняют fetch.
Явный запрос worktree в середине сессииМодель вызывает enter_worktree; последующие редактирования файлов выполняются внутри него.
Явный запрос на выходМодель вызывает exit_worktree с параметром keep или remove.
Модель запускает субагента с включённой изоляциейАвтоматически создаётся одноразовый worktree (agent-<hex>), который удаляется, если у агента нет изменений.

Два инструмента mid-session (enter_worktree / exit_worktree) намеренно привязаны к явным формулировкам — фразы “исправь эту ошибку” или “создай ветку” не запускают их. Нужно сказать что-то вроде “используй worktree”, “создай worktree” или “в worktree”. Флаг CLI --worktree такой защиты не имеет — он всегда создаёт worktree при наличии.

Что создаётся

Каждый управляемый Qwen worktree размещается в каталоге .qwen вашего проекта:

<repoRoot>/.qwen/worktrees/<slug>/ # Рабочий каталог ↳ ветка worktree-<slug> # Создаётся от текущей ветки
  • Slug — буквы, цифры, точка, подчёркивание, дефис; макс. 64 символа. Если имя не указано, автоматически генерируется slug вида <adjective>-<noun>-<6hex> (например, tender-jemison-037f0a). Ссылки на PR дают slug pr-<N>.
  • Ветка — всегда worktree-<slug>, ответвляется от той ветки, которая у вас была активна при запросе worktree (не обязательно HEAD основного рабочего дерева). Для PR-ворктри ветка называется worktree-pr-<N> и базируется на FETCH_HEAD(верхушка PR на стороне GitHub), а не на вашей локальной ветке.
  • Хукиcore.hooksPath worktree автоматически указывается на основной репозиторий .husky/ (предпочтительно) или .git/hooks/, чтобы коммиты внутри worktree по-прежнему запускали ваши существующие pre-commit / commit-msg хуки.
  • Необязательные симлинки — каталоги, перечисленные в worktree.symlinkDirectories (см. Настройки), симлинкуются из основного репозитория в новый worktree, чтобы тяжёлые каталоги типа node_modules можно было переиспользовать без переустановки.

Путь к worktree общего назначения не настраивается — он должен находиться в <repoRoot>/.qwen/worktrees/, чтобы CLI мог найти его при перезапуске и при очистке устаревших. (Несвязанная настройка agents.arena.worktreeBaseDir управляет только worktree Agent Arena, которые используют отдельное дерево путей в ~/.qwen/arena/.)

Футер и строка состояния

Когда worktree активен, в футере отображается затемнённый индикатор на отдельной строке:

⎇ worktree-experiment-a (experiment-a)

Если вы используете пользовательский скрипт строки состояния, он также получает объект worktree в JSON-нагрузке, передаваемой через stdin:

{ "worktree": { "name": "experiment-a", "path": "/path/to/repo/.qwen/worktrees/experiment-a", "branch": "worktree-experiment-a", "original_cwd": "/path/to/repo", "original_branch": "main" } }

Поле присутствует только когда worktree активен, поэтому достаточно проверки на null (input.worktree?.name).

Если ваша строка состояния уже отображает информацию о worktree, вы можете скрыть встроенную строку футера, чтобы избежать дублирования — см. Настройки ниже.

Диалог выхода (Ctrl+C / Ctrl+D)

Двойное нажатие комбинации выхода при активном worktree открывает Диалог выхода из worktree вместо закрытия CLI:

⎇ Активный worktree: "experiment-a" (worktree-experiment-a) • 2 новый коммит(а) на worktree-experiment-a • 3 не закоммиченных файла Удаление worktree приведёт к потере всего вышеуказанного. Что вы хотите сделать? ○ Сохранить worktree (выйти без удаления) ○ Удалить worktree и ветку (будет отброшено 2 коммита, 3 файла) ○ Отмена (остаться в сессии)

Диалог проверяет состояние worktree при открытии (git status --porcelain + git rev-list <baseHEAD>..HEAD) и показывает оба значения, чтобы вы точно знали, что будет отброшено. Клавиша ESC отменяет действие.

Если сам git status завершается ошибкой (например, повреждённый индекс, каталог worktree был удалён из-под CLI), диалог показывает предупреждение ⚠ Не удалось определить состояние worktree, и значения могут быть ненадёжными — выберите Сохранить или Отмена, пока не диагностируете проблему с репозиторием.

Восстановление через --resume

Привязка активного worktree сохраняется в файле-сайдкаре рядом с транскриптом сессии:

<chatsDir>/<sessionId>.worktree.json

Когда вы запускаете CLI с --resume <sessionId> (или выбираете сессию из /resume), три действия выполняются единообразно во всех режимах — интерактивный TUI, безголовый -p и ACP/Zed:

  1. Сайдкар загружается, и проверяется, что каталог worktree всё ещё существует на диске.
  2. Если он жив, модель получает одноразовое напоминание в самом следующем промпте:
    [Возобновлено] Активный worktree: "<slug>" по пути <path> (ветка: <branch>). Продолжайте использовать этот путь для всех файловых операций.
  3. Если каталог worktree был удалён между сессиями, устаревший сайдкар автоматически очищается — без ошибки, возобновление просто продолжается без контекста worktree.

Каждый режим выбирает свой механизм внедрения, но видимое пользователю поведение идентично:

РежимМеханизм
Интерактивный (TUI)Элемент истории INFO + префикс-напоминание в системе в следующем пользовательском промпте.
Безголовый (-p)Префикс <system-reminder> в промпте + системное событие JSON worktree_restored в выходном потоке.
ACP (например, Zed)Ожидающее уведомление, прикреплённое к следующему вызову prompt().

Модель не переключается автоматически в worktree через chdir — напоминание просто заставляет её направлять правки по пути worktree.

Изоляция субагента

Инструмент agent принимает необязательный параметр isolation: "worktree". Когда он установлен, Qwen Code создаёт эфемерный worktree в <repoRoot>/.qwen/worktrees/agent-<7hex>/ до запуска субагента, и:

  • Нет изменений → worktree автоматически удаляется по завершении работы агента.
  • Есть изменения → worktree сохраняется; его путь и ветка добавляются к результату агента, например:
    …вывод агента… [worktree сохранён: /path/to/.qwen/worktrees/agent-3f2a1b9 (ветка worktree-agent-3f2a1b9)]
    Просмотрите diff и объедините или удалите вручную.

Два ограничения:

  • isolation: "worktree" требует subagent_type — разветвлённые субагенты (без subagent_type) повторно используют полный контекст разговора родителя, поэтому их изоляция разделила бы намерение и рабочее дерево.
  • Фоновые агенты (run_in_background: true) корректно работают с изоляцией; очистка запускается, когда агент сообщает о завершении.

Автоматическая очистка устаревших

Эфемерные агентские worktree, пережившие сбой или завершение с --no-cleanup, удаляются при каждом запуске CLI с консервативными правилами fail-closed:

ПроверкаПоведение
Slug должен соответствовать шаблону agent-<7hex>Именованные worktree, созданные вами, никогда не трогаются.
mtime каталога > 30 днейБолее новые записи пропускаются.
Любое незакоммиченное отслеживаемое изменениеПропустить запись (не удалять).
Любой коммит, недоступный с удалённого репозиторияПропустить запись (не удалять).
Любая ошибка чтения git-состоянияПропустить запись (не удалять).

Именованные пользовательские worktree (slug из enter_worktree) никогда не очищаются автоматически — они остаются, пока вы не попросите их удалить.

Защитные проверки в exit_worktree action="remove"

Три независимые проверки выполняются перед удалением каталога и ветки:

  1. Владение сессией — каждый worktree имеет маркер-сайдкар с ID создавшей его сессии. Если другая сессия пытается его удалить, запрос отклоняется с чёткой ошибкой, указывающей на git worktree remove как ручной выход.
  2. Грязное рабочее дерево — незакоммиченные отслеживаемые или неотслеживаемые изменения блокируют удаление. Передайте discard_changes: true для переопределения. (Обход требует явного подтверждения пользователя — action: "remove" никогда не подтверждается автоматически в режиме AUTO_EDIT.)
  3. Неслитые коммиты — коммиты на worktree-<slug>, на которые не ссылается ни одна другая локальная ветка или удалённая ссылка, блокируют удаление безусловно; флага “отбросить коммиты” нет, потому что потеря закоммиченной работы редко соответствует намерениям пользователя. Сначала объедините, отправьте или переименуйте ветку в другом месте.

Те же три проверки применяются к кнопке Удалить в WorktreeExitDialog.

Настройки

Две настройки формируют работу с worktree общего назначения:

КлючТипПо умолчаниюЭффект
ui.hideBuiltinWorktreeIndicatorbooleanfalseСкрывает встроенную строку футера ⎇ worktree-… (…). Поле worktree по-прежнему передаётся пользовательским скриптам строки состояния. Установите true только если ваша строка состояния уже отображает worktree — иначе вы потеряете всю UI-подсказку.
worktree.symlinkDirectoriesstring[]undefinedКаталоги в основном репозитории, которые нужно симлинговать в каждый worktree общего назначения при создании. Пути задаются относительно корня репозитория; абсолютные пути и любые записи, содержащие .., отклоняются. Отсутствующие источники и существующие цели молча пропускаются (без перезаписи).

Пример:

// ~/.qwen/settings.json или <repo>/.qwen/settings.json { "worktree": { "symlinkDirectories": ["node_modules", ".turbo", "dist"], }, }

Применяется ко всем путям создания worktree: флаг --worktree, инструмент enter_worktree и agent isolation: "worktree".

Настройки, не связанные с worktree общего назначения, но полезные к сведению:

  • agents.arena.worktreeBaseDir — управляет размещением worktree Agent Arena (по умолчанию ~/.qwen/arena). Не влияет на worktree общего назначения, которые всегда находятся в <repoRoot>/.qwen/worktrees/.

Схемы для worktree.sparsePaths пока нет — это элемент дорожной карты (см. Ограничения).

Справочник по инструментам

enter_worktree

{ "name": "experiment-a" }
ПолеТипОбязательноПримечания
namestringнетSlug. Буквы, цифры, точка, подчёркивание, дефис; макс. 64 символа. Авто-генерация, если не указан.

Отказывается выполняться, когда:

  • CLI находится не в git-репозитории.
  • Текущий рабочий каталог уже находится внутри .qwen/worktrees/ (вложенные worktree запрещены).

exit_worktree

{ "name": "experiment-a", "action": "remove", "discard_changes": false }
ПолеТипОбязательноПримечания
namestringдаДолжен совпадать с slug, использованным в enter_worktree.
action"keep" | "remove"даkeep сохраняет каталог + ветку; remove удаляет оба.
discard_changesbooleanтолько когда action="remove" и грязноПереопределяет защиту грязного дерева. Не действует для action="keep".

action: "remove" всегда запрашивает подтверждение, в том числе в режиме одобрения AUTO_EDIT — он рассматривается как деструктивная операция оболочки, а не информационный инструмент.

agent — параметр isolation

{ "subagent_type": "my-agent", "description": "…", "prompt": "…", "isolation": "worktree" }
ПолеТипОбязательноПримечания
isolation"worktree"нетЗапускает агента в новом worktree agent-<7hex>. Требует установки subagent_type (без форков).

См. Субагенты для остальной части справочника по инструменту агента.

Справочник по CLI

--worktree [name | #N | url]

qwen --worktree # авто-генерация slug qwen --worktree my-feature # явный slug qwen --worktree=my-feature # форма с = qwen --worktree=#123 # ссылка на PR qwen --worktree https://github.com/owner/repo/pull/123 # URL PR
ВходРезультат
Голый флаг (без значения)Авто slug <adjective>-<noun>-<6hex>, ветка worktree-<slug>, базовая = текущая ветка.
Простой slugВетка worktree-<slug>, базовая = текущая ветка. Валидация slug: буквы/цифры/точка/подчёркивание/дефис, макс. 64 симв.
#N или <github-url>/pull/NSlug pr-<N>, ветка worktree-pr-<N>, базовая = FETCH_HEAD после git fetch origin pull/<N>/head (тайм-аут 30 с).

--worktree нельзя комбинировать с --acp / --experimental-acp.

Когда --worktree комбинируется с --resume <session-id>, приоритет у worktree: сохранённый worktree возобновляемой сессии (если есть) переопределяется, и в stderr выводится строка + напоминание в первом промпте об этом переопределении.

Для интерактивного (TUI) и безголового (-p) режимов worktree создаётся автоматически, и сессия переключается в него до первого шага.

Режимы ошибок при fetch PR (код выхода != 0, worktree не создан):

ПричинаФрагмент сообщения
Отсутствует удалённый originтребуется удалённый "origin", указывающий на GitHub
PR не существует на originНе удалось получить PR #<N>: PR не существует на origin
Тайм-аут сети 30 сНе удалось получить PR #<N>: тайм-аут через 30 с
Номер PR вне диапазона / нольНедопустимый номер PR

Ограничения

Следующие пункты намеренно не реализованы в текущей фазе:

  • Нет разреженной выгрузки. Большие монорепозитории загружают полное дерево. (worktree.sparsePaths — элемент дорожной карты.)
  • Нет интеграции с tmux. CLI не запускает сессии worktree в новых окнах tmux.
  • Worktree — отдельные “проекты” для хранения сессий. Сессии, запущенные с --worktree foo, сохраняются в каталоге chats этого worktree; чтобы возобновить их позже, нужно снова передать --worktree foo. Сессии, запущенные без --worktree, сохраняются в основной рабочей копии и не появятся в выборе возобновления этого worktree.
  • Нет переопределения сессии между slug. qwen --resume <sid> --worktree second, где <sid> был создан с --worktree first, не сможет найти сессию — сессии и worktree жёстко привязаны через projectHash(cwd). Чтобы сменить worktree для существующей сессии, нужно выйти, затем перезапустить с новым --worktree и свежим промптом. Будущее архитектурное изменение (привязка хранилища к корню репозитория вместо cwd) снимет это ограничение.
  • Вызов enter_worktree mid-session НЕ переключает process.cwd() или Config.targetDir. Этот инструмент использует соглашение только контекста модели (см. Субагенты). Только флаг запуска --worktree действительно переключает рабочий каталог процесса.
  • Относительные пути в других аргументах разрешаются ДО переключения worktree. Флаги, принимающие пути (--mcp-config, --openai-logging-dir, --json-file, --input-file, --telemetry-outfile, --include-directories), нормализуются в абсолютные пути относительно cwd запуска, когда установлен --worktree. Другие поля argv в форме пути, не входящие в этот список, всё равно разрешаются относительно cwd worktree — используйте абсолютные пути для надёжности. Отслеживайте дорожную карту в docs/design/worktree.md.

Устранение неполадок

На панели Footer не отображается индикатор worktree, хотя я только что его создал. Проверьте, что ui.hideBuiltinWorktreeIndicator не установлено в true. Также убедитесь, что slug не пуст в сообщении об успешном выполнении инструмента.

--resume не восстанавливает мой worktree. Проверьте, существует ли <chatsDir>/<sessionId>.worktree.json. CLI автоматически удаляет sidecar, когда каталог worktree удалён, поэтому отсутствие sidecar и каталога — это нормальное состояние “нет worktree для восстановления”, а не ошибка. Запустите с флагом --debug и выполните grep по restoreWorktreeContext, чтобы увидеть причину.

exit_worktree сообщает “created by a different session”. Это защита владения сессией. Возобновите исходную сессию и выйдите из неё, или выполните предложенную команду git worktree remove … вручную.

Устаревшие worktree agent-<hex> продолжают накапливаться. 30-дневный порог является консервативным; выполните очистку вручную с помощью git worktree list && git worktree remove <path> или подождите — следующий запуск CLI после истечения 30 дней удалит их, если они чистые и отправлены в удалённый репозиторий.

Last updated on