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 才從一套命令變成一張可以回望的地圖。