误推 master 该 revert 还是 reset?撤销与补 MR 流程

0 阅读3分钟

前两天开发完一个功能,习惯性 git commitgit push——刷新远程,提交直接落在了 master。CI 已经跑了一分钟,群里有人问谁合的。

一句话结论:已 push 到共享 master → git revert;只在本地、还没 push → git reset


一、revert 和 reset 怎么选

git revertgit reset
做法新增反向 commit,原 commit 仍在移动分支指针,可抹掉 commit
远程安全,不改写公共历史force push,影响他人
适用master / 共享分支本地或未 push 的分支
情况用什么
已 push 到 mastergit revert
本地 commit,未 pushgit reset --soft/mixed
刚 push、无人 pull、负责人确认极少数 reset + --force-with-lease(非常规,慎用)
commit 含密钥revert 当前代码 + 必须 git-filter-repo 清历史 + 轮换密钥(revert 删不掉历史里的密钥)

二、已 push:revert 撤回 + 处理 SOP

别慌,按顺序来:

步骤做什么
1. 停不要立刻 force push,先看 CI 和同事有没有 pull
2. 查git log origin/master -5
3. 撤git revert HEAD(多个 commit 见下)→ git push origin master
4. 告通知团队 pull,别在误提交上继续开发
5. 补流程需要 MR 记录时,走第三节 Case 2
6. 防配分支保护 + pre-push hook
git log --oneline -5
git revert HEAD                 # 单个 commit
git push origin master

# 多个误提交:一次性 revert 再提交(比逐个 revert 少冲突)
git revert --no-commit HEAD~2..HEAD
git commit -m "Revert mistaken commits on master"
git push origin master

01-git-revert-single.gif

冲突:手动改完冲突文件 → git add <file>git revert --continue


三、补走 MR 流程:三种 merge 场景

图例:A = 误推的功能 commit;B/C = 分支上后续 commit;R = revert;M = MR 合并。

Case操作结果
1拉分支,master 不 revert,直接 merge无效——分支与 master 都有 A,提示 Already up to date
2拉分支 → master revert → MR merge标准做法,代码回到误推后状态,历史留 Review
3amaster 仍含 A,分支上又有 B、C,直接 merge,只合入 B、C 增量
3bmaster 已 revert(有 R),分支含 A、B、C,再 merge,A+B+C 一并合回

最常见走 Case 2;分支上若还继续提交了 B、C,按 3a 或 3b 处理。

顺序不能反:

正确:先拉分支(含 A)→ master revert(产生 R)→ MR 合回(产生 M)
错误:先 revert 再拉分支 → 分支没有功能 commit,合不回来
错误:只拉分支不 revert → Case 1,merge 无效

Case 2 完整流程(补规范标准做法,历史上会多 R 和 M,但比 force push 安心):

git checkout master && git pull
git checkout -b feature/order-fix    # ① 从含误提交的 master 拉分支
git push -u origin feature/order-fix

git checkout master
git revert HEAD                      # ② 单个;多个见第二节
git push origin master

# ③ 提 MR:feature/order-fix → master

02-case2-mr-workflow.gif

MR 合并后 master 代码与误推后一致。分支若还有 B、C(Case 3),合入后会比当初误推时更多:

Case 2:master: ... ── A ── R ── M     feature: ... ── A
Case 3:master: ... ── A ── R ── M     feature: ... ── A ── B ── C

四、还没 push:用 reset

git reset --soft HEAD~1    # 撤销 commit,改动留暂存区
git reset HEAD~1           # 改动留工作区
git reset --hard HEAD~1    # 彻底丢弃(慎用)

03-git-reset-local.gif 若还想补 MR 流程:git branch feature/xxx 带走 commit → master 上 reset 回远程 → push feature → 提 MR。


五、预防:靠门禁,不靠口头约定

远程(团队必配):Gitee / GitHub 保护 master——禁止 direct push,必须 PR/MR + Review。配好后直推会被拒绝。

本地兜底.githooks/pre-push 拦截 master 直推:

#!/bin/sh
for p in master main; do
  b=$(git symbolic-ref HEAD 2>/dev/null | sed 's|.*/||')
  t=$(git rev-parse --abbrev-ref @{u} 2>/dev/null | sed 's|.*/||')
  [ "${t:-$b}" = "$p" ] && echo "禁止 push 到 $p,请走 feature + MR" && exit 1
done
git config core.hooksPath .githooks && chmod +x .githooks/pre-push

习惯:开功能先 git checkout -b feature/xxx;push 前看 git branch --show-current。CI 侧 master 只跑测试、不自动发布。


六、参考内容