Claude Codeでブランチをまたぐセッションはどう扱われるか
セッションはgitブランチではなく作業ディレクトリに紐づきます。ブランチを切り替えても会話が続く理由と、ブランチごとに独立させたいときにワークツリーが要る理由を仕様から追います。
Claude Codeのセッションは何に紐づいているか
Claude Codeのセッションが紐づく単位は、gitブランチではなく作業ディレクトリです。会話のトランスクリプトは~/.claude/projects/<project>/<session-id>.jsonlに保存されます。<project>部分は、作業ディレクトリのパスをそのまま変換した文字列です。ブランチ名はこのパスのどこにも登場しません。
この構造が効いてくるのは、同じディレクトリの中でgitブランチだけを切り替えたときです。ディレクトリが変わらない限り、Claude Codeにとっては同じセッションのままです。ブランチが変わっても、保存先のトランスクリプトファイルは同じものが使われ続けます。
gitブランチを切り替えると会話はどうなるか
作業ディレクトリの中でgit checkoutやgit switchを実行してブランチを切り替えても、セッションは終了しません。Claudeが見るファイルの中身は新しいブランチのものに変わりますが、それまでの会話履歴はそのまま残ります。ブランチを切り替えた後も、切り替え前に話していた内容をClaudeは覚えています。
会話は連続していても、足元のファイルは別物になっています。ここが実務上のつまずきどころです。ブランチAで「この関数を直して」と頼んだ直後にブランチBへ切り替えると、会話の文脈は関数Aの話のまま続きますが、実際にディスク上にある関数はブランチBのバージョンです。Claudeが過去の発言をもとに存在しないコードや別内容のコードを参照してしまう可能性が生まれます。1つのセッションで複数ブランチを行き来する運用では、ブランチを切り替えた直後に「今のブランチの状態を確認して」と一言添えると、この食い違いを防げます。
セッションピッカーはブランチをどう扱うか
セッションはディレクトリ単位で保存されますが、Claude Codeのセッションピッカー(/resumeやclaude --resume)は表示のレイヤーでブランチを扱えるようにしています。ピッカーの各行には、そのセッションの直近の活動時刻・ファイルサイズと並んでgitブランチが表示されます。ここでCtrl+Bを押すと、今いるブランチのセッションだけに絞り込めます。もう一度押すと全ブランチの表示に戻ります。
| 操作 | 効果 |
|---|---|
| 既定の一覧 | 効果現在のワークツリーのセッション + /add-dirで現在のディレクトリを加えた他所発のセッション |
Ctrl+B | 効果現在のgitブランチのセッションだけに絞り込む(再度押すと解除) |
Ctrl+W | 効果同じリポジトリの全ワークツリーへ表示を広げる |
Ctrl+A | 効果このマシン上の全プロジェクトへ表示を広げる |
保存の単位はディレクトリでも、探すときはブランチで絞り込める。この二層構造が、ディレクトリに紐づく仕組みを保ったまま「今のブランチに関係する会話だけ見たい」という需要に応えています。/resumeのピッカー操作全般はClaude Codeの/resumeコマンドで過去の会話を再開するに詳しくまとめています。
ブランチごとに独立したセッションを持つには何が要るか
ここまでの仕組みは、1つの作業ディレクトリの中でブランチを切り替えても会話を引き継げることを意味します。裏を返せば、ブランチAとブランチBで完全に独立したセッションを同時に走らせたい場合、ディレクトリを切り替えるだけでは実現できません。同じディレクトリはどの瞬間も1つのブランチしかチェックアウトできないためです。
これを実現する手段がワークツリーです。ワークツリーはブランチごとに別々の作業ディレクトリを作る仕組みで、ディレクトリが分かれれば、セッションもディレクトリ単位で自動的に分かれます。ブランチAのワークツリーとブランチBのワークツリーでそれぞれClaude Codeを起動すれば、2つの会話は最初から別のトランスクリプトとして保存され、互いのファイル変更にも干渉しません。ワークツリーの作り方・baseRefの選び方・依存関係の扱いはClaude Code Worktree実践ガイドが扱っています。
ワークツリーごとセッションを再開するときの挙動
ワークツリーで隔離していたセッションを再開すると、Claude Codeはそのワークツリーへ自動的に戻ります。対話モードだけでなく、-pでの--continue / --resumeやAgent SDK経由の再開でも同じです。ただし戻る前に、そのワークツリーが今も本体のチェックアウトとは別物であることをgitのメタデータから確認します。
この確認が通らない、あるいはワークツリー自体が削除済みだった場合の挙動は状況によって分かれます。
| 状況 | 再開時の挙動 |
|---|---|
| ワークツリーのディレクトリが削除済み | 再開時の挙動起動したディレクトリでセッションを続行し、ワークツリーとの紐づけを解除する |
| 起動元からワークツリーであることを保証できない(多くは、ワークツリーの内側から起動した場合) | 再開時の挙動紐づけは保持したまま、隔離なしで続行する |
| ワークツリーの安全性を確認できない(一時的な要因の可能性があり、再試行の余地を残す) | 再開時の挙動起動したディレクトリで隔離なしに続行し、紐づけ自体は保持する |
| ワークツリーとして不適格と判定 | 再開時の挙動紐づけを解除し、隔離なしで続行する |
対話モードはこの表の挙動で続行しますが、-pやAgent SDK経由の再開は事情が異なります。ワークツリーのディレクトリが削除済みだった場合を除き、上表のいずれの状況でも再開そのものをstderrエラーで中止します。バッチ実行やSDK統合でワークツリー再開を組み込む場合は、削除以外の失敗パターンでプロセスが止まる前提で設計する必要があります。
いずれのケースも、対話モードで続行する限りセッション自体が消えることはありません。ワークツリーという隔離の皮が剥がれても、会話とトランスクリプトはディレクトリ単位の保存の下で生き続けます。ワークツリーが分離しているあいだは、Claude Codeが本体のチェックアウトへのファイル編集・作業ディレクトリの越境・gitのリダイレクトを機械的にブロックする仕組みも働きます。
名前を付けたセッションはワークツリーをまたいで見つかる
ブランチをまたいだ探索は、ピッカーの絞り込みだけではありません。セッションに名前を付けておくと、claude --resume <name>や/resume <name>はリポジトリとその全ワークツリーにまたがって完全一致を検索します。今いるワークツリーが違っても、名前さえ一致すれば直接そのセッションを再開できます。
これは保存の単位がディレクトリであることの裏返しでもあります。名前という識別子を挟むことで、どのディレクトリ・どのブランチで作業していたかを覚えていなくても、目的のセッションへ一直線に戻れます。名前を付けていないセッションにも、実は2種類のラベルがあります。作業ディレクトリ名から自動生成される既定の表示名と、会話の内容からAIが生成するタイトルです。既定の表示名はclaude --resumeや/resumeの名前解決には使えませんが、AI生成タイトルは/renameで明示的に付けた名前と同じように解決の対象になります。複数ブランチを行き来する運用では、/renameで名前を固定しておくほうが取り違えのリスクが小さくなります。
つまずきやすい場面
複数ブランチを1つのディレクトリで行き来する運用には、いくつか見落としやすい落とし穴があります。
会話の文脈とファイルの中身がずれる問題は前述のとおりですが、これはコミット前の未保存の変更でも同様に起きます。ブランチAで編集中のファイルをコミットせずにブランチBへ切り替えると、gitの通常の挙動としてその変更は持ち越されるか、切り替え自体がブロックされます。どちらになるかはgitの動作次第で、Claude Codeのセッションの仕組みとは関係がありません。切り替え前に変更をコミットするかスタッシュしておく判断は、セッションを使っていないときと同じです。
もう1つは、/loopで始めたセッションがセッションピッカーの一覧から外れる挙動です。最初のプロンプトが/loopだったセッションはclaude --continueでも飛ばされ、ピッカーにも表示されません。ブランチを何度も切り替えながら定期実行タスクを仕込んでいる場合、そのセッションだけが一覧に出てこないことに戸惑うことがあります。これは/loop固有の仕様であり、ブランチをまたいだことによる不具合ではありません。
なぜディレクトリ単位という設計なのか
この設計は、2つの相反する要求を両立させるための選択に見えます。ブランチを切り替えるだけの軽い作業では会話を保ちたい一方、複数ブランチを本気で並行させるときは完全な隔離が欲しいという要求です。セッションをブランチに直接紐づけていたら、ちょっとブランチを切り替えるたびに新しい会話が始まってしまい、直前までの文脈を都度失うことになります。逆にすべてのセッションをディレクトリだけに閉じていたら、並行作業をしたい人は自分でディレクトリを増やす手間から逃れられません。
ディレクトリを基本単位にしつつ、ワークツリーという明示的な操作でだけ本当の隔離を得られるようにする。この二段構えが、日常的なブランチ切り替えの手軽さと、並行開発の安全性を両方とも成立させています。
隔離が始まったあとの実効性も仕組みで支えられています。ワークツリー内のセッションが本体のチェックアウトへファイル編集を試みる、あるいは作業ディレクトリの外へ出るコマンドを実行するとします。gitの操作先を本体側へリダイレクトする場合も含め、こうした越境はすべて機械的にブロックされます。
ブランチをまたぐ会話の連続性と、ブランチを分けた並行作業の隔離性は、どちらも仕組みの側が担保しています。使う側が気をつけて運用しなくても壊れにくい設計です。
よくある質問
同じディレクトリで別ブランチのセッションを探せますか
Ctrl+Bでブランチによる絞り込みを解除すれば、同じワークツリー内の全セッションが時系列で並びます。特定のブランチのセッションだけを見たいときにCtrl+Bで絞り込み、全体を見渡したいときに解除する使い方になります。
ブランチを切り替えた後、Claudeは自動で新しい状態を読み直しますか
ファイルの中身はブランチ切り替えと同時に新しいものに変わりますが、Claudeが持つ会話上の文脈は自動更新されません。切り替え直後にコードの現状確認を促す一言を送ると、食い違いを避けられます。
ワークツリーを使わずにブランチを並行して触る方法はありますか
同じディレクトリのまま/branchで会話を分岐させれば、片方のブランチの作業を止めずに別方針を試す使い方はできます。ただしgitのブランチそのものはディレクトリ全体で1つしかチェックアウトできないため、コードの変更履歴まで完全に分けたいなら、最終的にはワークツリーかgitブランチの切り替えが必要になります。
名前を付けていないセッションは別ブランチから探せませんか
探すことはできます。/resumeやclaude --resumeは、/renameで明示的に名前を付けたセッションだけでなく、AIが生成したタイトルを持つセッションについても、ワークツリーをまたいで完全一致で見つけられます。名前解決の対象から外れるのは、作業ディレクトリ名から自動生成された既定の表示名だけです。既定の表示名のまま埋もれているセッションは、Ctrl+AやCtrl+Wでピッカーの表示範囲を広げて目視で見つける形になります。頻繁にブランチをまたいで探したいセッションほど、/renameで名前を固定しておく効果が大きくなります。
セッションが保存されるディレクトリ名の付け方を自分で決められますか
CLAUDE_CONFIG_DIRとCLAUDE_CODE_PROJECT_DIR_NAMEを組み合わせると、名前を自分で選べます。作業ディレクトリのパスから自動生成される名前ではなく、選んだ名前でトランスクリプトを保存できます。ホストアプリケーションにClaude Codeを組み込む用途向けの設定です。
まとめ
Claude Codeのセッションは、gitブランチではなく作業ディレクトリの単位で保存されます。同じディレクトリの中でブランチを切り替えても会話は途切れず、ファイルの中身だけが新しいブランチのものに変わります。この挙動はブランチをまたいだ軽い作業には便利ですが、複数ブランチを本気で並行させたいなら、ディレクトリごと分けるワークツリーが要ります。セッションピッカーは保存の単位こそディレクトリのままに、Ctrl+Bでブランチ単位の絞り込みを提供し、両方の需要を両立させています。