Git撤销命令revert与reset区别全面对比

好的,这是一个非常核心且常见的 Git 问题。git revertgit reset 都是用于撤销更改的命令,但它们的工作方式、目的和影响有本质的区别。理解它们对于安全有效地管理 Git 历史至关重要。

图片[1]_Git撤销命令revert与reset区别全面对比_知途无界

下面我将从多个维度对它们进行全面的对比。


核心思想与比喻

  • ​**git reset​:​​“时光倒流”​**。它直接将分支的 HEAD 指针移动到指定的提交,仿佛后面的提交从未发生过。​它重写历史
    • 比喻​:你把一本书的某一页之后的所有内容都撕掉了,然后用胶水把书页粘回原来的位置。对于这本书(你的本地仓库)来说,被撕掉的内容不存在了。但如果你已经把书(仓库)复印了很多份给了别人(推送到远程),他们手里的复印件还是有那些内容的。
  • ​**git revert​:​​“撤销更改”​**。它创建一个新的提交,这个新提交的内容正好抵消(reverse)指定旧提交的更改。​它不修改历史,而是在历史后面追加新记录
    • 比喻​:你在书的末尾新增加了一页,标题是“修正第X页的错误”,这一页的内容正好是把第X页的错误涂抹掉。这本书的历史是完整的,所有人都能看到你做了一次修正。

全面对比表格

特性git resetgit 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~1
git 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 的更改,同时保留 BD 的历史。

步骤​:

  1. 执行命令:git revert <C的commit-hash>
    • 这会打开编辑器,让你为这次 revert 操作编写一个提交信息(默认信息是 Revert "Commit C message")。
  2. 保存并关闭编辑器后,Git 会创建一个新的提交 E,其内容正好是 C 的反向操作。

结果​:历史变成了一条直线,并且完整地记录了“做了什么”和“撤销了什么”。

... --- A --- B --- C --- D --- E (HEAD -> main)
                          ↑           ↑
                        (bug引入)   (bug修复)

优点​:

  • 安全:如果 D 已经推送到远程,你也可以安全地将 E 推送上去,不会造成协作冲突。
  • 清晰:历史记录了整个事件的来龙去脉。
方案二:使用 git reset

目标​:从历史上彻底抹去提交 C

步骤​:

  1. 执行命令:git reset --hard <B的commit-hash>
    • 警告​:--hard 会让你丢失 CD 的所有工作!如果你之后还需要 D 的改动,请先创建一个备份分支。
  2. 现在,你的本地 main 分支指向了 BCD 的提交从当前分支历史中消失了。

结果​:历史被改写,看起来像是直接从 B 跳到了 D 之后的状态(但实际上 D 的工作可能已丢失)。

... --- A --- B (HEAD -> main)

后续操作​:

  • 如果你想保留 D 的改动,可以在 reset 后重新应用它们(但会产生一个新的提交哈希)。
  • 如果你想让远程仓库也同步这个“干净”的历史,你必须使用 git push --force(或 git push --force-with-lease)。​这是非常危险的命令,因为它会用你的本地历史覆盖远程历史,可能导致其他协作者的提交丢失。

缺点​:

  • 危险:强制推送会破坏团队协作的约定,可能导致同事的工作成果被覆盖。
  • 不透明:历史被改写,其他人无法通过 git log 看到 CD 曾经存在过。

如何选择?黄金法则

  1. 是否已经将代码推送到远程仓库(与他人共享)?​
    • ​ -> ​使用 git revert。这是唯一安全的选择。
    • ​(仅在你的本地仓库)-> 可以继续考虑 git reset
  2. 你想保留完整的操作历史,还是想得到一个干净的线性历史?​
    • 保留历史​(推荐用于团队协作)-> ​使用 git revert
    • 得到干净历史​(常用于个人分支整理)-> ​使用 git reset
  3. 你想撤销一次提交,还是想彻底丢弃一段错误的开发?​
    • 撤销一次提交​ -> ​使用 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
喜欢就点个赞,支持一下吧!
点赞17 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容