Appearance
git reflog —— 最后的安全网
git reflog(Reference Log,引用日志)记录了 HEAD 的所有移动历史,是 Git 中最强大的"后悔药"。即使你执行了 reset --hard、删除了分支,也能通过 reflog 找回丢失的提交。
reflog 的工作原理
每当 HEAD 移动时(提交、切换分支、reset、rebase 等),Git 都会在 reflog 中记录一条日志。
reflog 存储位置:
.git/logs/HEAD:HEAD 的 reflog.git/logs/refs/heads/<branch>:每个分支的 reflog
bash
# 查看 HEAD 的 reflog
cat .git/logs/HEAD
# 格式:
# <旧 SHA-1> <新 SHA-1> <用户信息> <时间戳> <操作描述>
# 0000... abc123 Zhang San <zhang@ex.com> 1704067200 +0800 commit (initial)
# abc123 def456 Zhang San <zhang@ex.com> 1704067260 +0800 commit: feat: 功能A查看与解读 reflog
bash
# 查看 HEAD 的 reflog
git reflog
git reflog HEAD # 等价
# 输出示例:
# abc123 HEAD@{0}: reset: moving to HEAD~3 ← 最近的操作(刚才执行的 reset)
# def456 HEAD@{1}: commit: feat: 添加功能C ← reset 之前的状态(要恢复的)
# ghi789 HEAD@{2}: commit: feat: 添加功能B
# jkl012 HEAD@{3}: commit: feat: 添加功能A
# mno345 HEAD@{4}: checkout: moving from develop to main
# pqr678 HEAD@{5}: commit: fix: 修复 bug输出格式解读:
abc123:操作后 HEAD 指向的 SHA-1HEAD@{0}:reflog 索引(0 是最新的)reset: moving to HEAD~3:操作描述
bash
# 查看特定分支的 reflog
git reflog show main
git reflog show feature/login
# 查看所有引用的 reflog
git reflog --all
# 限制显示数量
git reflog -10
# 显示时间信息
git reflog --date=relative # 相对时间(如 "2 hours ago")
git reflog --date=iso # ISO 格式时间通过 reflog 恢复丢失的提交
场景1:误执行了 reset --hard
bash
# 误操作:reset 到 3 个提交前
git reset --hard HEAD~3
# 查看 reflog 找到 reset 前的状态
git reflog
# abc123 HEAD@{0}: reset: moving to HEAD~3
# def456 HEAD@{1}: commit: feat: 功能C ← 这是 reset 前的 HEAD
# 恢复到 reset 前的状态
git reset --hard def456
# 或者使用 HEAD@{1} 语法
git reset --hard HEAD@{1}场景2:误删了提交后的操作
bash
# 找到丢失的提交
git reflog | grep "feat: 重要功能"
# xyz789 HEAD@{5}: commit: feat: 重要功能
# 方案1:直接重置到该提交
git reset --hard xyz789
# 方案2:创建新分支保存该提交
git branch recovered-branch xyz789
git switch recovered-branch通过 reflog 恢复删除的分支
bash
# 误删了 feature/important 分支
git branch -D feature/important
# 找到该分支最后一次 commit 的 SHA-1
git reflog | grep "feature/important"
# abc123 HEAD@{3}: checkout: moving from feature/important to main
# def456 HEAD@{4}: commit: feat: 重要功能 ← 该分支的最后提交
# 找到后重建分支
git branch feature/important abc123
# 或
git switch -c feature/important abc123更精确的方法:
bash
# 查看分支专属的 reflog(即使分支已删除,记录还在一段时间内)
git reflog show feature/important
# error: 已删除则无法查看
# 替代:搜索所有 reflog
git reflog | grep "feature/important"reflog 的过期时间配置
reflog 不会永远保留,Git 会定期清理过期记录:
bash
# 查看过期配置
git config --get gc.reflogExpire # 默认 90 天
git config --get gc.reflogExpireUnreachable # 默认 30 天(不可达对象)| 配置项 | 默认值 | 说明 |
|---|---|---|
gc.reflogExpire | 90 天 | 从主分支可达的提交的 reflog 保留时间 |
gc.reflogExpireUnreachable | 30 天 | 不可达提交的 reflog 保留时间 |
修改过期时间:
bash
# 延长 reflog 保留时间(更安全)
git config --global gc.reflogExpire "180 days"
git config --global gc.reflogExpireUnreachable "60 days"
# 永不过期(不推荐,占用空间)
git config --global gc.reflogExpire never
git config --global gc.reflogExpireUnreachable never手动清理 reflog:
bash
# 清理所有过期的 reflog
git reflog expire --expire=now --all
# 清理不可达对象(配合 reflog expire 使用)
git gc --prune=nowreflog 的使用场景
bash
# 查找某个时间点的 HEAD 状态
git reflog --date=iso | grep "2026-03-01"
# 恢复到昨天某个时间的状态
git reset --hard HEAD@{yesterday}
git reset --hard HEAD@{"2 days ago"}
git reset --hard HEAD@{"2026-03-01 10:00:00"}
# 查看最近 24 小时内的所有操作
git reflog --since="24 hours ago"reflog vs git log
| 对比项 | git log | git reflog |
|---|---|---|
| 显示内容 | 提交历史(DAG) | HEAD 移动历史 |
| 包含操作 | 只有提交 | 提交、reset、checkout、rebase 等 |
| 持久性 | 永久(在引用可达时) | 有过期时间(默认 90 天) |
| 适用场景 | 查看项目历史 | 找回丢失操作 |
| 范围 | 所有人 | 只有本地操作记录 |
重要:reflog 是本地的,克隆后的新仓库没有原仓库的 reflog。
最佳实践
遇到问题,先查 reflog:几乎所有"丢失"的提交都能在 reflog 中找到
操作前查看 reflog 序号:危险操作前记录当前
HEAD@{0}的值,便于回滚不要手动清理 reflog:让 Git 自动管理,避免过早失去安全网
理解 reflog 的时效性:不可达对象只保留 30 天,重要数据及时创建分支或标签
bash
# 危险操作前的好习惯
git reflog # 记下当前 HEAD@{0} 的哈希
git tag backup-before-rebase # 创建临时标签作为保险
# 操作后如果出错
git reset --hard backup-before-rebase
git tag -d backup-before-rebase # 清理临时标签总结
| 操作 | 命令 |
|---|---|
| 查看 reflog | git reflog |
| 查看含时间的 reflog | git reflog --date=iso |
| 恢复到某个 reflog 点 | git reset --hard HEAD@{n} |
| 从 reflog 恢复分支 | git branch <name> <sha> |
| 搜索特定操作 | git reflog | grep "关键词" |
git reflog 是 Git 学习者最应该知道的"后悔药"。记住:在 Git 中,只要提交过,几乎总能找回——前提是 reflog 还未过期。