什么是 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
哪些属于你自己的改动
所以干脆禁止。
总结,最核心区别
| reset | revert | |
|---|---|---|
| 是否改变历史 | ✅ 会 | ❌ 不会 |
| 是否新增 commit | ❌ 不会 | ✅ 会 |
| 是否安全用于公共分支 | ❌ 不安全 | ✅ 安全 |
| 常见用途 | 本地整理历史 | 回滚线上代码 |
一句话理解
reset
我想撤销代码,同时可以重写历史。
revert
我想撤销代码,但要保留历史。
所以,最经典一句 Git 经验
Never reset public history.(不要对公共历史使用 reset)