CLAUDE LABEN
FORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられていますFORK — Claude Code 2.1.212で/forkの挙動が変わりました。会話を新しいバックグラウンドセッションへ複製し、作業を続けたまま並走できます。従来のセッション内サブエージェントは/subtaskに移りましたLIMITS — WebSearchの呼び出しがセッション単位で既定200回に制限されました。サブエージェントの起動も既定200回が上限で、暴走した検索・委譲のループを止められますMCPBG — 2分を超えるMCPツール呼び出しは自動的にバックグラウンドへ移り、セッションが固まらなくなりました。しきい値はCLAUDE_CODE_MCP_AUTO_BACKGROUND_MSで調整できますPLANFIX — プランモードがtouchやrmといったファイルを変更するBashコマンドを、許可プロンプトもcanUseToolコールバックも通さずに実行してしまう不具合が修正されましたSONNET5 — Claude Sonnet 5は導入価格として入力100万トークンあたり2ドル、出力10ドルで提供中です。8月31日を過ぎると3ドルと15ドルに戻りますIPO — Anthropicが早ければ10月の株式公開を視野に、引受銀行が投資家との面談を組み始めたと報じられています
記事一覧/Claude Code
Claude Code/2026-04-25中級

Claude Code の git 操作が `index.lock` で詰まる時、VM・CI 環境で必ず効く3つの回避策

Claude Code が VM や CI 環境で git add や git commit を実行した時に `Unable to create '.git/index.lock'` で停止する問題の根本原因と、現場で効く3つの回避策を解説します。

claude-code129git16troubleshooting61vmci2lock

「Claude Code に git push までお願いしたら、fatal: Unable to create '.git/index.lock': File exists. で止まったまま動かない」——この症状は私も自動化スクリプトを書き始めて最初に踏んだ落とし穴でした。ローカル環境ではまず再現しないのに、VM や Docker、CI のサンドボックスに入れた途端に発生します。

このエラーの厄介なところは、画面上は「ロックファイルを消せばいい」と書かれているのに、消しても次のコマンドでまた同じ場所で止まることです。原因は単一ではなく、所有権・前回プロセスの残骸・ファイルシステムの遅延 という3つの層が重なって発生しているケースがほとんどです。

私は同じ症状を Cowork mode のスケジュールタスクで何度も踏み、最終的に「ロックファイルと戦わない」設計に切り替えて解決しました。ここではその経験を踏まえて、VM・CI 環境で再現性の高い3つの回避策を順番に紹介します。

なぜ Claude Code の git 操作だけが詰まるのか

ローカルの開発機で同じコマンドを叩いても発生しないため、つい「Claude Code のバグ」と疑いたくなります。しかし実際には Claude Code は内部で git コマンドをそのまま呼んでいるだけで、ロック競合の原因はほぼ環境側にあります。

代表的な原因は次の3つです。

  • 所有権のズレ: VM やコンテナの /tmp や作業ディレクトリが nobody:nogroup のような特殊な所有者で作成されており、Claude Code が動かしているユーザー(多くは root か通常ユーザー)から書き込めない
  • 前回 bash セッションのゾンビプロセス: bash ツールの呼び出しは独立したセッションで動くため、前回の git commit が完了せずに終了した場合、ロックファイルだけが残る
  • ファイルシステムの flush 遅延: シャドウマウントやネットワークボリューム上で rm を実行しても、次の git コマンドからはまだファイルが見える瞬間がある

特に Cowork mode のように毎回新しい bash セッションが立ち上がる環境では、2 つ目の「ゾンビプロセスの残骸」が一番頻繁です。サンドボックスの制約上、ps でプロセスを掃除する権限がないため、対症療法的に rm で消す形になります。

回避策1: ロックファイルを安全に消してから再実行する

最初に試すべきは、.git/index.lock.git/HEAD.lock をまとめて削除してから git の状態をリセットする方法です。Claude Code に頼むなら、コミットの前段に必ず以下を挟むようにしてください。

# 1. ロックファイルが存在しても無視して削除
find .git -maxdepth 2 -name "*.lock" -type f -delete 2>/dev/null
 
# 2. 不整合な index を強制リセット
git reset --mixed HEAD 2>/dev/null
 
# 3. ファイルシステムの flush を待つ(NFS / シャドウマウント対策)
sync
sleep 1
 
# 4. 通常通りコミット
git add content/
git commit -m "Add: 新着記事"

find*.lock を一括削除しているのは、index.lock だけでなく HEAD.lockrefs/heads/main.lock も同時に残っていることがあるためです。-maxdepth 2.git/objects/ 配下の正常なロックを巻き込まないようにしている点もポイントです。

このパターンは、ローカル開発と同じスクリプトを Claude Code に渡したい場合に最小の変更で済みます。週に数回起きる程度の散発的な症状ならこれで十分です。

回避策2: 作業ディレクトリを書き込み可能なホームに移す

「ロック削除を挟んでも翌日また同じところで止まる」場合、/tmp/repos の所有権そのものが書き込み不可になっている可能性が高いです。VM が再起動するたびに /tmp がクリアされ、別のプロセスが先にディレクトリを作成してしまうことがあるためです。

私は最終的に、/tmp 配下が使えない時のフォールバック先として $HOME/repos を用意しました。クローンの直前に書き込みテストを入れると、原因不明の停止がほぼゼロになります。

WORK="/tmp/repos/myproject"
 
# 書き込みテスト: 失敗したら $HOME/repos にフォールバック
mkdir -p "$(dirname "$WORK")" 2>/dev/null
if ! touch "$(dirname "$WORK")/.write_test" 2>/dev/null; then
  echo "⚠️ /tmp/repos が書き込み不可 — $HOME/repos にフォールバック"
  WORK="$HOME/repos/myproject"
  mkdir -p "$HOME/repos"
fi
rm -f "$(dirname "$WORK")/.write_test" 2>/dev/null
 
# 以降、$WORK を作業ディレクトリとして使う
git clone --depth 1 "$REPO_URL" "$WORK"
cd "$WORK"

この設計の効きどころは、VM が再起動して /tmp/reposnobody 所有で作成されてしまった日だけ自動でホームに切り替わることです。私は Claude Code の Bash ツール実行エラーの修正方法 と組み合わせる形で運用していて、サンドボックスの状態に依存しない自動化が安定して動くようになりました。

回避策3: そもそもローカル git を経由せず GitHub REST API で push する

ロック削除でもダメ、フォールバックでもダメな環境(極端にディスクが逼迫している、git バイナリが古い、など)では、私はローカル git 自体を諦めて GitHub REST API で直接 push する方式に切り替えました。コードは少し長くなりますが、.git/index.lock の存在しない世界に行けるので、ロック競合が原理的に起こりません。

# 環境変数: GITHUB_TOKEN, OWNER, REPO, BRANCH=main
TOKEN="$GITHUB_TOKEN"
OWNER="masakihirokawa"
REPO="myproject"
BRANCH="main"
API="https://api.github.com/repos/${OWNER}/${REPO}"
 
# 1. ファイル内容を base64 で blob として登録
CONTENT=$(base64 -w0 < content/articles/ja/sample.mdx)
BLOB_SHA=$(curl -sS -X POST -H "Authorization: token $TOKEN" \
  -d "{\"content\":\"${CONTENT}\",\"encoding\":\"base64\"}" \
  "${API}/git/blobs" | jq -r .sha)
 
# 2. 現在のブランチの tree SHA を取得
PARENT_SHA=$(curl -sS -H "Authorization: token $TOKEN" \
  "${API}/git/refs/heads/${BRANCH}" | jq -r .object.sha)
BASE_TREE=$(curl -sS -H "Authorization: token $TOKEN" \
  "${API}/git/commits/${PARENT_SHA}" | jq -r .tree.sha)
 
# 3. 新しい tree を作成
TREE_SHA=$(curl -sS -X POST -H "Authorization: token $TOKEN" \
  -d "{\"base_tree\":\"${BASE_TREE}\",\"tree\":[{\"path\":\"content/articles/ja/sample.mdx\",\"mode\":\"100644\",\"type\":\"blob\",\"sha\":\"${BLOB_SHA}\"}]}" \
  "${API}/git/trees" | jq -r .sha)
 
# 4. commit を作って ref を進める
COMMIT_SHA=$(curl -sS -X POST -H "Authorization: token $TOKEN" \
  -d "{\"message\":\"Add sample\",\"tree\":\"${TREE_SHA}\",\"parents\":[\"${PARENT_SHA}\"]}" \
  "${API}/git/commits" | jq -r .sha)
curl -sS -X PATCH -H "Authorization: token $TOKEN" \
  -d "{\"sha\":\"${COMMIT_SHA}\"}" \
  "${API}/git/refs/heads/${BRANCH}"

この4ステップは GitHub の Git Data API の典型的な使い方で、Blobs → Trees → Commits → Refs の順に組み立てる形になります。1ファイルだけなら 5 秒もかからず完了し、.git ディレクトリも不要です。

私は失敗が許されない自動化(毎日決まった時刻に走るスケジュールタスクなど)でこの方式を採用しています。普段の開発まで API push にする必要はありませんが、「自動化が落ちると翌朝困る」種類のジョブには非常に向いています。さらに踏み込んで設計したい方には Claude Code の git push 失敗を体系的に直す と Claude Code 自動化を本番で安定させる長時間タスク設計 を読み合わせるとイメージが掴みやすいです。

どの順番で試すかの判断基準

3つの回避策はそれぞれ手間と汎用性のトレードオフが違います。私は次の順番で導入することをおすすめしています。

  • 週1回程度の頻度で起きる散発的な症状: 回避策1(ロック削除+reset)だけで十分。ローカル開発との差分が一番小さい
  • VM 再起動後に高確率で起きる: 回避策2(書き込み可能なディレクトリへフォールバック)を追加。所有権問題は単発の rm では解消しないため
  • 絶対に止めたくない自動化ジョブ: 回避策3(GitHub REST API)に切り替える。ローカル git を経由しないため、ロック競合・所有権・ファイルシステム遅延のすべてを回避できる

この見極めができないまま全部を一度に入れてしまうと、コードの可読性だけが落ちて運用コストが増えてしまいます。「今困っている症状はどのレイヤーから来ているか」を一つずつ切り分けるのが結果的に近道です。

Claude Code に渡す前提でワークフローを整理しておくと、ロック競合のような「環境依存のトラブル」も体系的に潰しやすくなります。

まずは今動いている自動化スクリプトの git add の前に、回避策1の4行を挟むところから始めてみてください。これだけで翌週からの停止頻度が体感できるくらい変わります。

シェア

お読みいただきありがとうございます

Claude Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

Claude Code2026-06-10
git add -A が .bak バックアップまで巻き込む — in-place 修正スクリプトと自動コミットの落とし穴
sed -i や自作の --fix スクリプトが残す .bak バックアップを git add -A が無言で取り込み、本番リポジトリに混入させてしまう問題。なぜ気づきにくいのか、scoped add と .gitignore でどう塞ぐかを実例で整理します。
Claude Code2026-06-03
Claude Code で git push が「成功」したのに反映されない — commit が無音で失敗する罠
git push がエラーを出さず Everything up-to-date と表示されるのに、変更がリモートに反映されない。clone 直後の identity 未設定で commit が無音失敗する原因と、SHA 照合で確実に検証する方法を解説します。
Claude Code2026-06-01
Claude Code から git push すると 403 Write access to repository not granted が出るときの対処
Claude Code の自動化で GitHub に push すると 403『Write access to repository not granted』が出る原因を、classic PAT と fine-grained PAT の違いから整理し、リポジトリアクセス・Contents 権限・組織承認の確認手順を解説します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →