Git merge 和 Git rebase 的比较
git rebase 命令对于初学者来说号称是 Git 中的巫术,但是如果小心使用,其实它上可以让开发团队的生活变得更轻松。 在本文中,我们将 git rebase 与相关的 git merge 命令进行比较,并确定将 rebase 合并到典型 Git 工作流程中的所有的可能的机会。
概念概述
首先要了解的是, git rebase 解决了与 git merge 相同的问题。 这两个命令都旨在将更改从一个分支集成到另一个分支 - 只是二者进行的方式非常不同。
考虑一下当我们开始在专用分支中处理新功能时会发生什么,然后另一个团队成员使用新提交更新主分支。 这会导致历史分叉,任何使用 Git 作为协作工具的人都应该熟悉这一点。
现在,假设 main 中的新提交与我们正在处理的功能相关。 要将新提交合并到我们的 feature 分支中,有两个选择:merge 或 rebase。
使用 Merge
最简单的选择是使用以下命令将 main 分支合并到 feature 分支中:
$ git checkout feature
$ git merge main
或者,可以将其压缩为一行:
$ git merge feature main
这会在 feature 分支中创建一个新的“合并提交”,将两个分支的历史联系在一起
Merge 很好,因为它是一种非破坏性操作。 现有的分支不会以任何方式改变。 这避免了 rebase 的所有潜在问题(在下面讨论)。
另一方面,这也意味着每次需要合并上游更改时,feature 分支都会有一个无关的合并提交。 如果 main 非常活跃,这可能会严重影响 feature 分支的历史记录。 虽然可以使用高级命令 git log 来缓解这个问题,但它会让其他开发人员难以理解项目的历史。
使用 Rebase
作为 merge 的替代方法,我们可以使用以下命令将 feature 分支重新定位到 main 分支上:
$ git checkout feature
$ git rebase main
这将整个 feature 分支移动到 main 分支的顶端,有效地将所有新提交合并到主分支中。 但是,rebase 不是使用合并提交,而是通过为原始分支中的每个提交创建全新的提交来重写项目历史记录。
变基的主要好处是我们可以获得更清晰的项目历史记录。 首先,它消除了 git merge 所需的不必要的合并提交。 其次,正如在上图中所看到的,rebase 还会产生完美的线性项目历史——我们可以按照功能的提示一直到项目的开始,而无需任何分支。 这样可以更轻松地使用 git log、git bisect 和 gitk 等命令导航我们的项目。
但是,这个原始提交历史有两个权衡:安全性和可追溯性。 如果不遵循 Rebase 的黄金法则,重写项目历史可能会给协作工作流程带来灾难性的后果。 而且,不太重要的是,rebase 丢失了合并提交提供的上下文——我们无法看到上游更改何时合并到feature中。
交互式 Rebase
交互式变基使我们有机会在将提交移动到新分支时更改提交。 这比自动变基更强大,因为可以对分支提交历史的进行完全控制。 通常,这用于在将 feature 分支合并到 main 分支之前清理混乱的历史记录。
要开始交互式变基会话,可以在 git rebase 命令后面加上 -i
选项:
$ git checkout feature
$ git rebase -i main
这将打开一个文本编辑器,列出所有将要移动的提交:
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
上面准确定义了执行 rebase 后分支的内容。 通过更改 pick 命令和/或重新排序条目,我们可以使分支的历史记录看起来像想要的任何内容。 例如,如果第二次提交修复了第一次提交中的一个小问题,我们可以使用 fixup 命令将它们压缩为单个提交:
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
当保存并关闭文件时,Git 将根据我们的指示执行 rebase,从而生成如下所示的项目历史记录:
像这样减少无关紧要的提交会使我们的 feature 历史更容易理解。 这是 git merge 根本无法做到的。
使用 rebase 的黄金法则
一旦你理解了 rebase 是什么,最重要的是学习什么时候不要使用rebase。 git rebase 的黄金法则是永远不要在公共分支上使用。
例如,考虑一下如果将 main 重新变基到 feature 分支上会发生什么:
rebase 将 main 中的所有提交移动到 feature 的顶端。 问题是这仅发生在您的存储库中。 所有其他开发人员仍在使用原始main分支的程序。 由于 rebase 会产生全新的提交,Git 会认为你的主分支的历史与其他人的不同。
同步两个main分支的唯一方法是将它们重新合并在一起,从而产生一个额外的合并提交和两组包含相同更改的提交(原始的,以及来自您rebase的分支的)。 不用说,这是一个非常令人困惑的情况。
所以,在运行 git rebase 之前,总是问自己,“还有其他人在使用这个分支吗?” 如果答案是肯定的,请开始考虑以非破坏性方式进行更改(例如 git revert 命令)。
强制推送
如果你尝试将变基的main分支推送回远程存储库,Git 将阻止这样做,因为它与远程main分支冲突。 但是,我们可以通过传递 --force
标志来强制推送,如下所示:
# 谨慎使用该命令!
$ git push --force
这会覆盖远程主分支来匹配我们存储库中变基的主分支,这会使团队的其他成员感到非常困惑。 因此,只有当我们确切地知道自己在做什么时,才能非常小心地使用此命令。
我们应该强制推送的唯一的可能情况是在将私有feature分支推送到远程存储库(例如,出于备份目的)之后执行本地清理时。 同样,重要的是,没有人从 feature 分支的原始版本执行提交。
相关文章
如何在 Windows 系统中卸载 git
发布时间:2023/04/09 浏览次数:223 分类:Git
-
在这篇简短的文章中,我们将学习如何卸载 Git,以及如何在从个人计算机的目录中卸载 Git 后删除这些文件。
Git 如何重命名本地分支
发布时间:2023/04/09 浏览次数:64 分类:Git
-
大多数情况下,重命名分支机构是由于上述情况。 因此,在本教程中,我们将学习使用下面提到的技术更改本地 Git 分支的名称。
重命名 Git 存储库中的文件和目录
发布时间:2023/04/09 浏览次数:102 分类:Git
-
在本文中,我们将讨论 git 中的重命名过程。 我们使用 Git Rename 来更改工作目录中文件和文件夹的名称。
在 Git 中取消初始化存储库
发布时间:2023/04/09 浏览次数:187 分类:Git
-
本本文介绍如何通过 Git 命令行取消初始化 Git 存储库。git init 命令开发一个新的空置 Git 存储库。 它还用于重新初始化已经存在的 Git 存储库。
Git 仓库名称该如何命名
发布时间:2023/04/09 浏览次数:208 分类:Git
-
使用 Git 时,选择一个简洁且最新的存储库名称是一项艰巨的任务。本教程介绍了如何以独特的方式命名 Git 存储库。
配置 Git 以忽略文件模式更改
发布时间:2023/04/09 浏览次数:67 分类:Git
-
本文讨论配置 Git 以忽略文件更改 chmod 所需的步骤。 如果您更改 Git 正在跟踪的文件的权限,系统将在该文件中注册更改。
在 Git 中暂存已删除的文件
发布时间:2023/04/09 浏览次数:93 分类:Git
-
本文讨论了在 Git 中暂存已删除文件的必要步骤。我们知道 rm 命令可以删除一个文件,而无需将其从工作目录中移除。 那么,我们如何暂存已删除的文件以进行提交呢?
在 Git 中显示冲突文件
发布时间:2023/04/09 浏览次数:139 分类:Git
-
本文讨论在 Git 中列出冲突文件的最简单和最干净的方法。 我们可以使用 git status 命令,但这很麻烦,尤其是当我们有大量不冲突的文件时。