跳转到内容
新建笔记

Git 恢复:误重置、reflog 与悬空对象

误重置后先停止继续修改,区分丢失的是未保存编辑、未提交文件,还是分支引用。恢复的关键不是记住一条 reset 命令,而是确定内容是否曾进入 Git 对象库。

丢失内容的状态Git 中可能存在什么优先方法
从未 add,也未 commit可能完全没有对应对象编辑器本地历史、系统备份、同步版本历史
add 过但未 commit通常有内容 blob;不保证有完整 tree查找悬空对象,识别内容后导出到新文件
已经 commit,但分支移动或删除提交及相关对象可能仍在reflog 查找提交并建立恢复分支

先保存当前仍有价值的文件和 .git 的备份;恢复期间不要运行 gc --prune=now、主动过期 reflog 或大范围清理。对象是否还在取决于引用、过期和垃圾回收,不能保证任何误操作都可恢复。

已提交内容:先找提交,再建分支

跳转到“已提交内容:先找提交,再建分支”
终端窗口
git status --short --branch
git reflog --date=iso
git log --all --oneline --graph --decorate
git show --stat <candidate-commit>
git branch recovery/lost-work <candidate-commit>

把 <candidate-commit> 替换为核实后的提交号;建立分支不会立即覆盖工作区。进一步检查可用 git show recovery/lost-work:path/to/file,或在新的工作区中检出恢复分支。PowerShell 中引用 reflog 写作 'HEAD@{7}',避免大括号被解释。

reflog 记录引用移动,不记录每一次键盘编辑;它也不是跨机器永久备份。

已暂存内容:检查对象类型

跳转到“已暂存内容:检查对象类型”
终端窗口
git fsck --full --no-reflogs --unreachable
git cat-file -t <object-id>
git cat-file -s <object-id>

--no-reflogs 让检查不把 reflog 当作可达根,便于发现对象;这不会删除 reflog。看到对象后区分 blob、tree、commit:

  • blob 保存文件内容,一般不保存原路径;需通过内容确认是什么文件。
  • tree 记录目录和对象关系,可用 git ls-tree -r <tree-id> 查看路径。
  • commit 关联树、父提交和元数据,可以建立恢复分支。

git fsck --lost-found 可把悬空对象写入 .git/lost-found,其中 blob 会写成原始内容。先把需要的内容复制到新的恢复目录;不要假设终端重定向在所有 PowerShell 版本中都能无损保存二进制文件。

原记录确实找到了 tree ece95176d7a0d7bacf01180f02615fe7d0cf3a67。它列出了 cameraLcd 工程的 Core、Drivers、Middlewares、CMake 配置及 STM32 链接脚本等路径。此类证据说明那个仓库当时有完整目录树,不说明每次执行 add 都会产生同样的 tree。

对仍含这个对象的原仓库,可以先只读检查:

终端窗口
git cat-file -t ece95176d7a0d7bacf01180f02615fe7d0cf3a67
git ls-tree -r ece95176d7a0d7bacf01180f02615fe7d0cf3a67
git archive --format=zip --output=../cameraLcd-recovered.zip ece95176d7a0d7bacf01180f02615fe7d0cf3a67

对象号仅属于这次历史案例,其他仓库不能照抄。解压到新目录后,对照当前版本检查启动文件、链接脚本和生成代码,再选择性迁回;不要直接以未知 tree 覆盖整个工作区。

日常撤销与事故恢复的边界

跳转到“日常撤销与事故恢复的边界”

取消暂存应使用 git restore --staged -- <file>;丢弃未暂存修改才使用 git restore -- <file>。对已公开的错误提交,通常创建 git revert <commit> 的反向提交,保留协作历史。移动本地 HEAD 的 reset 与“追加一次反向修改”的 revert 不是一回事。

恢复完成后,比较实际文件、编译或运行关键测试,并提交确认后的内容。仅找到一个对象号不代表已经恢复成功。

参考:git-fsck、git-reflog、git-cat-file、git-archive。