【Git 救援篇】不小心 git reset --hard?別慌:用 reflog 與底層物件找回丟失的 Commit / [Git Recovery Guide] Accidentally Ran git reset --hard? Rescuing Commits with Git Reflog
在終端機按下 Enter 的瞬間,許多工程師都曾有過心臟漏跳半拍的經歷:原本只想清除暫存,手指卻下意識敲出 git reset --hard HEAD~1,剛剛花了一下午寫完並提交的功能代碼,瞬間在編輯器視窗裡消失得無影無蹤。
The moment Enter is pressed, many developers experience that stomach-dropping panic: intending only to clear staged files, fingers muscle-memory typed git reset --hard HEAD~1, instantly wiping an entire afternoon of newly committed code from editor buffers.
請先深吸一口氣,停下鍵盤上的所有強制寫入指令。Git 的底層設計並不是像磁碟碎紙機一樣立即覆寫資料;事實上,只要那個修改曾經被 git commit 記錄過,你的程式碼絕大多數時候都依然毫髮無傷地躺在硬碟的物件資料庫裡。
Take a deep breath and immediately step away from destructive write commands. Git's underlying architecture is not a shredder that overwrites disk blocks immediately; if your work was committed even once, the files almost certainly remain intact inside the local object store.
圖一|reset --hard 僅後移分支與 HEAD 指標,Commit 物件仍完整保留於物件庫中(原創架構示意圖,非產品截圖)
Figure 1 | reset --hard only moves branch and HEAD pointers; the commit object remains intact in the object database (Original architecture diagram, not a product screenshot).
現象與機制:指標移走了,但 Commit 物件還活著 / Mechanism: Pointers Moved, Objects Remain
要理解為什麼代碼能救回,關鍵在於搞懂 git reset --hard 究竟做了什麼。Git 的分支在本質上只是一個「包含 40 碼 SHA-1 雜湊值純文字指標」。當我們下達 reset 指令時,Git 僅僅是把目前分支(如 main)的指針倒退指向上一顆提交,並將暫存區(Index)與工作目錄強制同步回該歷史狀態。
To understand why code is recoverable, we must examine what git reset --hard actually changes. A Git branch is fundamentally nothing more than a 40-character text pointer holding a commit SHA. When you reset, Git simply rewires your branch pointer backward to the parent commit and syncs the index and working tree to match that revision.
在此過程中,原先那顆被拋下的最新提交(例如圖一中的 Commit B),根本沒有被刪除。它只是暫時失去了任何有名字的分支引用,在 Git 的術語中被稱為「懸空提交」(Dangling Commit 或 Unreachable Object)。除非經過完整的垃圾回收(Garbage Collection)週期,否則該物件會一直保存在 .git/objects 中。
Crucially, the commit you just abandoned is never erased in that moment. It simply becomes detached from any named branch ref—a state known in Git terminology as a "dangling commit" or unreachable object. Until Git's background garbage collection cycle purges it, the object resides safely in .git/objects.
圖二|面對誤下 reset 的冷靜救援 SOP:唯讀檢視、reflog 溯源、建立新分支救援(原創流程圖)
Figure 2 | Step-by-step rescue SOP: Stop writing, inspect reflog, verify commit content, and restore via a new branch (Original workflow diagram).
救援的生命線:認識 reflog / The Lifeline: Understanding Git Reflog
如果分支指標已經移開,我們要去哪裡找回失蹤的提交雜湊碼?答案就是 git reflog。reflog(Reference Log)是 Git 在本機默默維護的日誌系統,專門記錄 HEAD 指針在每一次切換分支、提交、重置或變基時的移動軌跡。這意味著:即使分支名稱不再指向它,reflog 也忠實記錄了「上一秒鐘 HEAD 曾停在該 Commit」的事實。
With the branch pointer moved away, where do we discover the lost commit hash? The answer lies in git reflog. The reference log is a silent local bookkeeping mechanism tracking every movement of the HEAD pointer across commits, checkouts, resets, and rebases. Even when branches no longer point to your work, the reflog preserves the exact coordinates of where HEAD stood moments before.
工程師實測:四步驟安全復原 SOP / Four-Step Verified Rescue Workflow
當意外發生時,切忌慌亂執行 git clean -fd 或盲目切換分支。請依序執行以下經過實測驗證的標準復原流程:
When an accidental reset strikes, avoid typing panic commands like git clean -fd or blind branch hops. Follow this experimentally verified four-step rescue procedure:
# 步驟 1:唯讀檢視最近 HEAD 移動紀錄(找出 reset 前的 commit hash)
git reflog -10 HEAD
# 範例輸出:
# 4c4b3ff HEAD@{0}: reset: moving to HEAD~1
# cc66d9e HEAD@{1}: commit: feat: add payment handler <-- 這就是你遺失的寶貴提交!
# 步驟 2:使用唯讀指令確認該提交的完整修改內容
git show cc66d9e
# 步驟 3:從該雜湊碼拉出一條全新的救援分支,原地復活!
git branch rescue-payment cc66d9e
# 步驟 4:切換到救援分支,確認工作目錄代碼全數回歸
git switch rescue-payment
實測驗證紀錄(環境:Windows 11 / Git 2.52.0.windows.1):
本文在獨立暫存庫模擬提交後執行 git reset --hard HEAD~1,HEAD 退回初始版本。透過 git reflog -5 成功擷取出上一動 HEAD@{1} 雜湊碼 cc66d9e;藉由 git branch rescue-payment cc66d9e 建立新分支後切換,檔案內容與完整修改紀錄百分之百原樣復原。
Test Verification (Windows 11 / Git 2.52.0.windows.1): In a temporary disposable repository, git reset --hard HEAD~1 was executed after committing. Running git reflog -5 immediately exposed the prior HEAD@{1} hash cc66d9e. Spawning a new branch pointing to this hash completely restored all files and history without data loss.
復原邊界與安全警示 / Boundaries and Safety Constraints
儘管 reflog 是強大的安全網,工程師仍須清楚其物理邊界。第一,reflog 只記錄「曾經被 git commit」的快照;如果你修改了檔案卻從未執行過 commit 或暫存(git add),reset --hard 會直接抹除工作目錄中未追蹤的修改,此時只能仰賴編輯器本地歷史(Local History)救援。
While reflog is an invaluable safety net, engineers must recognize its functional limits. First, reflog exclusively tracks snapshots that reached commit status; unstaged modifications in the working tree that never saw git add or commit will indeed be wiped by reset --hard, leaving editor local history as the sole resort.
第二,reflog 屬於純本機參照,不會同步到 GitHub 或遠端倉庫,且具備有效期限(Git 預設為 unreachable 提交保留 30 天,reachable 提交保留 90 天)。因此,遇到意外應第一時間處置,救援後盡快推送遠端分支備份,方能徹底高枕無憂。
Second, reflogs are strictly local references never pushed to GitHub or remote origins, and they carry retention expiration (Git defaults to 30 days for unreachable objects and 90 days for reachable refs). Treat accidents promptly and push recovered branches to remotes for permanent peace of mind.
官方查核與文獻依據 / Sources and Verification:
查核日期:2026-11-05。本文核心機制依據 Git 官方維護文檔與資料模型規格:
- Git Documentation: git-reflog - Managing reflog information
- Git Documentation: git-reset - Reset current HEAD to the specified state
- Git Documentation: git-fsck - Verifying the connectivity and validity of the objects in the database
- Git Documentation: git-gc - Cleanup unnecessary files and optimize the local repository
References: Official Git manual on git-reflog, git-reset, git-fsck, and git-gc retention policies (Verified 2026-11-05). Original architectural diagrams produced for this article; not product screenshots.

留言
張貼留言