ota2000
3 min read

Claude Code で git index.lock が消えない問題と原因の特定

Claude Code を使っていると git addgit commitindex.lock で失敗し続ける問題にハマった。初歩的だけど原因の特定に手間取ったので記録しておく。

症状

Claude Code のセッション中に git コマンドを実行すると、ほぼ毎回これが出る。

fatal: Unable to create '.git/index.lock': File exists.

rm -f .git/index.lock で消しても数秒で再作成される。

最初に疑ったもの(ハズレ)

Cursor(VS Code 系 IDE)の git.autorefreshgit.autofetch が定期的に git status を叩いているのでは、と推測した。設定を false に変更し、Cursor を再起動してみたが解消しなかった。

拡張機能(GitHub Pull Requests 等)も疑って無効化したが変わらず。

犯人の特定

lock ファイルを消した直後にプロセスを確認する方法で特定できた。

rm -f .git/index.lock
# 再作成されるのを待って
ps aux | grep git

出力。

ota2000  18331  /opt/homebrew/opt/git/libexec/git-core/git status --porcelain=2

このプロセスの親を辿ると、Claude Code の statusline.js だった。Claude Code はターミナル下部にブランチ名と変更状態を表示するために、git status --porcelain を定期的に実行している。この実行時に index.lock が作られ、他の git コマンドと競合していた。

解決

GIT_OPTIONAL_LOCKS=0 という環境変数を設定すると、git は read-only な操作(git status 等)で lock ファイルを作らなくなる。

~/.claude/statusline.js を修正して、git コマンド実行時にこの環境変数を渡すようにした。

// Before
execSync('git status --porcelain', { encoding: 'utf8' });

// After
const gitEnv = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
execSync('git status --porcelain', { encoding: 'utf8', env: gitEnv });

加えて ~/.claude/settings.jsonenv にも追加しておいた。

{
  "env": {
    "GIT_OPTIONAL_LOCKS": "0"
  }
}

これで lock ファイルは再作成されなくなった。

振り返り

IDE を疑って設定を変えたり再起動したりで 30 分くらい無駄にした。最初から ps aux | grep git していれば一瞬だった。index.lock が消えないときはプロセスを見る。これに尽きる。

GIT_OPTIONAL_LOCKS=0 は read-only な git 操作の lock を抑制する公式の仕組みで、git のドキュメントにも記載がある。statusline のようなバックグラウンドで git status を叩く仕組みには最初から入れておくべきだろう。