好的,这是一个非常核心且常见的 Git 问题。git revert 和 git reset 都是用于撤销更改的命令,但它们的工作方式、目的和影响有本质的区别。理解它们对于安全有效地管理 Git 历史至关重要。
![图片[1]_Git撤销命令revert与reset区别全面对比_知途无界](https://zhituwujie.com/wp-content/uploads/2025/12/d2b5ca33bd20251213104404.png)
下面我将从多个维度对它们进行全面的对比。
核心思想与比喻
- **
git reset:“时光倒流”**。它直接将分支的 HEAD 指针移动到指定的提交,仿佛后面的提交从未发生过。它重写历史。- 比喻:你把一本书的某一页之后的所有内容都撕掉了,然后用胶水把书页粘回原来的位置。对于这本书(你的本地仓库)来说,被撕掉的内容不存在了。但如果你已经把书(仓库)复印了很多份给了别人(推送到远程),他们手里的复印件还是有那些内容的。
- **
git revert:“撤销更改”**。它创建一个新的提交,这个新提交的内容正好抵消(reverse)指定旧提交的更改。它不修改历史,而是在历史后面追加新记录。- 比喻:你在书的末尾新增加了一页,标题是“修正第X页的错误”,这一页的内容正好是把第X页的错误涂抹掉。这本书的历史是完整的,所有人都能看到你做了一次修正。
全面对比表格
| 特性 | git reset | git revert |
|---|---|---|
| 核心目的 | 将分支指针移动到指定提交,丢弃之后的提交。 | 创建一个新提交来撤销指定提交的更改。 |
| 历史记录 | 重写/删除历史。被重置的提交在工作区和暂存区中消失。 | 保留历史。原有的提交和新创建的 revert 提交都存在于历史中。 |
| 安全性 | 危险(对共享分支)。如果重置已被推送到远程仓库,会破坏协作历史,给其他协作者带来极大困扰。 | 安全(对共享分支)。因为它不修改历史,只是追加新内容,适合团队协作。 |
| 工作区与暂存区 | 有三种模式,影响不同: 1. --soft:只动 HEAD,改动保留在暂存区。2. --mixed(默认):动 HEAD,改动保留在工作区。3. --hard:动 HEAD,且清空工作区和暂存区,彻底丢弃改动。慎用! | 不影响工作区和暂存区的未提交改动。它只针对已提交的更改进行操作。 |
| 使用场景 | 1. 本地分支:撤销本地的、尚未推送的提交。 2. 整理提交:在 git push 前,将多个琐碎的提交合并成一个干净的提交。3. 彻底丢弃:使用 --hard 彻底放弃某次错误的提交及其所有改动。 | 1. 撤销公共提交:安全地撤销已经推送到远程仓库(如 GitHub, GitLab)的提交。 2. 精确的撤销:只想撤销某一次特定提交的影响,而保留之后的其他提交。 |
| 操作对象 | 可以指向任意提交(通过 commit hash, branch, tag 等)。 | 通常指向一个具体的提交(通过 commit hash)。也可以一次撤销一个范围内的多个提交(如 HEAD~3..HEAD)。 |
| 命令示例 | git reset --soft HEAD~1git reset --mixed HEAD~2 (默认)git reset --hard <commit-hash> | git revert <commit-hash>git revert HEAD~3..HEAD (撤销最近3个提交) |
工作流程与示例
假设我们有如下的提交历史,当前位于 HEAD(最新的 Commit D):
... --- A --- B --- C --- D (HEAD -> main)
场景:我们发现提交 C 引入了 bug,需要撤销它。
方案一:使用 git revert
目标:安全地撤销 C 的更改,同时保留 B 和 D 的历史。
步骤:
- 执行命令:
git revert <C的commit-hash>- 这会打开编辑器,让你为这次 revert 操作编写一个提交信息(默认信息是
Revert "Commit C message")。
- 这会打开编辑器,让你为这次 revert 操作编写一个提交信息(默认信息是
- 保存并关闭编辑器后,Git 会创建一个新的提交
E,其内容正好是C的反向操作。
结果:历史变成了一条直线,并且完整地记录了“做了什么”和“撤销了什么”。
... --- A --- B --- C --- D --- E (HEAD -> main)
↑ ↑
(bug引入) (bug修复)
优点:
- 安全:如果
D已经推送到远程,你也可以安全地将E推送上去,不会造成协作冲突。 - 清晰:历史记录了整个事件的来龙去脉。
方案二:使用 git reset
目标:从历史上彻底抹去提交 C。
步骤:
- 执行命令:
git reset --hard <B的commit-hash>- 警告:
--hard会让你丢失C和D的所有工作!如果你之后还需要D的改动,请先创建一个备份分支。
- 警告:
- 现在,你的本地
main分支指向了B,C和D的提交从当前分支历史中消失了。
结果:历史被改写,看起来像是直接从 B 跳到了 D 之后的状态(但实际上 D 的工作可能已丢失)。
... --- A --- B (HEAD -> main)
后续操作:
- 如果你想保留
D的改动,可以在 reset 后重新应用它们(但会产生一个新的提交哈希)。 - 如果你想让远程仓库也同步这个“干净”的历史,你必须使用
git push --force(或git push --force-with-lease)。这是非常危险的命令,因为它会用你的本地历史覆盖远程历史,可能导致其他协作者的提交丢失。
缺点:
- 危险:强制推送会破坏团队协作的约定,可能导致同事的工作成果被覆盖。
- 不透明:历史被改写,其他人无法通过
git log看到C和D曾经存在过。
如何选择?黄金法则
- 是否已经将代码推送到远程仓库(与他人共享)?
- 是 -> 使用
git revert。这是唯一安全的选择。 - 否(仅在你的本地仓库)-> 可以继续考虑
git reset。
- 是 -> 使用
- 你想保留完整的操作历史,还是想得到一个干净的线性历史?
- 保留历史(推荐用于团队协作)-> 使用
git revert。 - 得到干净历史(常用于个人分支整理)-> 使用
git reset。
- 保留历史(推荐用于团队协作)-> 使用
- 你想撤销一次提交,还是想彻底丢弃一段错误的开发?
- 撤销一次提交 -> 使用
git revert <commit-hash>。 - 彻底丢弃最近几次提交,回到之前的状态 -> **使用
git reset --hard <commit-hash>**(务必确保工作已备份!)。
- 撤销一次提交 -> 使用
总结
| 如果你的答案是… | 那么请使用… |
|---|---|
| 撤销已推送的公共提交 | **git revert** |
| 安全地撤销某次更改,并保留历史记录 | **git revert** |
| 在本地整理提交,准备推送前美化历史 | **git reset** |
| 彻底丢弃本地的、未推送的提交 | **git reset --hard** |
| 不确定,或者是在团队项目中 | **优先使用 git revert** |
记住这个简单的口诀:“公共分支用 revert,私有分支用 reset”。在大多数涉及团队协作的场景下,git revert 是你的朋友;只有在你完全掌控本地仓库,并且清楚自己在做什么时,才使用威力巨大但危险的 git reset --hard。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END

























暂无评论内容