【Claude Code 連載 第63回】worktree で並列セッションを走らせる — 編集を衝突させない分離

スポンサーリンク
【Claude Code 連載 第63回】worktree で並列セッションを走らせる — 編集を衝突させない分離 用語解説
【Claude Code 連載 第63回】worktree で並列セッションを走らせる — 編集を衝突させない分離
この記事は約15分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

スポンサーリンク

背景

この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。

1. 一言でいうと何か

git worktree は、独自のファイルとブランチを持つ別の作業ディレクトリで、メインのチェックアウトと同じリポジトリ履歴とリモートを共有するもの。各 Claude Code セッションを独自の worktree で走らせれば、1つのセッションの編集が別のセッションのファイルに触れることはありません。

具体的な絵はこうです——**1つのターミナルで Claude が機能を作りながら、2つ目のターミナルで別の Claude がバグを直す。**同じリポジトリなのに互いの作業を壊さない。

前回(第62回)の EnterWorktree / ExitWorktree ツールの背景がここです。

そして並列化の手段としての位置づけが明確に示されています。**worktree はファイル編集を分離するもので、subagent と agent team は作業自体を調整するもの。**役割が違うので、組み合わせても使えます(後述の isolation: worktree)。

補足が2つ。このページは CLI の話で、すべて git リポジトリを前提としています(他の VCS は WorktreeCreate フックで対応)。そしてデスクトップアプリは新しいセッションごとに自動で worktree を作ります——CLI で明示的にやることを、デスクトップは既定でやっている。

2. どういう場面で役立つか

シーン1:2つの作業を同時に進める

最も素直な用途です。機能開発とバグ修正を別々のターミナルで並行させる。git stash で行ったり来たりする必要がなくなります。

シーン2:subagent の並列編集を競合させない

subagent に isolation: worktree を付けると、各 subagent が一時的な worktree を取得します。**変更なしで完了すれば自動削除。**複数の subagent に同時にコードを触らせても衝突しません。

シーン3:特定の PR をチェックアウトして試す

# 付きの PR 番号か GitHub の PR URL を渡すだけで、pull/<number>/head をフェッチして専用の worktree を作ってくれます。

シーン4:git 以外の VCS でも分離を使う

SVN、Perforce、Mercurial などでも、WorktreeCreate / WorktreeRemove フックで独自の作成・後始末ロジックを差し込めます。

不要・向かないケース

  • 信頼ダイアログをまだ受け入れていないディレクトリインタラクティブに --worktree を初めて使う前に、そのディレクトリで一度 claude を実行して信頼ダイアログを受け入れる必要があります。未受諾なら**--worktree はエラーで終了します(-p の非対話実行は信頼チェックをスキップするので、claude -p --worktree はそのまま進みます**)。
  • -p で作った worktree を自動で片付けたい終了プロンプトがないので自動クリーンアップされません。git worktree remove で手動削除します。
  • .worktreeinclude とカスタムフックを併用したい。**フックはデフォルトの git 動作を置き換えるので、--worktree 使用時に .worktreeinclude は処理されません。**フックスクリプト内で自分でコピーします。
  • worktree.baseRef に任意の git ref を指定したい"fresh""head" のみです。
  • worktree の場所を細かく指定したい--worktree.claude/worktrees/<value>/ 固定です。別の場所に置くなら WorktreeCreate フックか、git で手動作成します。

3. コマンドと設定の実例

worktree で Claude を起動する

--worktree(短縮形 -w)を渡すだけです。

claude --worktree feature-auth

デフォルトでは、worktree はリポジトリルートの .claude/worktrees/<value>/ の下に、worktree-<value> という名前の新しいブランチ上に作られます。

2つ目の分離セッションは、別のターミナルで違う名前を指定して同じコマンドを再実行するだけです。

名前は省略できます。

claude --worktree

bright-running-fox のような名前が生成されます。

セッション中に Claude に「worktree で作業する」と指示することもでき、その場合は EnterWorktree ツールが使われます。既存の worktree に切り替えるには、.claude/worktrees/ 配下のターゲットパスを指定して EnterWorktree を呼ぶ——前の worktree はディスク上に変更されず残ります。

.gitignore.claude/worktrees/ を追加することが推奨されています。worktree の中身がメインのチェックアウトで「追跡されていないファイル」として見えてしまうのを防ぐためです。

承認とトランスクリプトの扱い

セキュリティ面で重要な仕様が2つあります。

.claude/worktrees/ の外のパスに入ると、最初に承認を求められます。理由が明確で——セッションの作業ディレクトリ、書き込みアクセス、CLAUDE.md や設定などのプロジェクト設定を、その場所に移動するからです。そしてこの承認は回避しにくいEnterWorktree の権限ルールでも「今後は聞かない」でもスキップされず、bypassPermissions モードだけがスキップします。v2.1.206 より前は、既存の worktree パスに承認なく入れていました。

v2.1.198 以降、worktree に出入りするとセッショントランスクリプトがそのディレクトリのプロジェクトストレージに再配置されます/cd と同じ扱い)。おかげで**/desktop--resume がその後そこでセッションを見つけられます。ただしWorktreeCreate フックで作られた worktree は除外され、トランスクリプトは起動ディレクトリに留まります。**

サンドボックスとの関係も明記されています。worktree はサンドボックス有効の状態で動作し、サンドボックスはメインリポジトリの共有 .git ディレクトリへの書き込みを許可するので、リンクされた worktree の中から git commit などがリファレンスとインデックスを更新できます。

起動失敗時の挙動も改善されています。worktree ディレクトリに入れない場合(WorktreeCreate フックがディレクトリ以外を出力した、セットアップ後にディレクトリが消えた、など)、パスを名指しするエラーを出してコード1で終了。****v2.1.205 より前はセッションをクラッシュさせ、-p では約30秒スタールしてからコード0で終了していました——静かに成功したように見える最悪のパターンです。

プラグインについても朗報があります。メインチェックアウトからプロジェクトスコープでインストールしたプラグインは、同じリポジトリの worktree でも読み込まれるので、worktree ごとの再インストールは不要(v2.1.200 以降。--worktree で作っても git worktree add で作っても同じ)。

ベースブランチの選び方

デフォルトは**origin/HEAD(リポジトリのデフォルトブランチ)からのブランチ**で、リモートと一致するクリーンなツリーから始まります。

鮮度の管理が細かい。過去24時間にフェッチしていなければ、Claude Code はデフォルトブランチのフェッチで origin/HEAD を更新します(5秒でキャップ、失敗したらローカルキャッシュのリファレンスを使用)。リモートが未設定、または origin/HEAD がローカルにもなくフェッチもできない場合は、現在のローカル HEAD にフォールバック。この自動更新は v2.1.208 以降で、それ以前は既にキャッシュされていた origin/HEAD をそのまま使っていました。

常にローカル HEAD から分岐させたいなら設定します。

{
  "worktree": {
    "baseRef": "head"
  }
}

"head" にすると、新しい worktree はプッシュされていないコミットと機能ブランチの状態を保持します。用途も明示されていて——「進行中の作業の上で動く必要がある subagent を分離する場合に便利」。

そして地味に重要な解決規則:セッションがリンクされた worktree 内で実行されている場合、"head" はメインチェックアウトの HEAD ではなく、その worktree の HEAD に解決されます。

受け付ける値は "fresh""head" のみで、任意の git ref は指定できません。

PR からブランチするのは1コマンドです。

claude --worktree "#1234"

**origin から pull/<number>/head をフェッチし、.claude/worktrees/pr-<number> に worktree を作ります。**完全な GitHub PR URL も渡せます。

作成方法を完全に制御したいなら WorktreeCreate フック——デフォルトの git worktree ロジックを丸ごと置き換えます。

名前を再利用したときの挙動

既にディレクトリが存在する worktree 名を再利用すると、その worktree が再開されます。

ただし3条件すべてを満たすと、古いチップで再開せず現在のベースにリセットされます。

  1. コミットされていない変更も追跡されていないファイルもない
  2. Claude Code が作成したブランチ上にまだいる
  3. 一度もコミットしていないか、PR がマージされてリモートブランチが削除された

v2.1.208 より前は、再利用した名前は常に古いチップで再開していました。この変更のおかげで、使い終わった名前を再利用しても古い状態を引きずらないようになっています。

gitignore されたファイルを持ち込む

**worktree は新しいチェックアウトなので、.env.env.local のような追跡されていないファイルは存在しません。**これが実務で最初に困る点です。

プロジェクトルートに .worktreeinclude を置けば自動コピーされます。

.env
.env.local
config/secrets.json

.gitignore 構文を使い、安全装置が組み込まれています——パターンに一致し、かつ gitignore されているファイルのみがコピーされるので、追跡されているファイルが複製されることは決してありません。

適用範囲は3つ:--worktree で作った worktree、subagent の worktree、デスクトップアプリの並列セッション。

subagent を worktree で分離する

Claude に「エージェント用に worktree を使う」と指示するか、カスタム subagent の frontmatter に isolation: worktree を付けて永続設定します。

各 subagent が一時的な worktree を取得し、変更なしで完了すれば自動削除。

ベースブランチは --worktree と同じ規則です——worktree.baseRef"head" でない限り、リポジトリのデフォルトブランチから分岐します。前述の「進行中の作業の上で動く subagent」というユースケースがここに繋がります。

クリーンアップ

終了時の扱いは変更を加えたかどうかで3分岐します。

  • コミットされていない変更も追跡されていないファイルも新しいコミットもないworktree とブランチは自動削除。ただしセッションに名前が付いている場合はプロンプトが出るので、後で使うために残せます。
  • いずれかが存在する:**保持するか削除するかを聞かれます。**保持すればディレクトリとブランチが残り後で戻れる。削除すると worktree ディレクトリとブランチが消え、コミットされていない変更・追跡されていないファイル・コミットがすべて破棄されます。
  • 非対話実行-p--worktree で作った worktree は、終了プロンプトがないので自動クリーンアップされません。git worktree remove で削除。

自動スイープの対象も明確に線引きされています。Claude が subagent とバックグラウンドセッション用に作った worktree は、cleanupPeriodDays より古く、かつコミットされていない変更・追跡されていないファイル・プッシュされていないコミットがなければ自動削除されます。**一方、--worktree で自分が作った worktree は、このスイープで削除されることはありません。**自分の作業が勝手に消えない設計です。

同時実行の保護もあります。エージェントが実行中の間、Claude は worktree に git worktree lock をかけるので、**同時実行のクリーンアップが削除できません。****ロックはエージェント完了時に解放。**スイープが残した worktree を消すなら git worktree remove(変更や未追跡ファイルがあれば --force)。

Windows 固有の修正が1つ、これはかなり重い内容です。worktree を削除する前に、Claude Code はその内部の任意の深さにある NTFS ジャンクションやディレクトリシンボリックリンクを「リンクエントリとして」削除するので、**worktree を消してもリンク先のファイルは消えません。**v2.1.205 より前はトップレベルのリンクしかリンクエントリとして扱っていなかったため、サブディレクトリにネストしたジャンクションを含む worktree を削除すると、worktree の外にあるリンク先ディレクトリの中身が削除されうる——データ消失事故です。Windows で使うなら v2.1.205 以降が必須と考えるべきでしょう。

手動で管理する

場所とブランチ設定を完全に制御したい場合——特定の既存ブランチをチェックアウトしたい、worktree をリポジトリの外に置きたい——は git を直接使います。

操作コマンド
新しいブランチで作成git worktree add ../project-feature-a -b feature-a
既存ブランチから作成git worktree add ../project-bugfix bugfix-123
その worktree で Claude を起動cd ../project-feature-a && claude
一覧git worktree list
削除git worktree remove ../project-feature-a

注意点として明記されているのは、各 worktree で開発環境を初期化し直すこと——依存関係のインストール、仮想環境のセットアップ、その他プロジェクトのセットアップに必要なもの.worktreeinclude がカバーするのはファイルのコピーまでで、npm install はしてくれません。

git 以外のバージョン管理

WorktreeCreateWorktreeRemove のフックでカスタムロジックを差し込みます。

次はstdin から worktree 名を読み、新しい SVN 作業コピーをチェックアウトし、ディレクトリパスを出力する例です。この出力パスを Claude Code がセッションの作業ディレクトリとして使います。

{
  "hooks": {
    "WorktreeCreate": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'NAME=$(jq -r .name); DIR=\"$HOME/.claude/worktrees/$NAME\"; svn checkout https://svn.example.com/repo/trunk \"$DIR\" >&2 && echo \"$DIR\"'"
          }
        ]
      }
    ]
  }
}

svn checkout の出力を >&2 で stderr に送り、echo "$DIR" だけを stdout に出しているのがポイントです。stdout がディレクトリパスとして解釈されるので、余計な出力を混ぜられません。

**セッション終了時の後始末には WorktreeRemove フックとペアにします。**そして再掲になりますが、フックを使うと .worktreeinclude は処理されないので、ローカル設定ファイルのコピーはフックスクリプト内で行う必要があります。

4. まとめ + 次回予告

  • worktree はファイル編集を分離する。subagent と agent team は作業を調整する——役割が違い、組み合わせられる。
  • claude --worktree <name>.claude/worktrees/<name>/worktree-<name> ブランチを作って起動。名前を省くと自動生成。
  • .claude/worktrees/.gitignore に入れる。
  • その外のパスに入ると必ず承認を求められる(作業ディレクトリ・書き込み権限・プロジェクト設定が移動するため)。権限ルールでも「今後は聞かない」でもスキップできず、bypassPermissions のみ。
  • 初回のインタラクティブ利用前に、そのディレクトリで一度 claude を実行して信頼ダイアログを受け入れる必要がある(-p は例外)。
  • ベースは origin/HEAD24時間以内にフェッチしていなければ5秒キャップで自動更新、失敗時はキャッシュ、リモートが無ければローカル HEADworktree.baseRef: "head" で常にローカル HEAD から分岐(値は "fresh""head" のみ)。
  • claude --worktree "#1234" で PR から worktree を作れる。
  • .worktreeinclude で gitignore されたファイルをコピーできる。追跡されているファイルは決して複製されない。
  • subagent は isolation: worktree で分離でき、変更なしなら自動削除
  • クリーンアップは変更の有無で3分岐。**-p で作ったものは自動削除されない。**自動スイープは subagent とバックグラウンドセッションの worktree だけが対象で、--worktree で作ったものは対象外。
  • Windows のネストしたジャンクション問題は v2.1.205 で修正済み——それ以前はworktree 外のディレクトリの中身が消えうる
  • 手動管理は git worktree add/list/remove。各 worktree で開発環境の初期化は自分でやる。
  • 非 git VCS は WorktreeCreate / WorktreeRemove フック。ただし.worktreeinclude は効かなくなる。

次回予告(暫定):このページが「アプローチの比較」として挙げている**Claude を並列で実行する(agents)**を取り上げ、worktree・subagent・agent team・バックグラウンドセッションといった並列化手段の使い分けを扱う予定です。


この記

よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました