revert

4 阅读2分钟

什么是 revert

一句话:

git revert = 创建一个新的 commit,用来“反向撤销”某个 commit 的修改。

注意:

❗它不会删除历史
❗不会改变 commit 结构

假设历史是:

A --- B --- C --- D   (master)

现在发现:

C 是一个 bug

执行:

git revert C

Git会创建一个新的提交:

A --- B --- C --- D --- C'

其中:

C' = C 的反向修改

也就是:

C 做了什么
C' 就撤销什么

为什么不用 reset?

因为reset会改变历史,是有风险的

Git revert 的设计哲学是:

不要删除历史,而是记录新的历史。

所以:

错误提交
↓
revert commit
↓
新的历史

但是revert可能会产生冲突:

因为什么呢?因为 = 新的提交,修改了代码,那么就有可能产生冲突

例如上面的例子,D 的改动不会消失。
revert C 只会撤销 C 引入的改动,而不会影响 D 的改动(但是有可能D和C改了相同的地方)。

假设代码变化是这样的:

B 的代码

x = 1

C 改成:

x = 2

D 在 C 的基础上继续修改:

x = 3

执行 git revert C

C 的 diff 是:

- x = 1
+ x = 2

反向 diff 是:

- x = 2
+ x = 1

然后 Git 尝试把这个反向 diff 应用到 当前代码(D)

于是:

👉 会产生冲突。

你会看到:

<<<<<<< HEAD
x = 3
=======
x = 1
>>>>>>> revert

你需要手动解决。

用一句最准确的话总结

git revert C 的行为是:

撤销 C 引入的 patch,而不是回到 B 的整个状态。

注意:revert没有 发现冲突时,会自动提交产生一个新的commit,但是如果有冲突,就需要手动提交commit了

另外:

关于工作区和暂存区:

工作区有改动时,有时候可以 revert,有时候不可以。关键取决于:

你的工作区改动会不会被 revert 的修改覆盖。

revert 的原则是:
不会悄悄覆盖你的本地修改。,注意,是覆盖,如果对工作区,出现了覆盖的现象,git会拒绝你的revert操作

至于暂存区:

如果暂存区有未提交的修改,git revert 大多数情况下会直接拒绝执行。

原因是:

revert 需要一个 干净的 index(暂存区) 来生成新的 commit。

因为 revert 会创建 commit。

而 commit 的内容是:

index(暂存区)的快照

如果 index 已经有东西:

原来的暂存修改
+ revert 修改

Git很难判断:

哪些属于 revert
哪些属于你自己的改动

所以干脆禁止。

总结,最核心区别

resetrevert
是否改变历史✅ 会❌ 不会
是否新增 commit❌ 不会✅ 会
是否安全用于公共分支❌ 不安全✅ 安全
常见用途本地整理历史回滚线上代码

一句话理解

reset

我想撤销代码,同时可以重写历史。

revert

我想撤销代码,但要保留历史。

所以,最经典一句 Git 经验

Never reset public history.(不要对公共历史使用 reset)