git reflogとは何か・消えたコミットを探し出す最後の手がかり
前記事の最後で、「一度でもコミットしていた内容なら復元できる可能性がある」と触れました。その復元の手がかりになるのがgit reflogです。一度ブランチの参照やコミットへの道筋を見失うと、Gitの中からは永久に辿れなくなると思うかもしれませんが、実はGitはそれとは別に、もう1つの記録を裏でずっと取り続けています。
HEADが動くたびに、ローカルがこっそり記録し続けている
reset --hardやブランチの削除でコミットへの道筋を失ったら、そのコミットはもう二度と辿れないと思うかもしれません。ですがGitは、HEAD(今どのコミットを指しているか)が移動するたびに、その軌跡をreflogという専用のログに記録し続けています。ブランチのラベルからは見えなくなったコミットでも、reflogを遡れば「少し前まではこのハッシュを指していた」という記録から見つけ出せることがあります。
# HEADの移動履歴を新しい順に表示する
git reflog show HEAD
# 734713b HEAD@{0}: reset: moving to HEAD~1
# a1b2c3d HEAD@{1}: commit: 途中まで書いたAPI連携
# 9f8e7d6 HEAD@{2}: checkout: moving from main to feature
# HEAD@{1}が「消えた」と思っていたコミットだと分かったら
git reset --hard HEAD@{1}
reflogは、車のドライブレコーダーの常時録画映像に近い存在です。普段は誰も意識していませんが、走行中(HEADが動くたび)は淡々と記録され続けています。事故を起こして「どこで曲がり間違えたのか分からない」となったとき、この録画を巻き戻せば、少し前の分岐点がどこだったかを確認できます。ただし録画データそのものが目的地ではなく、あくまで「少し前の状態を確認するための記録」である点が、通常のコミット履歴とは役割が違います。
pushされない、自分のマシンだけの記録
reflogがあるなら、間違えてコミットを消してしまっても、チームの他のメンバーのマシンから復元できるだろうと考えるかもしれません。しかしreflogはpushされる対象に含まれず、あくまで自分のローカルリポジトリだけに閉じた記録です。同じリポジトリを別のマシンにクローンしても、そのマシンのreflogは空の状態から始まり、自分のマシンで起きた操作の履歴は一切引き継がれません。
# reflogはリモートに存在しない。git logやgit branchで確認できるものとは別物 git log --oneline # コミット履歴(共有される) git reflog # HEADの移動履歴(このマシンだけのもの) # 別のマシンでcloneし直しても、そのマシンのreflogは空から始まる git clone https://example.com/repo.git
reflogは、日々の作業内容を書き留める自分だけの作業日誌のようなものです。同僚に「あの日どこで作業を間違えたか教えて」と聞かれても、その日誌は自分の机の引き出しにしかなく、同僚の引き出しには同じ内容は入っていません。何かやらかしたときに頼れるのは、あくまで自分の日誌だけだという前提を持っておく必要があります。
よくあるはまりポイント:reflogは無期限の保険ではない
reflogがあるからコミットは永久に安全だと思ってしまいがちですが、実際には保持期間に期限があります。デフォルトでは、他のコミットから辿れる(到達可能な)エントリは90日、ブランチ削除などで辿れなくなった(到達不能な)エントリは30日で、reflogの記録自体が期限切れとして扱われるようになっています。さらにその後、Gitの内部整理処理であるgc(ガベージコレクション)が実行されると、期限切れになったコミットの実体そのものが本当に削除されてしまいます。「reflogがあるから平気」と数ヶ月も放置せず、消えたと気づいた時点でできるだけ早く復元作業に取りかかることが重要です。
- git reflog
- HEADが移動するたびにその軌跡を記録する、ローカルリポジトリだけのログ。ブランチから辿れなくなったコミットの復元に使う
- HEAD@{n}
- reflog上で「n回前のHEAD位置」を指す表記。git reflog showの出力にそのまま対応する
- gc.reflogExpire / gc.reflogExpireUnreachable
- reflogエントリの保持期間を決める設定。デフォルトは到達可能90日・到達不能30日で、期限を過ぎるとgcで実体ごと削除されうる
reset --hardやブランチの削除で「作業内容が消えた」と青ざめたときは、慌てて何かを上書きする前に、まずgit reflogを実行する癖をつけておきましょう。多くの場合、探しているコミットのハッシュがそこに記録されています。
reflogがコミットの「移動履歴」を追うための仕組みだとすれば、コミットの「変更内容そのもの」を追いかけるためのコマンドがgit logです。