Git引入Bug后回滚并保留修改的正确方法?附实操问题求助
哥们,你现在看不到ABC提交是因为它不在当前分支的提交链上,但Git才不会随便丢东西!你只要敲这个命令就能找到它:
git reflog
这个命令会记录所有HEAD的移动历史,不管是分支上的还是游离的提交。你找一下标注着commit ABC的那条,旁边会有个短哈希(比如abc123),记下来这个哈希值。
接下来要从ABC里恢复单个文件,用git restore就很方便,语法是这样的:
git restore --source=abc123 src/your-problem-file.js
把src/your-problem-file.js换成你要恢复的具体文件路径就行。每恢复一个就测试一下,直到定位到出问题的那个文件。
等你把所有需要的修改都转移到DEF的工作区后,那个ABC提交就没用了。因为你还没推到远程,不用太担心它污染历史——只要没有任何分支引用它,过段时间Git的垃圾回收会自动把它清掉。如果想立刻清理,也可以敲这俩命令:
git reflog expire --expire=now --all git gc --prune=now
不过更稳妥的是,先把当前的修改提交到一个新分支上(比如基于DEF建个fix-bug分支提交),ABC自然就成了没人要的游离提交,不用手动删也没事。
其实你一开始完全没必要建那个TEMP提交,有几种更灵活的方式处理这种“代码炸了但不想丢修改”的场景:
方式1:用git stash暂存修改,随时取用
当你发现DEF之后的修改出问题,但又不想丢这些改动,直接敲:
git stash
这会把你当前工作区和暂存区的所有修改打包存到一个“储藏箱”里,你的工作区瞬间回到DEF的干净状态。之后你可以:
- 单个取出储藏里的文件:
git restore --source=stash@{0} src/your-file.js,stash@{0}是最近的一次储藏,要是有多个就改数字。 - 或者先把整个储藏恢复回来,再逐步撤销:
git stash pop,然后用git reset HEAD src/your-file.js把文件变回未暂存状态,一个个测试着撤销。
方式2:新建分支,选择性拉取修改
要是你已经改了一大堆,不想用stash,直接切到DEF并新建一个分支:
git checkout DEF -b debug-bug
然后从你原来的分支(比如main)里逐个把修改的文件拉过来:
git checkout main -- src/your-file.js
这样你能精准控制每个文件是否引入,测试没问题再提交,比建临时提交灵活多了。
方式3:用git reset --soft回退,保留修改
要是你已经提交了ABC(就是你现在的情况),其实不用切到游离HEAD状态,直接在原来的分支上敲:
git reset --soft DEF
这样你的分支会回到DEF的状态,但ABC里的所有修改都会留在暂存区里。之后你可以用git reset HEAD src/your-file.js把文件移到工作区,逐个测试调整,最后重新提交正确的修改。这样ABC提交就会被分支历史“覆盖”,不会出现在公开的提交链里,之后清理下reflog就能彻底移除它。
- 还没提交错误修改时:优先用
git stash暂存,或者新建分支选择性恢复文件,比建临时提交顺手太多。 - 已经建了临时提交:用
git reflog找回它,转移完需要的修改后,要么用git reset --soft回退分支重新提交,要么就让它当游离提交等Git自动清理。
内容的提问来源于stack exchange,提问作者WhiskerBiscuit

