git revert 是安全、可追溯的回退方式,通过创建反向新提交抵消目标更改,不改写历史,适用于已推送的协作场景;撤销合并提交需加 -m 1,多提交须倒序执行。

能 revert 就别 reset --hard + force-push,除非你有绝对控制权且已通知所有人。 revert 是唯一安全、可协作、留痕的线上回退方式;reset 强推会改写历史,破坏他人本地仓库,引发后续各种 merge 冲突和 reflog 错乱。
git revert commit-hash 基本用法
revert 不是删除提交,而是“生成一个反向操作的新提交”,所以它不改变原有提交链,所有历史都保留,只是多了一条“撤销”记录。
- 适用场景:错误提交已
git push到远程(如origin/main),多人正在基于该分支开发 - 命令格式:
git revert <commit-hash></commit-hash>(例如git revert abc1234) - 执行后会打开编辑器让你确认提交信息,默认是
Revert "xxx",可直接保存 - 之后必须
git push origin main把这个 revert 提交推上去——它才是真正的“撤回”动作
revert 合并提交必须加 -m 1
当你 revert 的是一个 git merge 产生的提交(比如把 feature/login 合进 main),Git 会报错:Commit abc1234 is a merge but no -m option was specified。这是因为合并提交有两个父提交,Git 不知道该以哪条线为基准做反向计算。
-
-m 1表示以第一个父提交(即合并前的主干,比如main当时的 HEAD)为基准——这是 95% 场景下的正确选择 -
-m 2表示以第二个父提交(即被合并进来的分支头,比如feature/login的 tip)为基准——极少用,除非你想彻底抹掉整个 feature 分支的所有引入变更 - 查证方法:
git show --pretty=raw abc1234,看parent行顺序:第一行是-m 1,第二行是-m 2 - 安全写法:
git revert -m 1 abc1234
revert 多个提交的顺序很关键
如果你要 revert 连续多个提交(比如从 C3 到 C5),必须**倒序 revert**:先 git revert C5,再 git revert C4,最后 git revert C3。否则 Git 会尝试对已被 revert 掉的变更再 revert 一次,结果可能完全相反。
- 原因:每个 revert 都是基于当前工作树状态计算 diff,不是“按哈希删记录”
- 验证方式:
git log --oneline -n 10看清楚提交顺序,从最晚(最靠上)的开始 revert - 批量 revert(慎用):
git revert C3^..C5(注意是C3^..C5,不是C3..C5),它内部仍是倒序执行,但出错时不好定位 - 如果中间某次 revert 出现冲突,解决后
git add . && git revert --continue
revert 后 push 被拒?先 pull --rebase,别硬 push --force
如果你 revert 完还没 push,别人却在这期间 push 了新提交,你直接 git push 会被拒绝(non-fast-forward)。这时不要立刻 git push --force-with-lease,那会把别人的提交也覆盖掉。
- 正确做法:
git pull --rebase origin main—— 它会把你刚做的 revert 提交“重放”到最新远程 HEAD 之后 - 如果 rebase 过程中出现冲突,是因为 revert 修改和别人的新提交有重叠,需手动解决,然后
git add && git rebase --continue - rebase 完成后,
git push origin main就能成功,无需 force - 记住:revert 提交参与 rebase,它的“反向性”不会因 rebase 改变,逻辑依然成立
真正容易被忽略的是:revert 合并提交时的 -m 1 和 revert 多提交时的顺序。这两个点一旦出错,代码状态就不可预期,而且很难通过 git log 直观发现——得靠 git diff 对比文件内容才能察觉。











