# ワークツリー
> 現在のセッションを離れずに、一時的な [git worktree](https://git-scm.com/docs/git-worktree) で実験的な作業を分離します。モデルが広範囲にわたる編集を行おうとしていて、それをメインチェックアウトから分離しておきたい場合や、サブエージェントを独自のサンドボックスで作業させたい場合に便利です。
## クイックスタート
### ワークツリー内でセッションを開始する (`--worktree` フラグ)
最初からセッション全体をワークツリー内で実行することが分かっている場合は、起動時に `--worktree` を指定します。
```bash
# 自動生成のスラッグ (例: tender-jemison-037f0a)
qwen --worktree
# 明示的な名前
qwen --worktree my-feature
# `=` 形式 (下のヒントを参照——位置プロンプトも同時に渡す場合に推奨)
qwen --worktree=my-feature
# PR 参照 — `origin` から refs/pull/<N>/head をフェッチ
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"をスラッグとして消費し(スペースがあるため)拒否します。代わりに以下のいずれかを使用してください。
qwen --worktree=my-feature "say hi"(=で明示的なスラッグ → 常に動作)qwen "say hi" --worktree(位置プロンプトを先に、フラグを後に → 自動スラッグ)qwen --worktree --approval-mode yolo "say hi"(間に他のフラグを挟むことでベア形式が確定)
ヒント —
qwen --resume --worktree foo(セッションIDなし)を初回使用すると、空のピッカーが表示されます。 ピッカーは選択したワークツリーのセッションストレージにスコープされます。そのワークツリー外で開始されたセッションはリストに表示されません。foo内で開始されたセッションを再開するには、qwen --resume <id> --worktree fooを直接使用してください。CLI はfoo/ディレクトリを再作成するのではなく、既存のものに再アタッチします。
process.cwd() とモデルのワークスペースは、最初のターンが実行される前にワークツリーに切り替えられます。Ctrl+C を2回押して終了すると、終了ダイアログ がワークツリーを保持するか削除するかを尋ねます。
--worktree フラグは --acp / --experimental-acp と組み合わせることはできません。ACP ホスト(Zed など)の場合は、代わりに loadSession / newSession リクエストの cwd としてワークツリーパスを渡してください。
またはセッション中に依頼する
代わりに、既存のセッション内で Qwen Code に自然言語でワークツリーを作成するよう依頼することもできます。
> start a worktree called experiment-a
Worktree experiment-a created on branch worktree-experiment-a
.qwen/worktrees/experiment-aこの時点から、モデルはすべてのファイル編集とシェルコマンドを .qwen/worktrees/experiment-a/ 経由でルーティングします。元の作業ディレクトリは触れられません。
完了したら:
> exit the worktree and remove it
Removed worktree experiment-a (branch worktree-experiment-a)後で戻ってきたい場合は、ワークツリーをディスク上に保持して終了するよう依頼します:
> exit the worktree but keep it
Kept worktree experiment-a at .qwen/worktrees/experiment-aワークツリーが使用されるタイミング
ワークツリーは、以下の4つの独立した経路でアクティブになります。
| トリガー | 動作 |
|---|---|
--worktree を指定して起動 | CLI はモデルターンが実行される前にワークツリーを作成し、セッションの chdir をその中に設定します。PR 形式(#N、完全なURL)は最初にフェッチします。 |
| セッション中に明示的にワークツリーを依頼 | モデルが enter_worktree を呼び出します。以降のファイル編集はその中で行われます。 |
| 明示的に離れるよう依頼 | モデルが keep または remove を指定して exit_worktree を呼び出します。 |
| モデルが分離機能を有効にしてサブエージェントを起動 | 使い捨てのワークツリー(agent-<hex>)が自動的に作成され、エージェントに差分がない場合はクリーンアップされます。 |
セッション中の2つのツール(enter_worktree / exit_worktree)は、意図的に明示的な言い回しの背後にゲートされています。「このバグを修正して」や「ブランチを作成して」と言っても、これらは トリガーされません。「ワークツリーを使って」「ワークツリーを開始して」「ワークツリー内で」などと言う必要があります。--worktree CLI フラグにはそのようなガードはなく、指定されると常にワークツリーを作成します。
作成されるもの
Qwen が管理するすべてのワークツリーは、プロジェクトの .qwen ディレクトリの下に配置されます。
<repoRoot>/.qwen/worktrees/<slug>/ # 作業ディレクトリ
↳ branch worktree-<slug> # 現在のブランチから作成- スラッグ — 英字、数字、ドット、アンダースコア、ハイフン。最大64文字。名前を指定しない場合、
<形容詞>-<名詞>-<6桁16進数>のスラッグが自動生成されます(例:tender-jemison-037f0a)。PR 参照の場合はpr-<N>が生成されます。 - ブランチ — 常に
worktree-<slug>で、ワークツリーを要求した時点でチェックアウトしているブランチから分岐されます(メインの作業ツリーのHEADであるとは限りません)。PR ワークツリーの場合、ブランチはworktree-pr-<N>で、ローカルブランチではなくFETCH_HEAD(GitHub 側の PR の先端)をベースとします。 - フック — ワークツリーの
core.hooksPathは自動的にメインリポジトリの.husky/(優先)または.git/hooks/を指すように設定されるため、ワークツリー内のコミットでも既存の pre-commit / commit-msg フックがトリガーされます。 - オプションのシンボリックリンク —
worktree.symlinkDirectoriesにリストされたディレクトリ(設定 を参照)は、メインリポジトリから新しいワークツリーにシンボリックリンクされるため、node_modulesなどの重いディレクトリを再インストールせずに再利用できます。
汎用ワークツリーパスは 設定できません — <repoRoot>/.qwen/worktrees/ の下に置かれなければなりません。これにより、再起動時や古いクリーンアップスイープ時に CLI がそれを見つけることができます。(無関係の agents.arena.worktreeBaseDir 設定は、Agent Arena ワークツリーのみを制御し、~/.qwen/arena/ 以下の別のパスツリーを使用します。)
フッターとステータス行
ワークツリーがアクティブな場合、フッターは独自の行に薄いインジケーターを表示します。
⎇ worktree-experiment-a (experiment-a)カスタムステータス行スクリプト を使用している場合、そのスクリプトは stdin にパイプされる JSON ペイロード内で worktree オブジェクトも受け取ります。
{
"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) で十分です。
カスタムステータス行ですでにワークツリー情報を表示している場合は、重複を避けるために組み込みのフッター行を非表示にできます。設定 を参照してください。
終了ダイアログ (Ctrl+C / Ctrl+D)
ワークツリーがアクティブな状態で終了ショートカットを2回押すと、CLI を閉じる代わりに ワークツリー終了ダイアログ が開きます。
⎇ Active worktree: "experiment-a" (worktree-experiment-a)
• 2 new commit(s) on worktree-experiment-a
• 3 uncommitted file(s)
Removing the worktree will discard everything above.
What would you like to do?
○ Keep worktree (exit without deleting)
○ Remove worktree and branch (discards 2 commit(s), 3 file(s))
○ Cancel (stay in session)ダイアログは開いた時点でワークツリーの状態を検査し(git status --porcelain + git rev-list <baseHEAD>..HEAD)、両方のカウントを表示するため、破棄される内容を正確に把握できます。ESC でキャンセルされます。
git status 自体が失敗した場合(例: インデックス破損、CLI の下でワークツリーディレクトリが削除された)、ダイアログは ⚠ Could not measure worktree state 警告を表示し、カウントが信頼できない可能性があります。根本的なリポジトリの問題を診断するまでは、Keep または Cancel を選択してください。
--resume 復元
アクティブなワークツリーのバインディングは、セッションのトランスクリプトと共にサイドカーファイルに永続化されます。
<chatsDir>/<sessionId>.worktree.json--resume <sessionId> で CLI を起動するか(/resume からセッションを選択)、インタラクティブTUI、ヘッドレス -p、ACP/Zed モードのいずれでも、以下の3つの動作が一貫して行われます。
- サイドカーが読み込まれ、ワークツリーディレクトリがディスク上にまだ存在することが確認されます。
- 存在する場合、モデルは次のプロンプトで一回限りのリマインダーを受け取ります。
[Resumed] Active worktree: "<slug>" at <path> (branch: <branch>). Continue using this path for all file operations. - ワークツリーディレクトリがセッション間で削除された場合、古くなったサイドカーは自動的にクリーンアップされます — エラーは発生せず、再開はワークツリーコンテキストなしで続行されます。
各モードは独自の注入メカニズムを選択しますが、ユーザーから見える動作は同じです。
| モード | メカニズム |
|---|---|
| インタラクティブ (TUI) | INFO 履歴アイテム + 次のユーザープロンプトへのシステムリマインダープレフィックス |
ヘッドレス (-p) | プロンプトへの <system-reminder> プレフィックス + 出力ストリーム内の worktree_restored JSON システムイベント |
| ACP (例: Zed) | 次の prompt() 呼び出しに添付される保留通知 |
モデルは自動的にワークツリーに chdir されるわけでは ありません — リマインダーによって、ワークツリーパスを通じて編集をルーティングし続けるようになります。
サブエージェントの分離
agent ツールはオプションの isolation: "worktree" パラメーターを受け入れます。設定されている場合、Qwen Code はサブエージェントが開始される前に <repoRoot>/.qwen/worktrees/agent-<7hex>/ に一時的なワークツリーを作成し、以下の動作をします。
- 変更がない場合 → エージェント終了時にワークツリーは自動的に削除されます。
- 変更がある場合 → ワークツリーは保持され、そのパスとブランチがエージェントの結果に追加されます。例:
差分をレビューし、手動でマージまたは削除してください。
…agent output… [worktree preserved: /path/to/.qwen/worktrees/agent-3f2a1b9 (branch worktree-agent-3f2a1b9)]
2つの制約:
isolation: "worktree"にはsubagent_typeが必要です。フォークされたサブエージェント(subagent_typeなし)は親の会話コンテキスト全体を再利用するため、それらを分離すると意図と作業ツリーが分断されます。- バックグラウンドエージェント(
run_in_background: true)は分離と問題なく動作します。クリーンアップはエージェントが完了を報告したときに実行されます。
自動的な古いワークツリーのクリーンアップ
クラッシュや --no-cleanup シャットダウンを生き延びた一時的なエージェントワークツリーは、CLI の起動時に保守的なフェイルクローズドルールで回収されます。
| ガード | 動作 |
|---|---|
スラッグが agent-<7hex> パターンに一致 | あなたが作成した名前付きワークツリーには触れません。 |
ディレクトリ mtime が 30 日を超える | 新しいエントリはスキップされます。 |
| 追跡対象の未コミット変更がある | そのエントリをスキップ(削除しません)。 |
| リモートから到達可能でないコミットがある | そのエントリをスキップ(削除しません)。 |
| git 状態の読み取り中にエラーが発生 | そのエントリをスキップ(削除しません)。 |
名前付きのユーザー作成ワークツリー(enter_worktree スラッグ)は 自動的には決してクリーンアップされません — 削除を明示的に要求するまで保持されます。
exit_worktree action="remove" の安全ガード
ディレクトリとブランチが削除される前に、3つの独立したガードがトリガーされます。
- セッション所有権 — 各ワークツリーには、それを作成したセッションIDを示すサイドカーマーカーが付いています。別のセッションがそれを削除しようとすると、手動での脱出手段として
git worktree removeを指し示す明確なエラーで拒否されます。 - ダーティな作業ツリー — 未コミットの追跡対象ファイルまたは追跡されていないファイルがあると、削除がブロックされます。上書きするには
discard_changes: trueを渡します。(バイパスには明示的なユーザー確認が必要です —action: "remove"は AUTO_EDIT モードでも自動承認されません。) - マージされていないコミット — 他のローカルブランチやリモート参照が指していない
worktree-<slug>上のコミットは、無条件に削除をブロックします。「コミットを破棄する」フラグはありません。なぜなら、コミットされた作業を失うことはユーザーが意図することはほとんどないからです。最初にマージ、プッシュ、またはブランチを他の場所にリネームしてください。
これら3つのガードは、WorktreeExitDialog → Remove ボタンにも適用されます。
設定
汎用ワークツリー体験を形成する2つの設定:
| キー | タイプ | デフォルト | 効果 |
|---|---|---|---|
ui.hideBuiltinWorktreeIndicator | boolean | false | 組み込みの ⎇ worktree-… (…) フッター行を非表示にします。worktree フィールドはカスタムステータス行スクリプトに引き続き配信されます。ステータス行ですでにワークツリーを表示している場合のみ true に設定してください。そうしないと、すべての UI アフォーダンスを失います。 |
worktree.symlinkDirectories | string[] | undefined | 作成時にメインリポジトリから汎用ワークツリーにシンボリックリンクするディレクトリ。パスはリポジトリルートからの相対パスです。絶対パスや .. を含むエントリは拒否されます。存在しないソースや既存の宛先は黙ってスキップされます(上書きはしません)。 |
例:
// ~/.qwen/settings.json または <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" }| フィールド | タイプ | 必須 | 備考 |
|---|---|---|---|
name | string | no | スラッグ。英字、数字、ドット、アンダースコア、ハイフン。最大64文字。省略時は自動生成。 |
以下の場合に実行を拒否:
- CLI が Git リポジトリ内にない場合。
- カレントワーキングディレクトリがすでに
.qwen/worktrees/内にある場合(入れ子のワークツリーは不可)。
exit_worktree
{ "name": "experiment-a", "action": "remove", "discard_changes": false }| フィールド | タイプ | 必須 | 備考 |
|---|---|---|---|
name | string | yes | enter_worktree で使用したスラッグと一致する必要があります。 |
action | "keep" | "remove" | yes | keep はディレクトリとブランチを保持、remove は両方を削除。 |
discard_changes | boolean | action="remove" かつダーティな場合のみ | ダーティツリーガードを上書きします。action="keep" では効果なし。 |
action: "remove" は AUTO_EDIT 承認モードでも常に確認を求められます — これは破壊的なシェル操作として扱われ、情報のみのツールではありません。
agent — isolation パラメーター
{
"subagent_type": "my-agent",
"description": "…",
"prompt": "…",
"isolation": "worktree"
}| フィールド | タイプ | 必須 | 備考 |
|---|---|---|---|
isolation | "worktree" | no | エージェントを新しい agent-<7hex> ワークツリーで実行します。subagent_type の設定が必要です(フォーク不可)。 |
エージェントツールリファレンスの残りの部分については サブエージェント を参照してください。
CLI リファレンス
--worktree [name | #N | url]
qwen --worktree # スラッグ自動生成
qwen --worktree my-feature # 明示的なスラッグ
qwen --worktree=my-feature # = 形式
qwen --worktree=#123 # PR 参照
qwen --worktree https://github.com/owner/repo/pull/123 # PR URL| 入力 | 結果 |
|---|---|
| ベアフラグ(値なし) | 自動スラッグ <形容詞>-<名詞>-<6桁16進数>、ブランチ worktree-<slug>、ベース = 現在のブランチ |
| プレーンスラッグ | ブランチ worktree-<slug>、ベース = 現在のブランチ。スラッグの検証: 英字/数字/ドット/アンダースコア/ハイフン、最大64文字 |
#N または <github-url>/pull/N | スラッグ pr-<N>、ブランチ worktree-pr-<N>、ベース = git fetch origin pull/<N>/head 後の FETCH_HEAD(30秒タイムアウト) |
--worktree は --acp / --experimental-acp と組み合わせることはできません。
--worktree を --resume <session-id> と組み合わせた場合、ワークツリーが優先されます: 再開されたセッションの保存済みワークツリー(存在する場合)は上書きされ、stderr 行と最初のプロンプトリマインダーが上書きを報告します。
インタラクティブ(TUI)およびヘッドレス(-p)モードでは、ワークツリーが自動的に作成され、最初のターンの前にセッションがその中に chdir されます。
PR フェッチの失敗モード(終了コード != 0、ワークツリーは作成されない):
| 原因 | メッセージ抜粋 |
|---|---|
origin リモートが存在しない | requires an "origin" remote that points at GitHub |
| PR が origin に存在しない | Failed to fetch PR #<N>: the PR does not exist on origin |
| 30秒のネットワークタイムアウト | Failed to fetch PR #<N>: timed out after 30s |
| PR 番号が範囲外 / ゼロ | Invalid PR number |
制限事項
以下の項目は現在のフェーズでは意図的に実装されていません。
- スパースチェックアウトなし。 大規模なモノレポではツリー全体がチェックアウトされます。(
worktree.sparsePathsはロードマップ項目です。) - tmux 統合なし。 CLI は新しい tmux ウィンドウでワークツリーセッションを起動しません。
- ワークツリーはセッションストレージにおいて独立した「プロジェクト」です。
--worktree fooで開始されたセッションは、そのワークツリーのチャットディレクトリの下に保存されます。後で再開するには、再度--worktree fooを渡す必要があります。--worktreeなしで開始されたセッションはメインチェックアウトの下に保存され、ワークツリーの再開ピッカーには表示されません。 - スラッグをまたいだセッションのオーバーライドはありません。
qwen --resume <sid> --worktree secondで、<sid>が--worktree firstで作成された場合、セッションを見つけることができません。セッションとワークツリーはprojectHash(cwd)によって強く結合されています。既存のセッションでワークツリーを切り替えるには、終了してから新しい--worktreeと新しいプロンプトで再起動する必要があります。将来のアーキテクチャ変更(ストレージのアンカーをcwdではなくリポジトリルートにする)により、この制約は解消される可能性があります。 - セッション中の
enter_worktreeはprocess.cwd()やConfig.targetDirを切り替えません。 そのツールはモデルコンテキストのみの規則を使用します(サブエージェント を参照)。起動時の--worktreeフラグのみがプロセスの作業ディレクトリを実際に切り替えます。 - 他の引数フィールドの相対パスは、ワークツリーの chdir の前に解決されます。 パスを受け取るフラグ(
--mcp-config、--openai-logging-dir、--json-file、--input-file、--telemetry-outfile、--include-directories)は、--worktreeが設定されている場合、起動時の cwd を基準に絶対パスに正規化されます。このリストにない他のパス形状の argv フィールドは、ワークツリーの cwd に対して解決されます — 安全のために絶対パスを使用してください。
`docs/design/worktree.md` のロードマップを参照してください。
## トラブルシューティング
**フッターにワークツリーインジケーターが表示されない(ワークツリーを作成したばかりなのに)**
`ui.hideBuiltinWorktreeIndicator` が `true` に設定されていないか確認してください。また、ツールの成功メッセージでスラッグが空でないことを確認してください。
**`--resume` でワークツリーが復元されない**
`<chatsDir>/<sessionId>.worktree.json` が存在するか確認してください。ワークツリーディレクトリが削除されると、CLI はサイドカーを自動的に削除します。そのため、サイドカーとディレクトリの両方が存在しない場合は、「復元するワークツリーがない」という正常な状態であり、バグではありません。`--debug` フラグを付けて実行し、`restoreWorktreeContext` を grep して理由を確認してください。
**`exit_worktree` が「別のセッションによって作成されました」と表示する**
これはセッション所有権ガードです。元のセッションを再開してそこから終了するか、提案された `git worktree remove …` コマンドを手動で実行してください。
**古い `agent-<hex>` ワークツリーがどんどん蓄積される**
30 日間の期限は控えめに設定されています。`git worktree list && git worktree remove <path>` で手動で掃除するか、待つだけでも構いません。30 日経過後の次の CLI 起動時に、ワークツリーがクリーンでプッシュ済みであれば自動的に削除されます。