git reflog 可能是最被低估的 Git 命令之一。它不負責提交,也不改變分支,只在後臺安靜地記錄一件事:你的引用曾經指向哪裡。
很多人第一次聽說它,是在一次災難之後。一次 reset --hard 讓剛寫完的代碼消失,一次誤刪分支讓幾天的提交無影無蹤。Git 看起來像一臺冷冰冰的銷燬機器,而 reflog 像藏在側門後的撤銷鍵。
reflog 記錄的不是文件
先糾正一個常見誤解:reflog 不是文件備份。它記錄的是 HEAD 和分支引用移動的歷史。提交對象仍然躺在 Git 的對象數據庫裡,真正丟失的只是“有哪個名字指向它”。
可以把 reflog 想成航海日誌:
- 你從哪裡出發;
- 在哪個提交停靠;
- 哪一次 rebase、merge、reset 改變了航線;
- 以及當時使用的命令。
查看完整記錄:
git reflog --date=iso
輸出通常像這樣:
a1f9e2d HEAD@{2026-11-03 09:42:17 +0800}: reset: moving to HEAD~2
7c3d0ab HEAD@{2026-11-03 09:39:02 +0800}: commit: feat: add reading progress
每一行都對應一個可以被找回的時間點。HEAD@{n} 不是抽象編號,而是一條真實存在的路徑。
把誤刪的分支撈回來
假設你在整理分支時刪掉了 feature/search,幾分鐘後才發現還沒有合併。
先找到它最後一次出現的位置:
git reflog
看到類似下面的記錄後,從那個提交重新建一條分支:
git branch feature/search HEAD@{4}
如果分支名就是你的目標,甚至可以原地恢復。只要提交對象還沒被 Git 的垃圾回收清理,這次“刪除”就只是一次改名。
reset 之後的第二次機會
git reset --hard 聽上去很危險,但 reflog 往往能把它變成一次可逆操作。
git reflog
# 找到 reset 之前的提交
git branch rescue a1f9e2d
不要急著把分支直接拉回原處。先建立一條 rescue 分支,確認內容完整,再用 cherry-pick、reset 或新的提交把需要的東西帶回來。撤銷不是回到過去,而是從過去取回你需要的部分。
它也不是萬能備份
reflog 很有用,但必須知道它的邊界:
- 默認只在本地保存,不會隨
git push上傳; - 過期時間通常由
gc.reflogExpire控制,默認約 90 天; - 未跟蹤文件被刪除後,reflog 無法恢復;
- 如果提交已經被垃圾回收,路徑也會一起消失。
所以它不是備份策略,只是 Git 留給你的一層緩衝。真正重要的代碼仍然需要遠端倉庫、備份和檢查點。
我後來越來越常使用 git reflog,不僅是為了救火。它讓我更清楚地看見自己如何移動:哪些操作是必要的,哪些 reset 只是在掩蓋一次不夠清晰的提交。
時間線不會撒謊。學會讀它,Git 才從一套命令變成一張可以回望的地圖。