Claude Media
statuslineでworktreeセッションを表示する — worktree.*フィールドの条件

statuslineでworktreeセッションを表示する — worktree.*フィールドの条件

Claude Codeのstatuslineが運ぶworktree.name/path/branch等5フィールドの出現条件と、workspace.git_worktreeとの違い・非gitのworktreeでの欠落を解説します。

Claude Codeのstatuslineは、セッション自体がworktree内で動いているときだけ、stdinのJSONにworktreeオブジェクトを追加します。フィールドはnamepathbranchoriginal_cwdoriginal_branchの5つです。どのworktreeで何をしているセッションかを、statuslineに常時表示できます。似た名前のworkspace.git_worktreeとは出現条件がまったく違うため、混同すると意図と違う場面でフィールドが空になります。

並列に開いた複数セッションを見分ける手段には/color/renameもあります。ただしこれらはセッションに名前や色を明示的に付ける機能です。worktree単位で動いているかどうかまで含めて自動的に判別したい場合は、statuslineのworktree.*が名前を付ける手間なく直接使えます。

worktree.*workspace.git_worktreeの違い

stdinのJSONには、worktreeに関するフィールドが2系統あります。名前が似ているため実装時に混同しやすいポイントです。

フィールド出る条件
worktree.*(5フィールド)出る条件セッション自体がworktreeセッションのとき。claude --worktreeでの起動・EnterWorktreeでの移動・worktreeセッションのresumeの3経路が対象
workspace.git_worktree出る条件カレントディレクトリがgit worktree addで作った任意のworktree内にあるとき。--worktreeを使わず手動でcdしただけでも値が入る

workspace.git_worktreeは任意のgit worktreeに対して出る汎用フィールドで、値はworktree名の文字列1つだけです。一方worktree.*は、セッション自体がworktreeセッションとして動いているときに使われるworktreeの情報で、パスや元のブランチまで含めた5フィールドを持ちます。対象となるのは--worktreeフラグでの起動・EnterWorktreeによるセッション中の移動・worktreeセッションのresumeの3経路です。詳しくはClaude Code Worktree実践ガイドで扱っています。

worktree.*が運ぶ5つのフィールド

フィールド内容
worktree.name内容アクティブなworktreeの名前
worktree.path内容worktreeディレクトリの絶対パス
worktree.branch内容worktreeに紐づくgitブランチ名(例: worktree-my-feature)。非gitのworktreeでは欠落
worktree.original_cwd内容worktreeに入る前にClaudeがいたディレクトリ
worktree.original_branch内容worktreeに入る前にチェックアウトされていたgitブランチ。非gitのworktreeでは欠落

original_cwdoriginal_branchは、worktreeに入る前のディレクトリとブランチをそれぞれ保持するフィールドです。複数のworktreeを行き来する運用では、この2つを表示に組み込んでおくと、いまのworktreeがどこから移動してきたセッションかをstatuslineだけで確認できます。JSON全体では次の形で渡ります。

stdin JSON(worktree部分の抜粋)
"worktree": {
  "name": "my-feature",
  "path": "/path/to/.claude/worktrees/my-feature",
  "branch": "worktree-my-feature",
  "original_cwd": "/path/to/project",
  "original_branch": "main"
}

worktreeセッションとして扱われる3つの経路

worktreeオブジェクトが現れるのは、セッション自体がworktreeセッションであるときで、次の3つの経路のいずれかが対象です。

  1. claude --worktree <name>(または-w)で起動したセッション本体。既定では.claude/worktrees/<name>/に、worktree-<name>という名前の新しいブランチで作られます
  2. ClaudeがEnterWorktreeツールで別のworktreeへ移動する
  3. worktreeセッションをresumeする

Sub-agentのfrontmatterにisolation: worktreeを指定すると、そのSub-agentは自分専用のworktreeで動きます。ただしこの隔離はSub-agentの実行環境を分けるための仕組みです。Sub-agent側のstatuslineはsubagentStatusLineという別枠のJSON構造(tasks配列)で扱われるため、メインセッションのworktree.*とは対応しません。

セッションを--fork-sessionでforkした場合、フォークされたセッションは元のセッションを起動したディレクトリで始まり、元セッションが使っていたworktreeはそのまま残ります。

非gitのworktreeで欠けるフィールド

WorktreeCreatehookでSVNやPerforceなど非gitのVCSにworktree作成を差し替えている場合、worktree.branchworktree.original_branchは欠落します。gitのブランチという概念自体が、その隔離コピーに存在しないためです。worktree.nameworktree.pathworktree.original_cwdの3つは、隔離の実装がgitかどうかに関わらず出ます。非gitのVCSでworktree作成・削除を差し替える手順はWorktreeCreate/WorktreeRemove hookでworktreeの作成・削除を差し替えるにあります。statusline側で分岐を書くときは、ブランチ系フィールドの欠落を前提にします。

セッション中にworktreeの状態が変わる場面

worktreeオブジェクトはセッション開始時の1回きりの値ではなく、セッションがworktreeセッションであり続けている間だけ出続けます。

ClaudeがEnterWorktreeツールで別のworktreeへ移動する場合があります。移動先がリポジトリの.claude/worktrees/ディレクトリの外にあるときは、Claude Codeが先にユーザーの承認を求めます。EnterWorktreeの権限ルールを許可済みにしていても、あるいは「今後確認しない」を選んでいても、この確認はスキップされません。bypassPermissionsモードのときだけ確認なしで移動します。逆にExitWorktreeツールでworktreeを抜けると、セッションはworktreeセッションでなくなるため、worktreeオブジェクトはそのセッションのJSONから消えます。

resumeしたセッションが元のworktreeへ戻れないケースでも、worktreeオブジェクトは消えます。Claude Codeはresume時にworktreeがまだ隔離されたチェックアウトのままかを検証しており、この検証に失敗すると隔離なしでセッションを継続します。典型的なのはworktreeディレクトリ自体が削除されている場合と、gitメタデータの検証自体が通らない場合の2パターンです。前者は「Your worktree <path> no longer exists」、後者は「Did not re-enter your worktree <path>」というメッセージが出ます。いずれの場合もClaude Codeはそのセッションのworktreeへの紐付けを消去し、stdinのJSONからworktreeオブジェクトそのものが消えます。statuslineの表示は、普段のディレクトリ表示に切り替わります。「さっきまで出ていたworktree名が急に消えた」と感じたら、まずworktreeディレクトリが削除されていないかを確認します。

いつstatuslineスクリプトが再実行されるか

worktree.*の値を含め、statuslineスクリプトはセッション開始時(resume時を含む)に一度実行されます。その後は次のイベントをきっかけに再実行され、表示が更新されます。

  • 新しいアシスタントメッセージが届いたとき
  • /compactが完了したとき
  • パーミッションモードが変わったとき
  • vimモードが切り替わったとき

一方、コーディネーターがバックグラウンドのSub-agentを待っているだけでメインセッションがアイドル状態のときは、これらのイベント駆動の更新が止まります。バックグラウンド側のworktree作業をリアルタイムに近い形で追いたい場合は、refreshIntervalを設定してタイマーでも再実行させる必要があります。

Claude Codeはこれらの更新イベントを300ミリ秒でデバウンスするため、短時間に複数の変化が重なっても、statuslineスクリプトの実行は1回にまとまります。実行中のスクリプトが終わる前に次の更新トリガーが来た場合は、その実行を打ち切って新しい入力で再実行するので、worktreeの値が古いままstdoutに残ることはありません。

statuslineスクリプトへの組み込み例

statuslineの基本設定はClaude Code statuslineの設定と表示項目の選び方にまとめています。ここではworktree.*だけを扱う分岐の書き方を示します。

~/.claude/statusline.sh
#!/bin/bash
input=$(cat)
 
WORKTREE_NAME=$(echo "$input" | jq -r '.worktree.name // empty')
 
if [ -n "$WORKTREE_NAME" ]; then
  BRANCH=$(echo "$input" | jq -r '.worktree.branch // "no-branch"')
  echo "🌳 ${WORKTREE_NAME} (${BRANCH})"
else
  DIR=$(echo "$input" | jq -r '.workspace.current_dir')
  echo "📁 ${DIR##*/}"
fi

worktree.nameはworktreeセッションでないときにnullになるので、// emptyで空文字へフォールバックさせてから-nで判定します。worktree.branchにも// "no-branch"のフォールバックを付けているのは、非gitのworktreeで実行しても行が崩れないようにするためです。並列で複数のworktreeを行き来する運用では、ここにworktree.original_branchを足して「どこから来たセッションか」まで1行に収めることもできます。

この分岐にworkspace.git_worktreeを挟むと、拾えるケースが増えます。worktree.nameが空でもworkspace.git_worktreeに値が入っていれば、--worktreeを使わず手動でcdしただけの任意のgit worktree内にいることが分かります。優先順位はworktree.nameworkspace.git_worktree → 通常のディレクトリ名、の順にフォールバックさせるのが実用的です。jq -r '.worktree.name // .workspace.git_worktree // empty'のように//を連結すれば、この優先順位付きフォールバックを1行で書けます。

gitベースのworktreeと非gitのworktreeを色分けしたいときは、worktree.branchの有無を判定に使えます。branchが空文字なら非gitとみなして黄色のANSIエスケープを、値があれば緑色を添えるといった具合です。

実際にworktreeを作らずに分岐を検証する

この分岐が正しく動くかは、実際にworktreeセッションを起動しなくてもモックのJSONで確認できます。

echo '{"worktree":{"name":"my-feature","branch":"worktree-my-feature","original_cwd":"/path/to/project","original_branch":"main"},"workspace":{"current_dir":"/path/to/.claude/worktrees/my-feature"}}' | ~/.claude/statusline.sh

出力に🌳 my-feature (worktree-my-feature)のような行が出れば、分岐は正しく動いています。JSONからbranchキーを外して同じコマンドを流せば、非gitのworktreeを模したno-branch表示も確認できます。worktreeオブジェクトごと外したJSONを流すと、worktreeセッションでないときの通常表示に戻ります。

まとめ

worktree.*は、複数のworktreeで並列にセッションを走らせているときに効果が出るフィールド群です。任意のgit worktreeで出るworkspace.git_worktreeと混同しないことが出発点になります。非gitのworktreeでbranch系フィールドが欠ける条件、resume失敗時にworktreeオブジェクトごと消えるケース、この2つを踏まえてstatuslineスクリプトを書けば、ターミナルを切り替えるたびにどのセッションを触っているかを一目で判別できます。並列セッションが増えるほど、このひと手間が効いてきます。

この記事を共有:XはてブLinkedIn