Git rebase:一个温和的介绍

Git rebase 很容易成为 Git 中最容易被误解的命令之一。 初学者经常会以错误的方式使用此命令弄乱他们的工作树,或者找不到 git rebase 和 merge 之间的区别。 因此,在本文中,我们尝试使用图形表示来详细解释 git-rebase 中实际发生和未发生的情况。 这篇文章是关于 rebase 的讨论,而不是关于如何 rebase 的简单教程。

Git 存储命令

什么是变基?

从字面上看,rebase 意味着更改对象的基础。 Git rebase 对 git branch 做同样的事情——它改变了分支的基础。

但是分支的基础到底是什么,我们为什么要这样做? 我们将在本文接下来的几节中回答这些问题。

分支的基础是什么?

分支的基础是从它的父分支分支出来的提交。 它也可以定义为与分支及其父分支相同的最新提交。 这是一个简单的可视化来理解它。

图 1:git commit-graph 的可视化表示,将功能分支的基础显示为蓝色。

功能 1 是功能分支偏离主分支的提交。 所以它是功能分支的基础提交。

在 git rebase 中,我们有兴趣将此基础更改为另一个提交,这意味着功能 2 提交将不再指向功能 1,而是其他一些提交。

git rebase 有什么作用?

在我们深入了解命令的细节之前,先快速浏览一下 git 命令的语法:

git rebase <target branch> 

此命令将当前分支重新绑定到目标分支上。 这意味着当前分支现在基于目标分支上的最后一次提交。 因此,git commit-graph 看起来就像分支从未与原始分支分离,并且提交基于当前基础。 这使提交图具有线性外观的提交图。

命令语法不是最重要的部分,重要的部分是命令的功能。 如果你搞砸了 git rebase,你会得到一些不需要的提交和复杂的提交图,而不是你想要的线性干净的提交图。 因此,让我们更详细地了解 git rebase。

正如我们在文章开头所讨论的那样,Git rebase 更改了分支的基础。 但这条线只是部分正确。

这些是我们可能期望 git rebase 做的事情

  • 将分支的基础更改为目标分支上的最新提交。
  • 保持我当前分支中的提交不变。

如果 git rebase 遵循此原则,则命令后图 1 中的 git commit 图 git rebase master 应该看起来像:

图 2:一个虚构的提交图,其中提交实际上会重新定位到目标分支。 与图 1 中给出的提交图相比,分支似乎从未从 master 分叉出来。

但是我们在这里遗漏了一个小问题:

  • 遵循上述方法基本上会破坏对该分支进行的提交的提交历史记录。 任何删除或重写 git 历史记录的命令都可能是导致问题的潜在原因。
  • 如果功能分支上的提交日期早于目标分支上的较新提交,则重新定位的分支将具有比它所基于的提交更旧(相对于时间)的较新提交,从而产生绝对的悖论。

为了避免这些问题, git rebase 实际做的是:

  • 将分支头指针重定位到目标分支指针。 (功能现在指向主人)
  • 在分支上进行新的重复提交。 这些提交本质上与原始提交具有相同的代码更改,但具有不同的 SHA1 值。
  • 较旧的提交仍以分离状态出现在图上。

因此,让我们最终想象一下实际 git-rebase 中会发生什么,

Git Reabse 实际图 3:我们在 master 上重新设置功能分支后的提交图。 请注意两次提交如何具有相同的消息(重复)但它们具有不同的 SHA1,这意味着它们是不同的提交。 原始提交作为分离节点出现在提交图中。

我什么时候使用 git rebase?

与 git merge 创建的凌乱图不同,Git rebase 仅用于具有干净的线性提交图。 所以这是这两者之间的权衡

  • Git merge 允许保留提交历史,但额外提交和复杂提交图的成本
  • Git rebase 保持提交次数不变,但代价是抽象掉提交历史。

因此,您可以合并的每个分支都可能重新定位,反之亦然,但建议不要重新定位公共/共享分支。 在使用 rebase 时,用户必须牢记保留历史记录和干净提交图之间的权衡。

结论

这使我们到了关于 git-rebase 的文章的结尾。 可视化 git 用于 git 命令的图形表示。 请继续关注有关 git 和其他开源程序的更多此类文章。