Claude Media
Claude Codeのworktreeはmainへの読み取り専用gitも拒否する

Claude Codeのworktreeはmainへの読み取り専用gitも拒否する

worktree隔離下のセッションはmain checkoutへのgit -Cを読み取り専用でも拒否します。PreToolUse承認やbypassでも通らない理由と、拒否文面の見分け方、現状の回避策を扱います。

worktree隔離下のClaude Codeセッションは、git -C <mainのパス>のようにmain checkoutへ明示的にリダイレクトするgitコマンドを、読み取り専用であっても拒否します。PreToolUseフックで手動承認しても、--dangerously-skip-permissionsを付けても結果は変わりません。この挙動はGitHub Issue #84258で報告され、reproducedラベルが付いています。worktreeの隔離範囲そのものの解説はClaude Code Worktree実践ガイドに譲り、本記事はこの拒否パターンに絞って、原因と見分け方、回避策を扱います。

何が起きるか — エラーメッセージと再現条件

報告者の再現手順はこうです。--worktreeまたはEnterWorktreeで隔離セッションを作り、worktree内でコミットを1つ作成したうえで、main checkoutを指す読み取り専用コマンドを実行します。

git -C /absolute/path/to/main/checkout status --short

これだけで拒否されます。実際に返るメッセージは次の内容です。

git merge --ff-onlyのような本来の目的のコマンドでも同じ拒否が返ります。報告者は、2.1.221までは同じコマンドが通り、2.1.222で拒否されるようになったと書いています。

拒否文面でどのチェックか見分ける

worktree隔離中は、公式ドキュメントが4つのチェックを定めています。

  • ファイル編集がmain checkoutを指すときのブロック
  • Bash・PowerShell・Monitorの作業ディレクトリがmain checkoutに解決されるときのブロック
  • gitをmain checkoutへリダイレクトするコマンドのブロック
  • コマンドの中身が静的に検証できないときのブロック

git -C <main>の拒否に当たるのは3つ目の「Git redirects」です。ドキュメントは対象の手口を、git -C・--git-dir・GIT_DIRまたはGIT_WORK_TREE環境変数・main checkoutへのcd後のgit実行、の4つで挙げています。コマンドが読み取り専用か書き込みかは区別しないので、statusもmergeも同じ扱いです。適用範囲は、Claude Codeを起動したリポジトリと、そこにリンクされたworktreeが指すmain checkoutの両方に及びます。

同じ「拒否」でも、止めているチェックは文面で見分けられます。

くらべる

拒否文面の見分け方

Git redirects

redirects git to the shared checkout via -C

mainを指す-C・--git-dir・環境変数・cdが原因です。コマンドからリダイレクトを外し、worktreeのディレクトリから実行し直すと通ります。

Command shape

too complex to verify

コマンド名が実行時に決まる、構文を解析できない、${!name}のような展開が隠れた命令を実行しうる、のいずれかで出ます。gitをmainに向けていなくても拒否されます。

2つ目の「Command shape」は、ドキュメントが「無効化する手段はない」と明記しているチェックです。エラー一覧のページによれば、gitを名指ししないコマンドでも、変数の間接参照や関数置換を含むと拒否されることがあります。対処はコマンドを単純な別々の行に分け、worktreeの中からgitを実行することです。

Command shapeは偽陽性も出ていた

Issue #84258の追記には、mainに一切触れないコマンドが拒否された例が載っています。worktree内でgit merge-baseの結果を変数に入れ、その変数を後続の$(...)で使う2行のスクリプトです。報告者は、変数をそのままの引数として再利用するか、2つ目の$(...)の中で使うと拒否されると書いています。同じ文字列に埋め込むだけなら通りました。

この種の拒否は、changelogで段階的に絞り込まれてきました。バージョンごとの動きは次のとおりです。

あゆみ

worktree隔離の拒否とその調整

  1. v2.1.216(2026-07-20)サブエージェントのgitリダイレクトを拒否

    worktree隔離下のサブエージェントがgit -C・--git-dir・GIT_DIR/GIT_WORK_TREEでmain checkoutへgitを向ける手口を修正しました。

  2. v2.1.222(2026-08-04)全セッション種別に拡張

    対象がサブエージェントだけでなくセッション本体にも広がり、file editsとBashの両方に適用されます。報告者が「最後に正常動作した」と書くのは、この1つ前の2.1.221です。

  3. 2026-08-05Issue #84258が登録される

    読み取り専用のgit -C <main>が拒否され、PreToolUse承認も効かないという報告です。

  4. v2.1.238(2026-08-20)拒否文面の誤誘導を修正

    リダイレクトの無いコマンドに「リダイレクトを外せ」と案内していた文面が直りました。

  5. v2.1.257・v2.1.259(2026-09-01・09-02)Command shapeの偽陽性を緩和

    gitに触れないループ、$VARの読み取り、"$(…)"、ヒアドキュメントが「too complex」で拒否されなくなりました。xargsやランチャー経由のコマンドも、mainに届かないものは通ります。

  6. v2.1.274(2026-09-17)ネストした展開は拒否側に倒す

    一部のネストしたシェル展開を含むBashコマンドは、拒否されるようになりました。

v2.1.222のリリース全体はClaude Code v2.1.222 — worktree分離をセッション本体まで拡張にまとめています。「全セッション種別」にはバックグラウンドセッションも含まれ、その隔離既定値はworktree.bgIsolationでバックグラウンド編集を直接許可する仕組みで扱っています。

changelogには、Git redirectsのチェックそのものを読み取り専用に限って緩める変更が、v2.1.289まで載っていません。Issue #84258はopenのままです。

PreToolUseでもbypassでも拒否は解除されない

報告者の環境には、ディレクトリをまたぐBashコマンドを検知して承認を求めるPreToolUseフックが設定されていました。フックはこのgit -Cコマンドを検知してユーザーに確認を求め、ユーザーは承認しました。それでもClaude Codeはハードコードされた拒否メッセージを返し、コマンドを実行しませんでした。

Anthropic側のcollaboratorは、v2.1.233で同じ挙動を再現し、「これは現時点で意図された動作でありリグレッションではない」と評価しています。チェックは実行時にパーミッション層とPreToolUseフックより下で働き、--dangerously-skip-permissionsでも変わりません。承認ダイアログで許可できる種類の拒否ではないため、「承認しても無視される」ように見えます。同じ権限システムでは逆方向の調整も進んでおり、/commit-push-prはv2.1.206でgit pushの自動許可先をorigin以外のリモートにも広げています。詳しくはcommit-push-prがpush remoteへのgit pushを自動許可にまとめています。

collaboratorは同じコメントで、現状の不備も認めています。worktreeセッションからローカルのmainを進める、サポートされた手段がないためです。ExitWorktreeの選択肢はkeepとremoveだけです。mainに対する読み取り専用のgitを許す、承認できるプロンプトに回す、「worktreeのブランチをmainへマージする」操作を用意する、のいずれかで直す案が挙がっています。ドキュメントの文言も直す意向です。

PreToolUseフックそのものの仕組みはPreToolUse hookでツール実行前に許可・拒否・改変するにまとめています。

なぜmainへのgit -Cが必要になるのか

worktreeのブランチをmainに取り込むとき、素のgitではworktreeの中からmainへ切り替えられません。mainはメインのチェックアウトで使用中だからです。一時ディレクトリに作ったリポジトリで試すと、次のように止まります(git 2.50.1、パスは省略しています)。

git switch main
# fatal: 'main' is already used by worktree at '<repo>'
git branch -f main worktree-demo
# fatal: cannot force update the branch 'main' used by worktree at '<repo>'
git -C <repo> merge --ff-only worktree-demo
# Fast-forward

マージを完了する経路は、mainのチェックアウトを指す-Cか、そこへ移動してからの実行しかありません。Issueの報告者がgit -C <main> merge --ff-onlyを使っていたのは、この制約によります。隔離チェックが塞いでいるのは、まさにこの経路です。

ドキュメントの「What worktrees share with the main checkout」節には、次の趣旨の記述があります。worktree内のgitコマンドはメインリポジトリの共有.gitディレクトリに書き込み、sandboxingはその書き込みを許可する。だからgit commitはsandbox有効時でもworktree内から問題なく動く、という内容です。これはファイルシステムのsandboxの話で、worktree内で完結するgit commitやgit logは、-Cのような明示的なリダイレクトを伴わないため、Git redirectsの対象になりません。Issueの報告者はこの記述と拒否の食い違いを指摘しており、collaboratorも読み誤りやすい文言だと認めています。

今できる回避策

Git redirectsの拒否を無効化する設定は、公式ドキュメントにもIssueにもありません。エラー一覧のページが挙げる行き先は、mainを対象にするときは「セッションの外のターミナルで自分でコマンドを実行する」ことです。選択肢を並べると次の3つになります。

くらべる

mainを動かしたいときの3つの経路

拒否されない

worktreeの中で完結させる

mainを指さず、worktreeのディレクトリでコマンドを実行します。ただしmainへのマージ自体の代わりにはなりません。

手戻りあり

ExitWorktreeで隔離を抜ける

隔離は「セッションがworktreeにいる間」だけ働くため、keep指定で戻ればmainを操作できます。claude agents経由のセッションでこの手順を使い、うまく回っているという報告がIssueにあります。

公式の案内

別のターミナルで実行する

Git redirectsのチェックはClaude CodeのBash・Monitorツール呼び出しにだけ働くので、ユーザーが自分のターミナルでgit -Cやマージを打つ分には制限されません。

ExitWorktreeで戻る方法には、報告者が避けたい理由があります。mainが並行セッションで先に進んでいるとマージが失敗し、worktreeへ戻って再度リベースする往復が起きます。作業を続けたいときにも不便で、worktreeを手動で削除する手間も生じます。

よくある質問

PowerShellコマンドでも同じ拒否が起きますか

起きません。ドキュメントはPowerShellコマンドについて、4つのチェックのうち作業ディレクトリのチェックだけが適用されると明記しています。Git redirectsチェックの対象はBashまたはMonitorのコマンドです。

サンドボックスの中で動かしていても拒否されますか

拒否されます。Issueには、sbxのサンドボックス内でbypassを使っていても無効にしたいというコメントが付きましたが、無効化の手段は示されていません。collaboratorの説明では、チェックはすべてのパーミッションモードで働きます。

まとめ

worktree隔離下でmainへのgit -Cが止まるのは、承認の有無とは別の層で働く隔離チェックのためです。拒否文面が「via -C」なら、mainへ向けたリダイレクトを外すか、セッションの外のターミナルで実行します。「too complex to verify」なら、コマンドを単純な別々の行に分けると通ることが多く、v2.1.257以降は偽陽性自体も減っています。

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