1. 从“手滑”到“心凉”:一次典型的文件丢失事故
那天下午,我正沉浸在一个新功能的开发中,代码写得很顺,不知不觉已经修改了几十个文件。就在我准备提交代码,切换到另一个分支去修复一个紧急bug时,我犯了一个几乎所有开发者都会犯的“手滑”错误。我本意是想用 git reset --hard HEAD~1 回退一个本地提交,但不知怎么的,脑子一抽,手指就敲下了 git reset --hard origin/master。回车键按下的瞬间,我甚至还没反应过来,直到看到终端里飞速滚过的“HEAD is now at...”提示,再一瞥我的工作区——一片空白。整整一下午的心血,那些还没 git add 的新文件,那些已经 git add 但还没 git commit 的修改,全都没了。那一刻,感觉心都凉了半截,血压估计都上来了。
我相信这种“心凉”的瞬间,很多朋友都经历过。git reset --hard 加上远程分支,比如 origin/master,是一个破坏性极强的命令。它做的不是简单的回退,而是强制将你的本地工作目录、暂存区(Index)和当前分支指针,全部同步到远程仓库的指定提交状态。这意味着,所有你本地独有的、尚未推送到远程的提交历史,会被直接丢弃;所有你修改了但还没提交的文件,会被无情地覆盖回远程版本;所有你新建了但还没加入版本控制的文件,虽然不会被Git覆盖,但它们的状态与Git无关,而你已经修改的、Git跟踪着的文件,内容就彻底被旧版本替换了。简单说,除了你手动 git push 上去的东西,其他本地改动都可能灰飞烟灭。
但别急着砸键盘或者开始回忆“Ctrl+Z”在Git里有没有用。我想告诉你的是,只要你执行过 git add(哪怕只是 add 了,没 commit),你的代码就很可能还“活”在Git的内部世界里,只是变成了一个“无家可归”的孤儿,技术上称之为 dangling object(悬空对象)。而我们的救星,就是那个平时存在感极低,但关键时刻能救命的命令——git fsck。这篇文章,我就以一个踩过坑的过来人身份,带你一步步摸清Git的“垃圾回收站”,把那些看似丢失的dangling对象找回来,完整复原你的工作成果。
2. 理解Git的“时光机”与“垃圾站”:对象数据库与dangling对象
要找回文件,我们得先明白Git把东西丢哪儿了。你可以把Git想象成一个超级严谨的图书馆管理员,它管理着一个对象数据库(Object Database)。你每次的提交(commit)、文件快照(blob)、目录树(tree),都会被这个管理员转换成一个个唯一的、由SHA-1哈希值(现在新版本Git也支持SHA-256了)命名的“包裹”,存进仓库的 .git/objects 目录里。当你执行 git add 时,你修改的文件内容就被打包成一个 blob对象 存了进去。当你执行 git commit 时,Git会创建一个 commit对象 指向一个 tree对象(代表项目快照),而这个tree对象又指向一系列blob和其他tree对象。
那么,git reset --hard origin/master 之后发生了什么?这个命令把当前分支的指针(比如 <

1609

被折叠的 条评论
为什么被折叠?



