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

Рабочие деревья (Worktrees)

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

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

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

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

# Автоматически сгенерированный слаг (например, tender-jemison-037f0a) qwen --worktree # Явное имя qwen --worktree my-feature # Форма с `=` (рекомендуется, если также передаётся позиционный prompt — см. подсказку ниже) 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 без значения, за которым следует позиционный prompt, может быть неоднозначным. Поскольку --worktree принимает необязательное значение, qwen --worktree "скажи привет" заставит yargs интерпретировать "скажи привет" как слаг (и отклонить его из-за пробела). Используйте один из вариантов:

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

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

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

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

Или попросите во время сессии

Кроме того, вы можете попросить Qwen Code на естественном языке создать рабочее дерево из текущей сессии:

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

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

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

> выйди из рабочего дерева и удали его Удалено рабочее дерево experiment-a (ветка worktree-experiment-a)

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

> выйди из рабочего дерева, но сохрани его Сохранено рабочее дерево experiment-a в .qwen/worktrees/experiment-a

Когда используются рабочие деревья

Рабочие деревья активируются по четырём независимым путям:

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

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

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

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

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

Когда рабочее дерево активно, в нижнем колонтитуле (Footer) отображается тусклый индикатор на отдельной строке:

⎇ 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" } }

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

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

Exit Dialog (Ctrl+C / Ctrl+D)

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

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

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

Если сам git status не срабатывает (например, поврежденный индекс, каталог рабочего дерева был удален из-под CLI), диалог показывает предупреждение ⚠ Could not measure worktree state, и счетчики могут быть ненадежными — выберите Оставить или Отмена, пока вы не диагностировали проблему с репозиторием.

--resume Restore

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

<chatsDir>/<sessionId>.worktree.json

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

  1. Боковой файл загружается, и проверяется, что каталог рабочего дерева все еще существует на диске.
  2. Если все в порядке, модель получает одноразовое напоминание при следующем запросе:
    [Resumed] Active worktree: "<slug>" at <path> (branch: <branch>). Continue using this path for all file operations.
  3. Если каталог рабочего дерева был удален между сессиями, устаревший боковой файл очищается автоматически — без ошибки, возобновление просто продолжается без контекста рабочего дерева.

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

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

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

Sub-Agent Isolation

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

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

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

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

Automatic Stale Cleanup

Временные рабочие деревья агентов, пережившие сбой или завершение с --no-cleanup, удаляются при каждом запуске CLI с консервативными правилами безопасного отказа:

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

Защитные механизмы при exit_worktree action="remove"

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

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

Те же три защитных механизма применяются к кнопке WorktreeExitDialog → Remove.

Настройки

Два параметра формируют работу с рабочими деревьями общего назначения:

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

Пример:

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

Применяется ко ВСЕМ путям создания рабочих деревьев: флаг --worktree, инструмент enter_worktree и agent isolation: "worktree".

Настройки, не связанные с рабочими деревьями общего назначения, но о которых стоит знать:

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

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

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

enter_worktree

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

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

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

exit_worktree

{ "name": "experiment-a", "action": "remove", "discard_changes": false }
ПолеТипОбязательноПримечания
namestringдаДолжен совпадать с слагом, использованным в 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"нетЗапускает агента в новом рабочем дереве agent-<7hex>. Требует указания subagent_type (форки не поддерживаются).
Полный список инструментов агентов см. в разделе Sub-Agents.

Справочник по 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
ВводРезультат
Пустой флаг (без значения)Авто-слаг <adjective>-<noun>-<6hex>, ветка worktree-<slug>, базовая ветка = текущая.
Простой slugВетка worktree-<slug>, базовая ветка = текущая. Проверка slug: буквы/цифры/точка/подчёркивание/дефис, макс. 64 символа.
#N или <github-url>/pull/NСлаг pr-<N>, ветка worktree-pr-<N>, базовая ветка = FETCH_HEAD после git fetch origin pull/<N>/head (таймаут 30 с).

--worktree нельзя сочетать с --acp / --experimental-acp.

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

В интерактивном (TUI) и фоновом (-p) режимах worktree создаётся автоматически, и сессия переходит в эту директорию перед первым запросом.

Режимы сбоя при получении PR (код возврата != 0, worktree не создан):

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

Ограничения

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

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

Дорожная карта — в docs/design/worktree.md.

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

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

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

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

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

Last updated on