引用日志(Reflog)
本教程共 26 篇 · 第 19 篇 · 更新于 2026-07-29 · 约 5 分钟阅读
19. 引用日志(Reflog)
本节目标:理解引用日志的本质是 Git 的”后悔药”,学会用 reflog 找回那些你以为已经丢失的提交。
什么是引用日志
Git 的引用日志(reflog)就像手机里的”最近删除”相册。
你删掉一张照片,它并没有立刻从手机里消失,而是进了”最近删除”。reflog 也一样。当你执行 git reset --hard、git rebase、git commit --amend,Git 并没有真正丢弃旧提交。它只是把它们记在 reflog 里。
一句话:reflog 记录了你本地仓库中 HEAD 每一次指针移动的轨迹。
Notereflog 只存在本地。推送到远程仓库的提交不会被远程帮你保留 reflog,clone 也不会复制别人的 reflog。这是你个人的操作历史。
reflog 长什么样
打开终端,进入任意一个 Git 仓库,输入:
git reflog
输出大概长这样:
a1b2c3d HEAD@{0}: commit: 修复登录按钮样式
e4f5g6h HEAD@{1}: checkout: moving from feature to main
i7j8k9l HEAD@{2}: commit (merge): 合并 feature 分支
m0n1o2p HEAD@{3}: rebase -i (finish): returning to refs/heads/main
q3r4s5t HEAD@{4}: commit: 添加用户头像上传
每一行是一条记录。HEAD@{0} 表示 HEAD 当前所在的位置,HEAD@{1} 是上一步,HEAD@{2} 是上上步,以此类推。
HEAD@{n} 语法
HEAD@{n} 是 reflog 专属的引用语法。它的意思是”HEAD 在第 n 步时所指向的提交”。
这跟 HEAD~n 不一样。HEAD~n 是沿着提交历史往上数第 n 个父提交,而 HEAD@{n} 是沿着操作历史回溯。
举个例子:你先在 main 分支提交了 A,然后切到 feature 分支提交了 B,再切回 main。
HEAD~1是提交 A(父提交)HEAD@{1}是提交 B(切回 main 之前的位置)
与 git log 的区别
| 对比项 | git log | git reflog |
|---|---|---|
| 内容 | 提交历史(祖先链) | 操作历史(HEAD 移动轨迹) |
| 是否包含”丢失”提交 | 不包含 | 包含 |
| 作用域 | 永久 | 默认 90 天后过期 |
| 能否跨分支追踪 | 按分支走 | 按时间顺序全记录 |
一句话:git log 看”谁是谁的祖先”,git reflog 看”你踩过哪些坑”。
找回”丢失”的提交
这是 reflog 最常用的场景。假设你不小心执行了:
git reset --hard HEAD~3
三个提交”消失”了。git log 里看不到了。别慌。
- 先看 reflog 找到那三个提交:
git reflog
a1b2c3d HEAD@{0}: reset: moving to HEAD~3
e4f5g6h HEAD@{1}: commit: 第三次提交
i7j8k9l HEAD@{2}: commit: 第二次提交
m0n1o2p HEAD@{3}: commit: 第一次提交
- 找到你想恢复的位置,比如
HEAD@{1}:
git reset --hard HEAD@{1}
三个提交就回来了。
Warningreflog 记录有过期时间。默认情况下,可达对象保留 90 天,不可达对象保留 30 天。过期后 Git 垃圾回收会真正删除它们。所以发现误操作要尽快恢复。
指定分支的 reflog
git reflog 默认显示 HEAD 的记录。你也可以查看某个分支的 reflog:
git reflog show main
这在排查”某个分支的顶端怎么跑到这里来了”时特别好用。
reflog 过期时间
想调整过期时间,可以改配置:
# 控制可达对象的保留天数
git config gc.reflogExpire 180.days
# 控制不可达对象的保留天数
git config gc.reflogExpireUnreachable 60.days
实际操作演示
我们来模拟一次”事故”和”救援”。
- 先制造三次提交:
echo "第一次" > a.txt && git add . && git commit -m "第一次提交"
echo "第二次" >> a.txt && git add . && git commit -m "第二次提交"
echo "第三次" >> a.txt && git add . && git commit -m "第三次提交"
- 查看 log,确认三次提交都在:
git log --oneline
c3f01dc 第三次提交
b2e90ab 第二次提交
a1b2c3d 第一次提交
- 执行”危险操作”:
git reset --hard HEAD~2
- 再看 log,第三次和第二次提交不见了:
git log --oneline
a1b2c3d 第一次提交
- 查看 reflog 找到它们:
git reflog
a1b2c3d HEAD@{0}: reset: moving to HEAD~2
c3f01dc HEAD@{1}: commit: 第三次提交
b2e90ab HEAD@{2}: commit: 第二次提交
- 恢复到
HEAD@{1}:
git reset --hard HEAD@{1}
- 验证:
git log --oneline
c3f01dc 第三次提交
b2e90ab 第二次提交
a1b2c3d 第一次提交
三次提交全部恢复。
Note如果你找不到想要的提交,试试
git fsck --lost-found。它能找到所有”悬挂”的提交对象,不过操作更底层,适合极端情况。
常见使用场景
git reset --hard撤消后反悔git rebase后发现丢了提交git commit --amend覆盖了原始提交- 切换分支后发现之前的提交”不见了”
- 误删分支后想找回那个分支指向的提交
核心记忆:reflog 是你的后悔药。只要没过期,几乎没有救不回来的提交。
这章学到了什么
- reflog 是 Git 的”后悔药”,记录 HEAD 每一次指针移动的轨迹
HEAD@{n}语法沿操作历史回溯,与HEAD~n沿祖先链回溯不同git log看祖先链,git reflog看操作历史,后者包含”丢失”的提交- 找回误删提交的方法:先用 reflog 定位,再用
git reset --hard HEAD@{n}恢复 - reflog 有过期时间,默认可达对象保留 90 天,发现误操作要尽快恢复
下一章,我们学习如何安全地重写提交历史。