改错代码、提交错分支、工作区被搞乱——Git 误操作几乎是每个开发者的必经之路。本文按三种典型场景给出急救步骤,最后再用 reflog 兜底,看完这篇基本可以告别「代码找不回来了」的恐慌。
场景一:刚 commit 了不该提交的内容(还没 push)
这是最安全的情况,本地还没有同步出去,直接用 reset 回退即可。关键是分清三档模式:
# 软重置:撤销 commit,改动保留在暂存区(最常用,想重新组织提交时用)
git reset --soft HEAD~1
# 混合重置(默认):撤销 commit 和暂存,改动保留在工作区
git reset HEAD~1
# 硬重置:撤销 commit、暂存和工作区,改动直接丢弃(危险,想清楚再用)
git reset --hard HEAD~1
选择口诀:改动还想留就 soft,想重新改就 mixed(默认),确定不要了才 hard。
回退多个提交时,HEAD~n 中的 n 换成数量即可,也可以直接指定 commit id:git reset --soft <commit-id>,回退到该提交之后的状态。
场景二:错误提交已经 push 到远端
远端已经有人可能拉取了代码,这时不要用 reset 改写历史,用 revert 生成一个反向提交:
# 撤销某次提交的改动,生成一个新的「反向提交」
git revert <commit-id>
# 撤销最近一次提交
git revert HEAD
# 批量撤销一段连续提交(不含 oldest,含 newest)
git revert oldest-commit-id..newest-commit-id
revert 的好处是历史不会被改写——错误提交和撤销操作都完整保留,别人拉取不会产生冲突。多人协作分支(main / develop)上的误操作,revert 永远是首选。
如果误操作只是把不该提交的文件(如配置文件、日志)commit 了进去,也可以用 git rm --cached <file> 移出跟踪后 amend:
git rm --cached application-prod.yml
git commit --amend --no-edit # 修改本次提交而不新建提交(仅限未 push 或确认无他人拉取时)
场景三:本地改了一半,需要临时切分支
手头改动还没法提交,但必须切到别的分支修线上问题——这是 stash 的主场:
git stash # 暂存全部未提交改动(含暂存区)
git stash -u # 连未跟踪的新文件一起暂存
git stash pop # 恢复最近一次暂存并删除记录
git stash apply # 恢复但保留记录(想应用到多个分支时用)
git stash list # 查看所有暂存
git stash pop stash@{2} # 恢复指定某一次暂存
git stash drop stash@{0} # 删除某条暂存记录
一个实用习惯:暂存时加备注,方便半天后想起来这是哪次改动:
git stash push -m 「修复订单金额精度-进行到一半」
注意:stash 只作用于当前分支的工作区,pop 恢复时如果目标分支同文件有冲突,Git 会提示冲突而不是覆盖,此时解决冲突后需要手动 git stash drop。
兜底:reflog 找回一切
reset --hard 之后发现误删了有用的提交?别慌,只要提交过的内容,reflog 里都有记录:
git reflog # 查看本地所有 HEAD 移动记录
# 输出示例:
# a1b2c3d HEAD@{0}: reset: moving to HEAD~2
# e4f5g6h HEAD@{1}: commit: 完成支付回调逻辑
git reset --hard e4f5g6h # 跳回任意历史状态,被删的提交就回来了
reflog 默认保留 90 天,这就是 Git 说的「几乎不会真正丢失提交」。唯一救不回来的是从未 commit 过的工作区改动——所以重要改动勤 commit,反正可以 squash。
更多分支与撤销操作可以对照速查表使用:Git 命令速查、Git 撤销与回退速查。