git pull で出る gc.log 警告と unreachable loose objects
遭遇したエラー
git pull 実行時に以下の警告が出た。
Auto packing the repository in background for optimum performance.
See "git help gc" for manual housekeeping.
warning: The last gc run reported the following. Please correct the root cause
and remove .git/gc.log
Automatic cleanup will not be performed until the file is removed.
warning: There are too many unreachable loose objects; run 'git prune' to remove them.pull 自体は成功するが、警告が毎回出続ける状態になる。
警告の意味を分解する
1. gc.log が残っている
過去にバックグラウンドで自動実行された git gc(”Auto packing the repository in background” のやつ)が何かを警告して終了した。その内容が .git/gc.log に書かれている。
2. 自動 gc が止まっている
Automatic cleanup will not be performed until the file is removed. の通り、.git/gc.log が存在する間、Git は以降の自動 gc をスキップする。同じ失敗を繰り返さないためのセーフガード。gc.log を消さない限り自動メンテが永久に止まる。
3. unreachable loose objects が多すぎる
どこからも参照されていない(ブランチ・タグ・reflog から辿れない)孤立した object ファイルが .git/objects/ 配下に大量に積もっていた。git gc は通常 2 週間の猶予を持って残すので自動では消えず、ユーザーに git prune を促した。
つまり「自動 gc が unreachable object の多さを検知 → 破壊的な prune は自動でやらない → ログ残して停止」という状態。
原因
「unreachable loose object が積もる」原因は、コミットや object を作った後にその参照を捨てる操作を繰り返したこと。代表的なのは以下。
git rebase/git commit --amend— 元のコミットは新コミットに置き換わって参照を失う。rebase で 10 commit 書き換えれば 10 個の orphan ができるgit reset --hardで先祖に戻す — 戻した分のコミットが宙に浮く- ブランチの削除 — マージ済みでないブランチを
-Dで消すと、そのブランチ先端以降が孤立 git fetchで古い ref が捨てられる — リモートが force-push されていた等- 大量の
git stash作成 → drop
reflog(デフォルト 90 日、unreachable は 30 日)に残っている間は「unreachable だけど reflog 経由で reachable」なので prune 対象外。reflog から落ちて初めて「真の unreachable」になり、それが閾値(デフォルト 6700 個前後)を超えると git gc --auto が今回の警告を出す。
特定の 1 つの操作が原因というより、長期間運用しているリポジトリでの累積で起きる。
解消手順
git prune --expire=now # 2週間より新しい unreachable object も全部削除
git gc # パック化・整理
rm .git/gc.log # 警告のトリガを除去prune の破壊性に注意
git prune --expire=now は 2 週間以内の unreachable object も即削除する。最近 reset / rebase で捨てた commit を git reflog 経由で復活させたい可能性があるなら使わない方がいい。
安全側でいくなら --expire=now を外してデフォルト(2 週間)に任せる。
git prune # 2週間より古い unreachable object のみ削除
git gc
rm .git/gc.log確認コマンド
現在の状態を把握するには以下が役立つ。
# reflog 保持期間(デフォルト未設定なら 90 日 / 30 日)
git config gc.reflogExpire
git config gc.reflogExpireUnreachable
# reflog エントリ数
git reflog --all | wc -l
# 自動 gc の閾値
git config gc.auto
# repo の整合性チェック
git fsck --no-dangling予防
長期運用するリポジトリでは、定期的に git gc を手動で回すか、gc.auto の閾値を下げてマメに走らせると累積を防げる。
git config gc.auto 256まとめ
gc.logの存在は自動 gc が止まっているサイン- 原因は rebase / amend / branch 削除の長期累積
- 解消は
git prune→git gc→rm .git/gc.logの 3 ステップ --expire=nowは強力だが reflog からも消えるので reset 取り消しの保険を捨てることになる