误重置后先停止继续修改,区分丢失的是未保存编辑、未提交文件,还是分支引用。恢复的关键不是记住一条 reset 命令,而是确定内容是否曾进入 Git 对象库。
三种可恢复性
跳转到“三种可恢复性”| 丢失内容的状态 | Git 中可能存在什么 | 优先方法 |
|---|---|---|
| 从未 add,也未 commit | 可能完全没有对应对象 | 编辑器本地历史、系统备份、同步版本历史 |
| add 过但未 commit | 通常有内容 blob;不保证有完整 tree | 查找悬空对象,识别内容后导出到新文件 |
| 已经 commit,但分支移动或删除 | 提交及相关对象可能仍在 | reflog 查找提交并建立恢复分支 |
先保存当前仍有价值的文件和 .git 的备份;恢复期间不要运行 gc --prune=now、主动过期 reflog 或大范围清理。对象是否还在取决于引用、过期和垃圾回收,不能保证任何误操作都可恢复。
已提交内容:先找提交,再建分支
跳转到“已提交内容:先找提交,再建分支”git status --short --branchgit reflog --date=isogit log --all --oneline --graph --decorategit 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 --unreachablegit 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 版本中都能无损保存二进制文件。
原 STM32 工程恢复记录
跳转到“原 STM32 工程恢复记录”原记录确实找到了 tree ece95176d7a0d7bacf01180f02615fe7d0cf3a67。它列出了 cameraLcd 工程的 Core、Drivers、Middlewares、CMake 配置及 STM32 链接脚本等路径。此类证据说明那个仓库当时有完整目录树,不说明每次执行 add 都会产生同样的 tree。
对仍含这个对象的原仓库,可以先只读检查:
git cat-file -t ece95176d7a0d7bacf01180f02615fe7d0cf3a67git ls-tree -r ece95176d7a0d7bacf01180f02615fe7d0cf3a67git archive --format=zip --output=../cameraLcd-recovered.zip ece95176d7a0d7bacf01180f02615fe7d0cf3a67对象号仅属于这次历史案例,其他仓库不能照抄。解压到新目录后,对照当前版本检查启动文件、链接脚本和生成代码,再选择性迁回;不要直接以未知 tree 覆盖整个工作区。
日常撤销与事故恢复的边界
跳转到“日常撤销与事故恢复的边界”取消暂存应使用 git restore --staged -- <file>;丢弃未暂存修改才使用 git restore -- <file>。对已公开的错误提交,通常创建 git revert <commit> 的反向提交,保留协作历史。移动本地 HEAD 的 reset 与“追加一次反向修改”的 revert 不是一回事。
恢复完成后,比较实际文件、编译或运行关键测试,并提交确认后的内容。仅找到一个对象号不代表已经恢复成功。