我们可以通过合并有问题的代码来妥协一个应用程序,无论是由于不小心将未完成的工作集成到主分支,还是忽略了自动测试中遗漏的严重错误。
在本文中,我将指导您使用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
` 移回到原来的位置。为此,我们:
- 使用 `
git reflog
` 识别之前的 `HEAD
`。 - 使用
git reset --hard <previous_head>
将HEAD
重置为上一个,将<previous_head>
替换为之前的HEAD
。
git reflog
的输出将看起来像这样:
我们可以通过查看显示“checkout: moving from feature to main”的那一行来识别之前的HEAD
(它写feature
和main
,因为那些是我们分支的名称)。
在这种情况下,之前的头部是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
回滚提交时的冲突解决
有时在回滚提交时可能会出现冲突,特别是如果被回滚的提交与代码库中后来的更改有冲突。在这种情况下:
- Git将会暂停回滚:我们需要手动解决冲突。Git会标记冲突的文件并要求干预。
- 解决冲突:我们打开每个冲突文件,解决Git标记的冲突,并保存更改。
- 暂存已解决文件:
git add <file-path>
- 继续回滚:
git revert --continue
结论
使用git revert
来回滚合并提交可以确保每个更改和修正都记录在提交历史中。
此外,了解在何种情况下应该使用git reset
与git revert
可以让我们做出更好的决策,特别是在考虑协作工作流或仅限于本地更改的情况下。
你可以在下面的常见问题解答部分了解更多关于这个主题的信息。如果你想要了解更多关于Git的知识,我推荐以下资源: