複数のIssueをAIエージェントに並行して振ると、git worktreeは正直手放せない。ブランチを切り替えずに何本も同時進行できるので、以前fzfでworktreeとブランチを一括整理する4本のエイリアスやstale lockの自動unlockといった片付け系の話も書いてきた。「増える前提で、片付けの摩擦を減らす」方向でずっと戦ってきたつもりだった。
ところがある日、片付けとはまったく別の壁にぶつかった。worktreeを何十件も登録したまま作業していたら、Bashツールにecho testを投げただけで失敗するようになったのだ。ファイルが多すぎるとかディスクが足りないとかではない。サンドボックスの起動そのものが、コマンドラインの長さで死んでいた(正直、原因を突き止めるまで笑えなかった)。
この記事で学べること
- git worktreeを多数登録した状態でBashサンドボックスが完全停止する
E2BIGの仕組み - OSのコマンドライン長上限(
ARG_MAX)とサンドボックスのdeny/allowパスリストがなぜ衝突するのか - 一度発生すると、そのセッションのBashがもう使えなくなる理由と、セッション内では直せない理由
- 定期的な棚卸しで予防する方法
前提条件
- git worktreeを使って複数ブランチを並行開発している(AIエージェント経由でも手動でも)。とくにローカルで複数のAIコーディングツールを同時に走らせている場合、ブランチ分離だけでは足りずworktreeが必須になりやすい(気づけば10本、20本と積み上がっているやつだ)
- macOSのSeatbeltやLinuxのbubblewrap/landlockなど、パスベースの許可/拒否リストでコマンド実行を隔離するsandbox機構を使っている
- そのsandboxが、コマンド実行のたびにOSの
exec系システムコールを新規に呼び出す方式である
何が起きたか
実際に踏んだ症状はこうだ。ある無人実行タスクの最中、git worktree listのような軽いコマンドは通る。ところがその直後、echoで環境変数を確認しようとしただけで、次のエラーで即死する。
Could not start /bin/zsh: the command line plus environment exceed the OS exec argument limit (E2BIG)
一度この状態に入ると、pwdすら通らなくなる。ファイル読み書きもgit操作も、文字通り何も実行できないまま、そのセッションのBashは詰む。以前Claude Codeのhookを入れて開発が止まったときの切り分け方を書いたことがあるが、あれはhookの暴発や無限ループというロジック層の話だった。今回はhookもロジックも一切関係ない、OSのexecそのものが失敗している点が根本的に違う。
厄介なのは、直前まで動いていたという「実績」が何の保証にもならないことだ。直前のコマンドは健全なはずなのに、同じセッションの中で動く→動かないに突然切り替わる。事前にコマンドの成否だけを見て安全性を予測できるだろうか。答えは、できない。
なぜ起きるのか
原因はOSレベルのコマンドライン長制限、いわゆるARG_MAXだ。Unix系OSのexec系システムコール(execveなど)は、渡す引数(argv)と環境変数(envp)の合計サイズにカーネルレベルの上限を設けている。これを超えてexecしようとすると、カーネルはE2BIGというエラーコードを返す。値そのものはOS・カーネルのバージョンによって違うので、自分の環境の目安はPOSIX標準コマンドのgetconf ARG_MAX(Linux/macOS共通)やsysctl kern.argmax(macOS)で確認できる。
Bashをsandbox化する仕組みは、多くの場合「どのパスへの読み書きを許可・拒否するか」というルールをプロファイルとして生成し、コマンド実行のたびにそのプロファイルを引数として渡す。実際、このリポジトリで以前公開したBash sandboxのegress隔離とsecretマスクの記事でも、macOS Seatbeltを活用してuntrusted codeのnetwork egressを許可リストベースで制限する仕組みを扱っている。パスの許可・拒否リストをコマンド実行のたびに引数として渡す設計自体は、この手のsandboxではめずらしくない。
問題は、git worktreeを1つ登録するたびに、そのworktree配下のパス(.envやエージェントのローカル設定ファイルなど)がプロファイルの拒否リストに個別追加されていく設計になりやすいことだ。worktreeを作るたびに.envや設定ファイルを自動でコピー・生成する仕組みを組んでいる場合はなおさらで、コピー先のパスもろとも拒否リストに乗る。プロファイルはworktreeの登録数にほぼ比例して肥大化する。あるところで、実行しようとしているコマンド本体+環境変数+肥大化したプロファイルの合計がARG_MAXを超え、それ以降はecho一つ実行できなくなる。
発生条件は当てにならない
「worktreeが何件になったら危険か」を知りたくなるが、実際に自分の手元で計測・記録した観測結果はこうだった。
| 観測タイミング | 登録worktree数(git worktree list実測) | 症状 |
|---|---|---|
| 1回目 | 27件 | echo testすら即失敗。無人実行タスクが全工程で停止 |
| 2回目(2日後) | 11件 | git worktree listは成功したが、直後のechoから突然全滅 |
実測値としては27件と11件、両方で同じ障害が起きている。しかも2回目は、同一セッションの中で「直前のコマンドは通った」直後に壊れている。件数のしきい値は再現の下限を示すものではなく、単なる過去の観測値でしかない。「今のところ動いているから大丈夫」という判断は、この障害に関しては通用しない(信頼できない目撃証言、というやつだ)。
復旧手順
一度E2BIGが出たセッションは、そのセッション内では直せない。理由は単純で、復旧のためのコマンド(git worktree removeやprune)自体もBash経由のexecを必要とし、それがまた同じ理由で失敗する。壊れたツールで壊れたツールを直そうとしている、というやつなんですけど、堂々巡りにしかならない。
復旧は次の手順になる。
- 別のターミナル(サンドボックス化されていないシェル、または新規セッション)を開く
- 不要なworktreeを削除する
git worktree list
git worktree remove <path>
git worktree prune
- 元のAIエージェントのセッションを再起動する
セッションを再起動せずにそのまま使い続けようとしても、サンドボックスのプロファイルは古いセッションの状態を引きずっているので直らない。worktreeを減らした上で、必ずセッションごと切り直す必要がある。
予防策
復旧より安いのは、この状態に入らないことだ。Issueやタスクごとに新しいworktreeを切ってPRを出す運用は、開発が活発なほど自然に採用される形だが、活発であればあるほど後片付けを1回でも忘れた分がそのまま積み上がる。実際、このリポジトリの直近のコミット履歴を見ても、数日おきにマージが連続している時期があり、その裏では同じ数だけworktreeが作られては消し忘れられている、というのが実感に近い。
- 定期的な棚卸し:
git worktree list | wc -lで件数を定点観測し、閾値を決めて機械的にpruneする。しきい値は当てにならないと分かった以上、「少なければ少ないほど安全」というシンプルな方針にする - 無人実行タスクの前提チェック: 夜間バッチのような無人実行の直前にworktree件数を確認し、多ければ実行前に警告か中断をする(実行中に壊れると復旧不能なので、事前に弾く方が安い)
- マージ済みworktreeは即削除する運用にする: 溜め込んでから一括整理するのではなく、PRがマージされた時点で削除まで一連の作業として終える(「あとでまとめて」が一番危ない発想だった)
動作確認
読者の手元でも、次のコマンドで自分の環境のリスクを確認できる。
# OSのコマンドライン長上限の目安を確認(Linux/macOS共通)
getconf ARG_MAX
# 現在登録されているworktree数を確認
git worktree list | wc -l
# 環境変数のサイズを確認(これもargvと合算される)
env | wc -c
# マージ済み・不要なworktreeを安全に削除する(削除前にdry-runで対象確認)
git worktree list --porcelain
git worktree prune --dry-run
getconf ARG_MAXで出てくる数値はあくまで目安で、実際に1コマンドの実行で使える上限はそれより小さいことが多い。手元の数値を鵜呑みにせず、worktree件数が増えてきたら早めにpruneする習慣をつけるほうが確実だ。
注意点・Tips
E2BIGが出たら即座に別ターミナルへ切り替える: 同じセッション内で粘っても、pwdのような最小コマンドすら通らない状態からは復帰できない(粘るだけ時間の無駄、というのを身をもって学んだ)- 無人実行パイプラインでは事前ガードを入れる: 実行中に壊れると、その回の処理は丸ごと失敗して人手での再実行が必要になる。壊れてから気づくのではなく、壊れる前に検知する設計にしておきたい
- この障害モードはClaude Code固有ではない: パスベースの許可・拒否リストをコマンド実行のたびに引数として渡す方式のsandboxであれば、同じ理屈で
ARG_MAXにぶつかりうる。sandbox化されたAIエージェントツールでgit worktreeを複数並行運用している場合は、ツールが変わっても構造的なリスクとして頭に入れておく価値がある
まとめ
git worktreeの並列運用は便利だが、増やせば増やすほど、サンドボックスが内部で保持する許可・拒否リストも一緒に膨らんでいく。ある日それがOSのコマンドライン長上限を超えると、最小コマンドすら実行できないままセッションが詰む。しかも詰んだセッションの中では直せない。復旧は外のターミナルからのgit worktree削除とセッション再起動、予防は定期的な棚卸しだ。あなたの環境でも、sandbox化された開発ツールでworktreeを何本も並行運用しているなら、一度git worktree list | wc -lを叩いて件数を確認しておく価値はある。壊れてから知るのと、壊れる前に知るのとでは、対応にかかる時間がまるで違う(後者はコマンド一発、前者は別ターミナル探しから始まる)。



