エラーの内容
いつものように git status、git pull、あるいは git log を実行したところ、突然このエラーが表示されました:
error: object file .git/objects/ab/cdef1234567890abcdef is empty
fatal: loose object abcdef1234567890 (stored in .git/objects/ab/cdef1234567890) is corrupt
Gitが完全に動かなくなります。コミット、プル、プッシュ — どれも機能しません。git status すら実行できないこともあります。主な原因として、Git の書き込み中に強制シャットダウンした、ディスク容量が操作の途中で不足した、あるいは git gc 実行中に停電が発生したことが挙げられます。これらのいずれかにより、サイズがゼロのファイルや不完全なオブジェクトファイルが残され、それらが解決されるまで Git は処理を拒否します。
ステップ1 — fsck で破損箇所を全て確認する
まだ何も操作しないでください。まず、何が壊れているかを正確に把握します:
git fsck --full
.git/objects/ 内のすべてのオブジェクトをスキャンし、欠損・ダングリング・破損しているエントリにフラグを立てます。出力は通常このようになります:
error: object file .git/objects/ab/cdef1234567890abcdef is empty
error: object file .git/objects/3f/a0b12c... is empty
dangling blob 7d3e9f...
missing tree 8c12a4...
ひどい場合は、5〜10個の破損したハッシュが表示されることがあります。後で参照できるよう、すべて書き留めておきましょう。
ステップ2 — 空のオブジェクトファイルを削除する
サイズがゼロのファイルは最も一般的な症状です。Git は空のオブジェクトを解析できず、処理を先に進めません。削除します:
# まずドライランで削除対象を確認する
find .git/objects -size 0
# サイズがゼロのオブジェクトファイルをすべて削除する
find .git/objects -size 0 -delete
その後、再度 git fsck --full を実行してください。これらのオブジェクトがリモートまたは reflog に存在していれば、次のステップで追加作業なしに Git が自動的に復元できることが多いです。
ステップ3 — リモートからフェッチして欠損オブジェクトを復元する
リモートがあれば復元は簡単です。フェッチにより、GitHub、GitLab、またはプッシュ先から欠損オブジェクトを直接取り戻します:
git fetch --all
HEAD または現在のブランチ参照自体が破損していて fetch が失敗する場合は、代わりに特定のブランチを指定します:
git fetch origin main
git fetch origin --tags
もう一度 git fsck --full を実行してください。多くの場合、このフェッチ一回で破損が完全に解消されます。
ステップ4 — リモートフェッチで不十分な場合は reflog から復元する
.git/logs/ の中には、すべての HEAD の動きが時系列で記録されたジャーナル — Git の reflog があります。オブジェクトが消失していても、reflog には問題が起きる前の HEAD の位置が記録されています:
git reflog
最後にクリーンだったコミット(破損のタイムスタンプの直前)を見つけ、そこにリセットします:
git reset --hard <commit-hash>
reflog 自体が読めない場合は、生のファイルを直接確認します:
cat .git/logs/HEAD
ステップ5 — git status がまだ壊れている場合はインデックスを再構築する
インデックスファイル(.git/index)がオブジェクトと同時に破損している場合があります。削除して、Git に HEAD ツリーから再構築させます:
rm .git/index
git reset HEAD
ワーキングディレクトリのファイルはそのまま残ります。Git は現在のコミットのツリーからインデックスを再構築するだけで、通常これで git status が再び動作するようになります。
ステップ6 — gc を実行してクリーンアップと再パックを行う
破損が解消されたら、残存するルーズオブジェクトをパックファイルに統合し、ダングリング参照を削除します:
git gc --aggressive --prune=now
これにより内部インデックスも再構築され、fsck がフラグを立てたものの重大なエラーとして分類されなかった整合性の警告が解消されることがあります。
最終手段 — リモートがあれば新しくクローンする
何も効果がなく、クリーンなリモートが利用可能な場合は、破損したリポジトリとの戦いをやめて新しく始めましょう:
# まずコミットされていない変更をバックアップする
cp -r my-repo /tmp/my-repo-backup
# 新しくクローンする
git clone git@github.com:user/my-repo.git my-repo-fresh
# 必要な未追跡ファイルをコピーし直す
cp /tmp/my-repo-backup/some-file.txt my-repo-fresh/
修正を確認する
リポジトリが正常であることを確認するために、以下の4つのチェックを実行します:
# エラーが報告されないことを確認
git fsck --full
# クリーンな状態が表示されることを確認
git status
# エラーなしでログが出力されることを確認
git log --oneline -10
# 実際の操作をテストする
git pull
git fsck で error: の行がゼロであれば、オブジェクトデータベースは正常です。問題ありません。
再発を防ぐために
- Git プロセスを強制終了しない —
git gc、git clone、git pushは必ず自然に完了させましょう。 - ディスク容量を監視する — 操作の途中でディスクが満杯になると、オブジェクトの書き込みが静かに失敗します。アクティブなリポジトリがあるマシンは少なくとも数GB の空き容量を確保しておきましょう。
- 重要なマシンには UPS を使用する — パック操作中の突然の電源断がこのエラーの最大の原因です。安価な UPS でもリスクを完全に排除できます。
- こまめにプッシュする — リモートが本当のバックアップです。オブジェクトがそこに存在すれば、
git fetch一回で復元できます。 - 重要なリポジトリで定期的に
git fsckを実行する — 早期に発見した1つの破損オブジェクトなら数秒で修正できます。後から大量に発見した場合は、数時間の復旧作業になることがあります。

