Git Revert:安全撤销 Git 提交的完整指南 – wiki大全


Git Revert:安全撤销 Git 提交的完整指南

在软件开发过程中,我们经常会遇到需要撤销或修改 Git 提交的情况。Git 提供了多种方式来处理这种情况,其中 git revert 是一个尤其安全且推荐的选项,特别是当你需要撤销已推送到共享仓库的提交时。本文将深入探讨 git revert 的工作原理、使用场景、具体操作以及它与 git reset 等其他撤销命令的区别。

什么是 git revert

git revert 命令用于撤销(或“反转”)一次或多次现有的提交。它通过创建一个新的提交来引入一个与被撤销提交相反的更改集。这意味着原始的提交历史保持不变,而新的提交则有效地“撤销”了之前的更改。

核心思想: 不修改历史,而是用一个新的提交来抵消旧提交引入的更改。

git revert 的工作原理

假设你有一个提交 C,它引入了一个新功能或修复了一个 bug。后来你发现 C 导致了新的问题,需要撤销。git revert C 命令会执行以下操作:

  1. 识别更改: Git 会找出提交 C 相对于其父提交所引入的所有更改(添加、删除、修改)。
  2. 反向应用: Git 会尝试将这些更改的反向操作应用到当前工作目录。例如,如果 C 添加了一行代码,revert 提交就会删除那一行;如果 C 修改了一行,revert 提交就会恢复到修改前的状态。
  3. 创建新提交: 如果反向应用成功,Git 会为你准备一个新提交,其中包含了这些反向更改。你将被要求为这个新的撤销提交撰写提交信息。
  4. 保存历史: 原始提交 C 仍然存在于历史中,只是在其之后多了一个撤销提交 R

为什么 git revert 是安全的?

git revert 之所以被称为“安全”的撤销方式,主要有以下几个原因:

  1. 不改写历史: 这是最关键的一点。git revert 不会删除或修改任何已存在的提交。这意味着它不会破坏共享仓库的历史,这对于团队协作至关重要。如果一个提交已经被推送到远程仓库并被其他人拉取,使用 git reset 来修改或删除它会造成其他协作者的历史混乱。
  2. 可追溯性: 撤销操作本身也是一个提交,因此它完全可追溯。你可以清楚地看到哪个提交撤销了哪个功能,这对于审计和理解项目演变非常有帮助。
  3. 适用于已推送的提交: 当你发现一个已推送到远程仓库的提交有问题时,git revert 是唯一的正确选择。

git revert 的使用场景

  • 撤销已推送到远程仓库的提交: 这是 git revert 最主要和推荐的使用场景。
  • 撤销一个错误的提交,但保留其历史记录: 当你需要明确记录撤销行为时。
  • 撤销一个合并提交(Merge Commit): git revert 可以处理合并提交,但需要指定主线父提交(通常是第一个父提交)。
  • 作为 git reset --hard 的替代方案: 在个人分支上,如果你想撤销更改但又不想完全丢弃历史,git revert 也是一个不错的选择,尽管 git reset 在这种情况下可能更直接。

git revert 命令详解

1. 撤销单个提交

bash
git revert <commit-hash>

  • <commit-hash> 替换为你想要撤销的提交的完整或部分哈希值。
  • 执行此命令后,Git 会打开一个编辑器,让你编辑新的撤销提交的提交信息。默认信息会说明这是对哪个提交的撤销。
  • 保存并关闭编辑器后,一个新的提交就会被创建。

示例:

“`bash

查看提交历史,找到要撤销的提交哈希

git log –oneline

假设要撤销的提交哈希是 abcdefg

git revert abcdefg
“`

2. 撤销多个提交(按范围)

bash
git revert <commit-hash-from>..<commit-hash-to>

这个命令会撤销从 <commit-hash-from><commit-hash-to> 之间的所有提交(不包括 <commit-hash-from> 本身,但包括 <commit-hash-to>)。这些提交会按照它们在历史中出现的顺序逐一被撤销,每个撤销操作都会生成一个独立的提交。

注意: 如果你想要撤销包括 <commit-hash-from> 在内的范围,可以使用 ^ 符号:

bash
git revert <commit-hash-from>^..<commit-hash-to>

3. 撤销多个提交并合并为一个新提交

有时,你可能想撤销一系列提交,但只创建一个单个撤销提交,而不是为每个被撤销的提交都创建一个撤销提交。可以使用 -n--no-commit 选项。

“`bash
git revert -n ..

git revert –no-commit ..

然后手动提交

git commit -m “Revert a range of commits: through
“`

  • --no-commit 选项会执行反向应用操作,但不会自动创建提交。所有反向更改都会被放入暂存区。
  • 你可以检查这些更改,必要时进行调整,然后手动提交它们。这会将所有撤销操作合并到一个提交中。

4. 撤销合并提交 (Merge Commit)

撤销合并提交比较特殊,因为它有两个父提交。你需要告诉 Git 你想撤销哪一个父提交引入的更改。通常,第一个父提交是主线分支。

bash
git revert -m 1 <merge-commit-hash>

  • -m 1 (或 --mainline 1) 告诉 Git 保留第一个父提交(通常是合并目标分支,例如 mainmaster)的内容,并撤销第二个父提交(通常是特性分支)引入的更改。简单来说,它会撤销合并本身,使其看起来像该特性分支从未被合并过一样。
  • 如果你指定 -m 2,则会撤销主线分支的更改,这通常不是你想要的。

重要提示: 撤销合并提交通常不推荐,因为它可能会在未来再次合并同一个特性分支时导致复杂的问题。更好的做法是先撤销特性分支上的问题提交,然后再重新合并。如果确实需要撤销合并,并且该合并之后有进一步的开发,则可能需要更仔细的策略。

5. 解决冲突

在撤销过程中,尤其是当被撤销的提交与后续的提交有代码重叠时,可能会发生冲突。

当 Git 遇到冲突时,它会暂停 revert 过程,并在你的文件中标记冲突。你需要:

  1. 手动解决冲突: 编辑文件,移除冲突标记 <<<<<<<=======>>>>>>>,并决定保留哪些代码。
  2. 将解决后的文件添加到暂存区: git add <conflicted-file>
  3. 完成撤销: git revert --continue
    • 如果你决定放弃撤销操作,可以使用 git revert --abort

git revertgit reset 的区别

理解 git revertgit reset 的核心区别至关重要:

特性 git revert git reset
工作原理 创建一个新的提交来撤销旧提交的更改。 移动分支指针,可以选择性地修改工作区和暂存区。
历史记录 不修改历史,保留所有提交。 改写历史,删除或移动旧提交。
安全性 安全,适用于已推送的共享提交。 不安全,不应在已推送的共享提交上使用。
可追溯性 撤销操作本身也是一个提交,完全可追溯。 撤销的提交可能从历史中消失(取决于模式)。
使用场景 撤销已发布、已共享的提交;需要保留历史记录。 撤销本地未推送的提交;清除暂存区或工作区更改。
常用模式 git revert <commit> git reset --soft <commit>
git reset --mixed <commit> (默认)
git reset --hard <commit>

何时使用哪个?

  • git revert 总是用于撤销已推送到远程仓库的提交。它保持历史的线性,不影响其他协作者。
  • git reset 仅用于撤销本地未推送的提交。它本质上是“回滚”到某个历史点,并丢弃该点之后的所有提交。

总结

git revert 是一个强大且安全的 Git 命令,用于通过引入新的、相反的更改来撤销先前的提交。它在不改写历史的情况下保持了项目的完整性和可追溯性,使其成为处理已共享提交错误的理想选择。通过熟练掌握 git revert 的使用,你可以更自信、更安全地管理你的 Git 仓库,无论是在个人项目还是团队协作中。


滚动至顶部