【完全ガイド】git error: cannot lock ref の原因と解決方法|stale locks・packed-refs・namespace衝突まで徹底解説
Git の pull / fetch / push で発生する厄介なエラー:
$ git pull
error: cannot lock ref 'refs/remotes/origin/main': Unable to create '.git/refs/remotes/origin/main.lock': File exists.
# または
error: cannot lock ref 'refs/remotes/origin/feature/login': 'refs/remotes/origin/feature' exists; cannot create 'refs/remotes/origin/feature/login'
# または
error: cannot lock ref 'refs/heads/main': unable to resolve reference 'refs/heads/main': reference broken
index.lock の姉妹エラーですが、こちらは ref(reference)のロックに関するもの。エラーメッセージも複数のパターンがあり、原因も5種類以上に分かれます:
- stale lock file(前コマンド異常終了)
- 大文字小文字衝突(macOS / Windows)
- packed-refs 破損
- 並列操作(IDE + CLI)
- namespace collision(feature vs feature/login)
現場では:
- git fetch 後に急に発生
- remote branch を消したのに残る
- case-sensitive な filesystem で頻発
- force push 後のリファレンス不整合
- CI/CD で謎に発生
このエラーは、単純に lock ファイル削除だけでは解決しないケースが多く、原因を正しく判別する必要があります。特にnamespace collision(feature と feature/login のような競合)は、削除しても再発するため、根本的な対処が必要です。
本記事では、cannot lock ref の完全な原因と解決方法を、リファレンスとして実用的に整理します。ref lock の仕組み、5大原因、git update-ref -d、git fetch --prune、git gc、git pack-refs の使い方、実践シナリオ、予防のベストプラクティス、FAQまで完全網羅。この1本で ref lock 関連エラーを根本から解決できるようになります。
- 1. 結論:原因は5パターン
- 2. まず理解する:ref と lock の仕組み
- 3. 【原因①】stale lock file
- 4. 【原因②】namespace collision(超要注意)
- 5. 【原因③】packed-refs 破損
- 6. 【原因④】並列操作
- 7. 【原因⑤】stale remote refs(削除された remote branch)
- 8. 使い方リファレンス
- 9. 実践シナリオ
- 10. 予防のベストプラクティス
- 11. トラブルシューティング
- 12. よくある質問(FAQ)
- 12.1. Q1. .lock ファイル、いつ削除していい?
- 12.2. Q2. index.lock との違い
- 12.3. Q3. namespace collision は Windows / macOS だけ?
- 12.4. Q4. git update-ref -d は危険?
- 12.5. Q5. packed-refs を直接編集していい?
- 12.6. Q6. git fetch --prune の効果
- 12.7. Q7. fetch.prune = true の副作用
- 12.8. Q8. reflog で救済可能?
- 12.9. Q9. 大規模リポジトリで頻発
- 12.10. Q10. GitHub Actions で発生
- 12.11. Q11. リモートに存在するのに削除される
- 12.12. Q12. Git 2.46+ での改善
- 13. 参考リンク
- 14. まとめ
結論:原因は5パターン
時間がない方向けに、最速の対処を先に示します。
5大原因と最速解決
| # | 原因 | 症状 | 最速解決 |
|---|---|---|---|
| ① | stale lock file | 前コマンド異常終了 | lock ファイル削除 |
| ② | namespace collision | ref A と A/B が衝突 | 片方削除 |
| ③ | packed-refs 破損 | reference broken | git pack-refs |
| ④ | 並列操作 | IDE + CLI | 待機・停止 |
| ⑤ | stale remote refs | 削除されたリモート | git fetch --prune |
一括対処(安全確認後)
# 1. Git プロセス確認
ps aux | grep git
# 2. lock ファイル一括削除
find .git -name "*.lock" -type f -delete
# 3. remote 同期
git fetch --prune
# 4. 検証
git fsck --full
エラーメッセージ別対処
# パターンA: Unable to create ... .lock: File exists
find .git -name "*.lock" -delete
# パターンB: 'refs/xxx' exists; cannot create 'refs/xxx/yyy'
git update-ref -d refs/xxx
# パターンC: reference broken
git pack-refs --all --prune
# パターンD: stale remote
git fetch --prune
詳細は以下で解説します。
まず理解する:ref と lock の仕組み
Git ref(reference)とは
ref = commit へのポインタ。ブランチもタグも、実はすべて ref:
.git/refs/
├── heads/ ← ローカルブランチ
│ ├── main ← ファイル:SHA を1行だけ含む
│ └── feature
├── remotes/ ← リモートトラッキング
│ └── origin/
│ └── main
└── tags/ ← タグ
└── v1.0
各ファイルの中身:
cat .git/refs/heads/main
# abc1234567890abcdef1234567890abcdef123456
ただの40文字の SHA が1行。これがブランチの実体。
ref lock の仕組み
ref を更新する時、Git は専用の lock ファイルを作成:
Before:
.git/refs/heads/main # 通常状態
During update:
.git/refs/heads/main
.git/refs/heads/main.lock # ロック中
After:
.git/refs/heads/main # 更新完了、lock 削除
同時更新を防ぐため。index.lock と同じ設計。
packed-refs との関係
Git は定期的にloose refsをpacked-refsに統合:
# loose refs(1ファイル1 ref)
.git/refs/heads/main
.git/refs/heads/develop
.git/refs/heads/feature-1
# ↓ git gc or git pack-refs
# packed-refs(1ファイルにまとめる、高速化)
.git/packed-refs
大規模リポジトリでは packed-refs 中心。これが破損すると別種のエラー。
【原因①】stale lock file
症状
最頻出パターン:
git pull
error: cannot lock ref 'refs/remotes/origin/main':
Unable to create '.git/refs/remotes/origin/main.lock': File exists.
診断
# 全 lock ファイル一覧
find .git -name "*.lock" -type f
# 出力例:
# .git/refs/remotes/origin/main.lock
# .git/refs/heads/feature.lock
# .git/packed-refs.lock
解決
Git プロセス確認:
ps aux | grep git
# 動いていなければ、lock 削除OK
個別削除:
rm -f .git/refs/remotes/origin/main.lock
一括削除:
find .git -name "*.lock" -type f -delete
⚠️ 他の Git プロセスが動いていないことを必ず確認。
なぜ発生するか
- Ctrl+C で中断した git fetch / pull
- ネットワークタイムアウト(fetch 中に切断)
- IDE の自動 fetch がクラッシュ
- ディスクフルなどのシステムエラー
プロセス管理(ps aux | grep git や pkill)の使い方は、Linux kill vs pkill vs killall の記事、ss コマンドの使い方の記事も参照してください。
【原因②】namespace collision(超要注意)
症状
片方だけ削除しても再発する、厄介な問題:
git fetch
error: cannot lock ref 'refs/remotes/origin/feature/login':
'refs/remotes/origin/feature' exists;
cannot create 'refs/remotes/origin/feature/login'
なぜ発生するか
Git の ref はファイルシステムのパスとして保存されます:
refs/heads/feature→ ファイルrefs/heads/feature/login→ ディレクトリfeature/の中の login ファイル
同じ名前でファイルとディレクトリは共存できない(OS の制約)。
❌ 不可能な状態:
.git/refs/heads/feature ← ファイル
.git/refs/heads/feature/ ← ディレクトリ
└── login ← ファイル
診断
# ref 一覧
ls -la .git/refs/heads/
ls -la .git/refs/remotes/origin/
# packed-refs も確認
grep feature .git/packed-refs
両方に存在すれば namespace collision。
解決
方法A: 古い ref を削除
# バックアップ(念のため)
git branch feature-backup origin/feature
# ref 削除
git update-ref -d refs/heads/feature
# または
git update-ref -d refs/remotes/origin/feature
# 再 fetch
git fetch
方法B: リモート側で名前変更
チームで合意して、feature を feature-main などにリネーム。
方法C: 特定 ref を除外
.git/config:
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
fetch = ^refs/heads/feature
予防策
ブランチ命名規則を明確に:
- 親子関係を避ける
feature/login,feature/logout→ OK(feature自体は使わない)feature,feature/x→ NG
【原因③】packed-refs 破損
症状
git pull
error: cannot lock ref 'refs/heads/main':
unable to resolve reference 'refs/heads/main': reference broken
.git/packed-refs が壊れた or 不整合。
診断
# packed-refs の中身
cat .git/packed-refs
# 予期しない内容、または途中で切れている
# 整合性チェック
git fsck --full
# 出力にエラーメッセージ
解決
方法A: git pack-refs で再作成
git pack-refs --all --prune
すべての loose refs を再度 packed-refs に統合、古い packed-refs 上書き。
方法B: packed-refs 削除して再構築
# バックアップ
cp .git/packed-refs .git/packed-refs.backup
# 削除
rm .git/packed-refs
# 再構築(loose refs から)
git pack-refs --all --prune
方法C: git fsck で検証
git fsck --full
# エラーがあれば個別対処
方法D: 最終手段:fresh clone
cd ..
git clone <URL> fresh-repo
【原因④】並列操作
症状
# ターミナル1
git fetch
# ターミナル2(同時)
git pull
# error: cannot lock ref ...
IDE + CLI、複数ターミナル、CI ジョブの並列実行などで発生。
診断
# 動いている git プロセス
ps aux | grep git
# lock ファイルを保持しているプロセス
lsof .git/refs/heads/main.lock
解決
待機して再実行:
sleep 5
git pull
IDE のバックグラウンド動作を停止:
- VS Code:
settings.jsonでgit.autofetch: false - JetBrains IDE: Version Control 設定
- SourceTree, GitKraken: 更新間隔
VS Code等のIDE との並行動作については、Unable to create ‘.git/index.lock’ の記事にも詳細な対処法を書いています。
並列実行を避ける:
# ❌
git fetch & git pull &
# ✅
git fetch && git pull
【原因⑤】stale remote refs(削除された remote branch)
症状
git fetch
# error: cannot lock ref 'refs/remotes/origin/deleted-branch'
- リモートで削除されたブランチ
- 強制 push で歴史が書き換わったブランチ
診断
# 現在のリモートトラッキング
git branch -r
# origin/main
# origin/deleted-branch ← リモートには存在しない
# リモートの実際の状態
git ls-remote --heads origin
解決
--prune オプション:
git fetch --prune
# または
git fetch -p
恒久的に自動 prune:
git config --global fetch.prune true
以降、git fetch は自動的に --prune。
特定 ref を手動削除:
git update-ref -d refs/remotes/origin/deleted-branch
使い方リファレンス
git update-ref
任意の ref を直接操作するコマンド。
# 削除
git update-ref -d refs/heads/branch-name
# 作成
git update-ref refs/heads/new-branch abc1234
# 更新
git update-ref refs/heads/main abc1234
# 検証付き更新(前の値と一致する時のみ)
git update-ref refs/heads/main abc1234 old_sha
低レベル操作なので慎重に。
git pack-refs
loose refs を packed-refs に統合:
# 全て統合
git pack-refs --all
# 統合 + loose 削除
git pack-refs --all --prune
大量ブランチ時に高速化。
git fetch –prune
削除された remote branch を同期:
git fetch --prune
# または短縮
git fetch -p
恒久設定:
git config --global fetch.prune true
git gc
Git のガベージコレクション:
git gc
# または積極的に
git gc --aggressive --prune=now
lock 関連のクリーンアップも含まれる。
git fsck
リポジトリ整合性チェック:
git fsck --full
# --full: object 全体をチェック
# --unreachable: 到達不能な object も表示
実践シナリオ
シナリオ1:git pull で stale lock
git pull
# error: cannot lock ref 'refs/remotes/origin/main'
# 対処
find .git -name "*.lock" -delete
git pull
# → 成功
シナリオ2:feature vs feature/xxx の namespace collision
git fetch
# error: cannot lock ref 'refs/remotes/origin/feature/login':
# 'refs/remotes/origin/feature' exists
# 診断
ls .git/refs/remotes/origin/feature*
# → feature(ファイル) と feature(ディレクトリ)の衝突
# バックアップ
git branch feature-backup origin/feature
# 古い ref 削除
git update-ref -d refs/remotes/origin/feature
# 再 fetch
git fetch
# → 成功
シナリオ3:packed-refs 破損
git pull
# error: unable to resolve reference: reference broken
# 診断
git fsck --full
# → エラー多数
# packed-refs 再構築
git pack-refs --all --prune
git fsck --full
# → クリーン
# 動作確認
git pull
シナリオ4:CI/CD で並列実行
# .github/workflows/parallel.yml
# 悪い例
jobs:
job1:
runs-on: ubuntu-latest
steps: [uses: actions/checkout@v4]
job2:
runs-on: ubuntu-latest
steps: [uses: actions/checkout@v4]
# 同じキャッシュを使うと lock 競合
# 良い例
jobs:
job1:
concurrency:
group: git-ops
cancel-in-progress: false
シナリオ5:チーム開発でブランチ削除多い
# 毎日多くのブランチが削除される
git config --global fetch.prune true
# 以降自動で削除同期
git fetch
シナリオ6:GitLab CI で頻発
# .gitlab-ci.yml
variables:
GIT_STRATEGY: clone # 毎回 clean
# または
GIT_STRATEGY: fetch
GIT_CLEAN_FLAGS: -ffdx
before_script:
- find .git -name "*.lock" -delete 2>/dev/null || true
シナリオ7:Rails 開発でよくある
# feature ブランチで大量の変更 + rails db:migrate
# 中断されて lock 残り
git pull
# error: cannot lock ref
# 対処
find .git -name "*.lock" -delete
git pull
Rails 開発では、rails db:migrate 使い方の記事、Rails 8 アップグレードガイドの記事とセットで対処すると効果的です。
シナリオ8:Kamal デプロイで発生
kamal deploy
# ビルド中に fetch などが並行
# → lock 競合の可能性
# 対処: デプロイ中は他の git 操作を控える
Kamal デプロイの詳細は、Kamal 2 デプロイの記事を参照してください。
シナリオ9:Docker 内で発生
docker exec -it container bash
cd /app
git fetch
# error: cannot lock ref
# 対処
find /app/.git -name "*.lock" -delete
git fetch
Docker関連の問題は、docker daemon 接続エラーの記事、Docker no space left on device の記事にも詳しい対処法があります。
シナリオ10:大規模リポジトリで発生
# 数万ブランチのリポジトリ
git fetch
# ref 数が多く、lock 競合しやすい
# 対処
git config core.fsyncMethod fsync # 安全性向上
git config core.packedRefsTimeout 10000 # timeout 延長
予防のベストプラクティス
1. fetch.prune を有効化
git config --global fetch.prune true
削除されたリモート branch を自動同期。
2. ブランチ命名規則
❌ 避ける
feature
feature/x
✅ 推奨
feature/main
feature/login
feature/logout
親名を予約語にせず、全てサブディレクトリ形式に。
3. Ctrl+C は最終手段
git fetch # 実行中
# ❌ Ctrl+C
途中で止めるより 完了を待つ。どうしても止めるなら、git fetch --abort などが利用可能な操作を使う。
4. IDE の Git 統合を意識
VS Code settings.json:
{
"git.autofetchPeriod": 600,
"git.autoRefresh": false
}
5. git gc の定期実行
# 週次で
git gc --auto
自動 pack で lock 競合を減らす。
6. 並列実行を避ける
# ❌
git fetch & git pull &
# ✅
git fetch && git pull
7. git fsck で健康チェック
git fsck --full
定期的に整合性確認。
トラブルシューティング
lock 削除しても再発
プロセスが動いている証拠:
# 全 git プロセス確認
ps aux | grep git
# 全部 kill
pkill -f git
# lock 削除
find .git -name "*.lock" -delete
git update-ref -d が動かない
git update-ref -d refs/heads/feature
# fatal: cannot lock ref
これも lock ファイルが原因:
rm .git/refs/heads/feature.lock
git update-ref -d refs/heads/feature
namespace collision が繰り返す
リモート側の問題。チームで:
- ブランチ命名規則の合意
- 問題ブランチを削除・リネーム
- CI/CD の設定見直し
GitHub / GitLab で発生
リモート側で強制 push・履歴書き換えが原因の可能性:
# 完全リセット
git fetch --prune
git remote update --prune
git gc --prune=now
submodule で発生
cd submodule
find .git -name "*.lock" -delete
cd ..
git submodule update --recursive
Windows で頻発
Git for Windows のプロセス残留。Task Manager で確認・終了。
Windows 特有のプロセス残留の対処は、Unable to create ‘.git/index.lock’ の記事に詳しく書いています。
よくある質問(FAQ)
Q1. .lock ファイル、いつ削除していい?
Git プロセスが動いていないことを確認してから。動作中に削除は危険(データ破損)。
Q2. index.lock との違い
index.lock: staging area(.git/index)のロックref lock: ブランチ・タグ等の参照ロック
作られる場所が違うだけで、仕組みは類似。
Q3. namespace collision は Windows / macOS だけ?
いいえ、Linux でも発生。ファイルとディレクトリの共存はどのOSでも不可能。
Q4. git update-ref -d は危険?
低レベル操作なので慎重に。誤ると ref を失うが、reflog で救済可能な場合が多い。
事前バックアップ:
git branch backup-branch <target-ref>
Q5. packed-refs を直接編集していい?
基本ダメ。フォーマット厳密、間違うとリポジトリ破損。git pack-refs 経由推奨。
Q6. git fetch --prune の効果
削除されたリモートブランチのローカル参照を削除。lock 系エラーの予防に効果大。
Q7. fetch.prune = true の副作用
ローカル作業中のブランチが削除されることはない(trackingブランチのみ対象)。安心して有効化推奨。
Q8. reflog で救済可能?
削除された ref も、reflog に残っていれば復旧可能:
git reflog
# 過去の操作履歴
# 該当 commit を確認して
git branch recovered abc1234
Q9. 大規模リポジトリで頻発
git config core.packedRefsTimeout 10000
git gc --auto
タイムアウト延長と定期 GC。
Q10. GitHub Actions で発生
- name: Clean lock files
run: find .git -name "*.lock" -delete 2>/dev/null || true
- uses: actions/checkout@v4
with:
fetch-depth: 0
CI 開始時にクリーニング。
Q11. リモートに存在するのに削除される
fetch.prune = true の副作用ではない。ネットワーク一時断で誤削除は稀。
対処: git fetch 再実行。
Q12. Git 2.46+ での改善
Git 2.46 / 2.47(2024年)で ref 関連の診断情報が強化。Git 更新推奨:
git --version
# 2.46.0 以降がおすすめ
参考リンク
Git 公式
- git-update-ref Documentation – update-ref 公式
- git-pack-refs Documentation – pack-refs 公式
- git-fsck Documentation – fsck 公式
- gitrepository-layout – リポジトリ構造
まとめ
cannot lock ref の解決、要点を再整理します。
5大原因まとめ
| # | 原因 | 症状 | 解決 |
|---|---|---|---|
| ① | stale lock | File exists | find .git -name "*.lock" -delete |
| ② | namespace collision | 'refs/X' exists; cannot create 'refs/X/Y' | git update-ref -d refs/X |
| ③ | packed-refs 破損 | reference broken | git pack-refs --all --prune |
| ④ | 並列操作 | 同時実行 | 順次実行 |
| ⑤ | stale remote refs | 削除されたリモート | git fetch --prune |
最速の解決手順
# 1. Git プロセス確認
ps aux | grep git
# 2. lock ファイル一括削除
find .git -name "*.lock" -type f -delete
# 3. remote 同期
git fetch --prune
# 4. 検証
git fsck --full
覚えるべきコマンド
# ref 直接削除
git update-ref -d refs/heads/branch-name
# packed-refs 再構築
git pack-refs --all --prune
# 削除されたリモートを同期
git fetch --prune
# 整合性チェック
git fsck --full
# ガベージコレクション
git gc --auto
必須設定
git config --global fetch.prune true
git config --global gc.auto 6700
多くの問題を予防。
予防策
fetch.prune = true恒久設定- ブランチ命名規則を明確化
- 並列実行を避ける
- IDE の自動 fetch を意識
- 定期的な
git gc git fsckで健康チェック
事故防止
- プロセス確認せずに削除しない
git update-refは慎重に- packed-refs 直接編集禁止
- バックアップ習慣
- どうにもならなければ fresh clone
環境別
| 環境 | 特徴 |
|---|---|
| Windows | プロセス残留、大文字小文字非区別 |
| macOS | 大文字小文字非区別(デフォルト) |
| Linux | 大文字小文字区別 |
| CI/CD | 並列実行問題 |
| Docker | volume 権限問題 |
これらの知識は、日常の Git 操作・チーム開発・大規模リポジトリ・CI/CD・Docker / Kamal デプロイなど、あらゆる場面で活用できます。本記事をブックマークしておけば、ref 関連の複雑なエラーを確実に解消できるようになります。
本記事は2026年6月時点の情報をもとに、Git 2.40+ での動作確認・公式ドキュメントに基づき作成しています。Git のバージョンによって挙動が異なる場合があるため、最新の情報は Git 公式ドキュメント(git-scm.com/docs)もあわせてご確認ください。
-
前の記事
【完全ガイド】git fatal: Unable to create ‘.git/index.lock’ の原因と解決方法|lock ファイル仕組み・IDE並行動作まで徹底解説 2026.07.14
-
次の記事
【完全ガイド】ORA-04031: unable to allocate shared memory の原因と解決方法|Shared Pool・Hard Parse・Bind変数まで徹底解説 2026.07.16
コメントを書く