Git Reflog:误操作后的后悔药
git reset --hard、错误的 rebase、删掉的分支——这些操作看起来都把提交"弄丢"了。
大多数时候没丢。只要提交曾经存在于本地仓库,git reflog 都能翻出来。
一、reflog 是什么
它记录 HEAD 和分支引用在本地每一次移动:
git reflog
# 3f2a1b0 HEAD@{0}: reset: moving to HEAD~3
# 9c8d7e6 HEAD@{1}: commit: feat: add validation
# 5b4a3c2 HEAD@{2}: rebase (finish): returning to refs/heads/main
HEAD@{n} 就是第 n 步之前的快照。注意它只存在于本地,不会推送,默认保留 90 天。
二、reset --hard 之后
git reset --hard HEAD~3 # 手滑,三个提交没了
git reflog # 找到 reset 之前那条
git reset --hard HEAD@{1} # 回去
也可以只捞不挪:
git cherry-pick 3f2a1b0
三、rebase 搞砸了
rebase 会留下一串 rebase (start) / rebase (finish) 记录,找到 rebase (start) 之前那一条:
git reflog | grep rebase
git reset --hard HEAD@{5}
rebase 中途想直接放弃,其实不用 reflog:
git rebase --abort
四、删掉的分支
git branch -D feature-x # 删错了
git reflog # 找到该分支最后一次提交
git branch feature-x 9c8d7e6
如果连 reflog 都记不清,直接看所有分支引用里剩下的提交:
git log -g --oneline --all
五、提交没进任何分支
在 detached HEAD 上直接 git checkout main,那个提交就没人引用了。这时用:
git fsck --lost-found
ls .git/lost-found/commit/
git show <id>
git fsck --unreachable 列出的就是所有不可达对象,理论上都能捞。
六、reflog 会失效的情况
git gc --prune=now清理过,或超过保留期- 从没在本地存在过(比如别人 force push 覆盖了远程)
- clone 之后本地根本没拉过那些提交
所以救命的顺序是:先 reflog,再 fsck,最后看远程或同事的仓库。
七、把它变成习惯
手滑之后的正确姿势:
- 千万别慌着继续操作,每次 commit / reset / merge 都会往 reflog 再压一条
git reflog定位目标- 用
git reset --hard回去,或用git branch rescue <id>先建个保险分支
第三条尤其推荐:先建分支把提交钉住,再慢慢折腾,怎么都不会丢。