Git 回滚合并提交:附带示例的指南

我们可以通过合并有问题的代码来妥协一个应用程序,无论是由于不小心将未完成的工作集成到主分支,还是忽略了自动测试中遗漏的严重错误。

在本文中,我将指导您使用git revert来安全地撤销合并,确保提交历史保持完整并保护项目的完整性。

git revert的工作原理

我们可以将git revert视为Git的撤销命令版本。然而,git revert命令并不会删除提交或跳转到分支的以前状态。相反,它会创建一个新的提交,用于撤销特定提交的更改。

撤销带有哈希值<commit_hash>的提交的语法是:

git revert <commit_hash>

我们可以使用git log命令列出提交及其哈希标识符。”git log“的输出会按从最近到最旧的提交顺序列出提交,如下所示:

例如,要撤销实现减法函数的提交,我们将使用以下命令:

git revert 7ba24a3e62d4d37182428ccfaa070baa222b1151

使用git revert,我们可以撤销特定提交的更改,而不会影响提交历史。

请注意,git revert 并没有魔法般的效果,它可能取决于提交历史,并且可能导致必须手动解决的冲突。

与手动更改相比 git revert 的优势

如果我们可能需要手动解决冲突,为什么 git revert 还有用呢?手动撤销更改不是更简单吗?让我们看看它的优势:

  • 保留历史:git revert 创建一个新的提交,撤销指定提交的更改,同时保留整个提交历史。这有助于保持更改和回滚的透明历史。
  • 原子性回滚:它确保回滚是原子性和一致的。当我们手动删除并提交更改时,存在人为错误的风险。
  • 冲突感知:它确保如果有任何依赖原始提交的集成或更改,我们会通过冲突得到提醒。这看起来可能不方便,但它可以防止意外的副作用。
  • 元数据:由 git revert 创建的新提交包括元数据和描述被回滚内容的提交消息,有助于未来的理解。没有 git revert,这个上下文可能会丢失。

在不同场景下回滚合并

在这一部分,我们学习如何撤销合并。为了示例,我们假设我们正在将名为 feature 的分支合并到 main 分支,并从 main 分支执行命令:

git merge feature

我们在这里学到的东西可以应用到任何两个分支上,只需相应地替换分支名称。

撤销一个没有关联提交的合并

`git merge` 命令并不总是创建一个新的提交。只有在 `main` 分支与 `feature` 分支分叉时才会创建提交。因为 `git revert` 需要一个提交来进行操作,所以我们不能在这种情况下使用它。

`main` 和 `feature` 分支在 `main` 上创建了新的提交而这些提交不是 `feature` 分支的祖先时,它们就会分叉。换句话说,在 `feature` 创建之后,`main` 上创建了新的提交。

如果分支没有分叉,当我们在 `main` 分支上运行 `git merge feature` 命令时,Git 将使用快速前进合并。这意味着它将 `main` 分支的 `HEAD` 移动到 `feature` 分支的 `HEAD`。

我们可以通过查看 `git merge` 的结果来观察这一点:

要撤销这样的合并,我们只需要将 `main` 分支的 `HEAD` 移回到原来的位置。为此,我们:

  1. 使用 `git reflog` 识别之前的 `HEAD`。
  2. 使用git reset --hard <previous_head>HEAD重置为上一个,将<previous_head>替换为之前的HEAD

git reflog的输出将看起来像这样:

我们可以通过查看显示“checkout: moving from feature to main”的那一行来识别之前的HEAD(它写featuremain,因为那些是我们分支的名称)。

在这种情况下,之前的头部是fe59838。要将main分支的HEAD移回并撤销合并,我们然后使用以下命令:

git reset --hard fe59838

撤销具有相关提交的合并

如果main分支和feature分支已经分离,那么当我们合并两个分支时,将创建一个新的提交,称为合并提交。

合并提交将一个分支上的更改应用到另一个分支上。在这种情况下,将feature中的更改应用到main分支。

要撤销main分支上的更改,我们在合并提交上使用git revert。这将创建一个新的提交,撤销通过合并引入到main分支的更改,有效地将主分支的状态恢复到合并之前的状态。

首先,我们需要确定合并提交的哈希值。我们可以使用git log命令:

因为合并提交有两个父节点,所以git revert的语法略有不同。我们需要使用-m 1选项来指定我们希望相对于main分支回滚更改:

git revert -m 1 b8dab2c8611e324ed0d273133987415350e6d10d

回滚提交时的冲突解决

有时在回滚提交时可能会出现冲突,特别是如果被回滚的提交与代码库中后来的更改有冲突。在这种情况下:

  1. Git将会暂停回滚:我们需要手动解决冲突。Git会标记冲突的文件并要求干预。
  2. 解决冲突:我们打开每个冲突文件,解决Git标记的冲突,并保存更改。
  3. 暂存已解决文件:git add <file-path>
  4. 继续回滚: git revert --continue

结论

使用git revert来回滚合并提交可以确保每个更改和修正都记录在提交历史中。

此外,了解在何种情况下应该使用git resetgit revert可以让我们做出更好的决策,特别是在考虑协作工作流或仅限于本地更改的情况下。

你可以在下面的常见问题解答部分了解更多关于这个主题的信息。如果你想要了解更多关于Git的知识,我推荐以下资源:

Source:
https://www.datacamp.com/tutorial/git-revert-merge