花拾录
← 返回知识库

Git 提交历史被改乱之后:用 reflog、cherry-pick 找回丢失分支的完整流程

软件工程 / 工具AI2026/09/271 阅读0 评论

先别慌:Git 很少真的丢东西

误执行 git reset --hard、git rebase 出错、误删分支后,很多人第一反应是去翻备份。实际上只要提交对象还在本地仓库的 .git/objects 里没被垃圾回收,就有机会找回。Git 的 reflog 会记录 HEAD 和分支引用的移动历史,这是恢复的第一入口。

注意两点前提:

  • 恢复操作要在同一个本地仓库里做,换机器或重新 clone 通常无效。
  • 越早操作越好。默认情况下不可达对象会在 gc.reflogExpire(reflog 条目,默认 90 天)和 gc.reflogExpireUnreachable(不可达条目,默认 30 天)之后被清理,执行过 git gc --prune=now 会立即清掉。

第一步:用 reflog 定位丢失的提交

git reflog

输出形如 HEAD@{3}: reset: moving to HEAD~1,每行左侧是提交哈希,右侧是这次引用移动的原因。找到“改乱之前”的那一条,记下它的哈希。

如果只想看某个分支的历史:

git reflog show <branch-name>

只想确认这个提交内容对不对,先用只读方式查看:

git show <hash>
git log --oneline -5 <hash>

确认无误后再决定怎么恢复。

第二步:选择恢复方式

情况 A:整个分支被 reset 或删掉了

如果分支名还在,只是指向了错误位置:

git branch -f <branch-name> <hash>

如果分支已被删除,直接重新创建:

git branch <branch-name> <hash>

然后 git checkout <branch-name> 切过去检查。

情况 B:当前分支需要整体回到旧状态

git reset --hard <hash>

这条命令会丢弃工作区和暂存区的改动,执行前先确认没有未提交的重要修改(可以先 git stash)。

情况 C:只想要其中一两个提交,不想回退整条历史

这正是 cherry-pick 的用途。把目标提交“摘”到当前分支上:

git cherry-pick <hash>

多个提交按顺序写:

git cherry-pick <hash1> <hash2>

一段连续区间用 A..B(不含 A)或 A^..B(含 A)。如果冲突,解决后执行 git cherry-pick --continue;想放弃则 git cherry-pick --abort。

第三步:验证与收尾

恢复之后不要只看 git log 就结束,建议逐项确认:

  1. git log --oneline --graph --all 看整体拓扑是否合理。
  2. git status 确认工作区干净。
  3. 跑一遍测试或构建,确认代码内容真的回来了。
  4. 需要推送时,如果历史被改写,通常要 git push --force-with-lease(比 --force 安全,会在远端被别人更新过时拒绝推送)。共享分支上强推前先和协作者沟通。

几个容易踩的坑

  • reflog 是本地记录,不会随 push 同步到远端,别人仓库里查不到你的操作轨迹。
  • git fsck --lost-found 可以列出悬空对象(dangling commit/blob),在 reflog 也找不到时作为兜底手段,但输出可读性差,需要逐个 git show 辨认。
  • rebase 过程中出错,可以 git rebase --abort 回到起点;已经 rebase 完才发现问题,同样用 reflog 找到 rebase 前的 HEAD@{n} 回退。
  • 恢复成功后,如果确定不再需要旧对象,再让 Git 自然回收即可,不必手动 gc。

一句话总结:git reflog 找哈希,git branch -f / git reset --hard 回退,git cherry-pick 挑着捡,最后验证再推送。

评论(0)

  • 还没有评论,来抢沙发~

相关文章