为什么弃用Git rebase

https://zhuanlan.zhihu.com/p/29682134?utm_medium=social&utm_source=ZHShareTargetIDMore

作者阐释了 git rebase 命令的原理和缺陷,rebase 会导致线性的历史没有分支。此外如果 rebase 过程中发生了冲突,还可能会引入更多的问题。作者推荐使用 git merge。

首先,讲述一下 merge 和 rebase 之间的差别。

我们首先来思考一下将feature分支合并到master分支的基础案例。通过merge的话,我们创建了一个新的提交g表示两个分支的合并。提交图清晰的展现了发生了什么,我们可以从更大的 Git-repos 中看到熟悉的“火车轨道”轮廓。

merge 的案例:

为什么弃用Git rebase_第1张图片

同样地,我们可以在merge之前选择rebase。提交会被移除,并且feature分支被重置到master分支,feature分支上的提交被重新应用到master。差别在于这些重新应用的提交通常是原始的副本,它们的 SHA-1 值和原来的提交不一样。

rebase 的案例:

为什么弃用Git rebase_第2张图片

我们现在将 feature 的基础提交从 b 变为了 c,这就是 rebase 的意思。将 feature 合并到 master 是一个快进合并,因为在 feature 上的所有提交都是 master 的直接子代。

快进合并的案例:

为什么弃用Git rebase_第3张图片

和 merge 的方法比较起来,rebase 导致分支的历史都是线性的。我以前更喜欢在合并之前 rebase 分支的原因在于提高了可读性,我认为其他的开发者应该也是这种情况。

但是,这种方式带来了一些不是很明显的挑战。

考虑一下这种情况,有一个依赖在 master 上被移除了,但在feature上还在使用。当feature分支rebase到master上时,第一个重新应用的提交会打破你的构建,但只要没有合并冲突,rebase就不会被中断。从第一个提交出现的错误会保留在随后的所有提交中,这导致了一个链式的错误提交。

这个错误只会在 rebase 完成后才会被发现,并且通常会在顶部增加一个修复 bug 的提交 g。

rebase 失败的案例:

为什么弃用Git rebase_第4张图片

如果你在 rebase 过程中出现了冲突,Git 将会暂停在冲突的提交上,允许你在开始之前解决冲突。在一系列的提交中间解决冲突通常会让人困惑,难以改正,并且可能会导致额外的错误。

引入错误是在 rebase 过程中发生的。这样,当你重写历史的时候,新的错误就会被引入,它们可能会掩盖第一次写入历史时造成的真正的错误,尤其是使得我们使用 Git bisect 时会变得更加困难。Git bisect 可以说是 Git 工具箱中最强大的调试工具了。例如,思考一下下面的 feature 分支,我们假设在分支的末端引入了一个错误。

为了找到引入错误的提交,你可能会搜索几十个甚至上百个提交。这个过程可以通过编写测试错误存在的脚本来自动执行,并通过 Git bisect 使用命令

git bisect run 

来运行。

Bisect 会通过二分查找整个历史,识别出引入bug的提交。在上面展示的案例中,它成功地找到第一个错误的提交,因为所有的有问题的提交包含着我们正在寻找的真正的错误。

为什么弃用Git rebase_第5张图片

另一方面,如果我们在 rebase 过程中引入了额外的错误提交(下图的 d 和 e),bisect 将会遇到麻烦。这个例子中,我们希望Git识别出f提交,但它会错误地识别出 d,因为它包含了其他的错误打破了测试。

为什么弃用Git rebase_第6张图片

这个问题比看起来更大。

我们为什么要使用 Git ?因为它是我们追踪我们代码中错误来源最重要的工具。Git 是我们的安全网。通过 rebase 虽然能够达成线型历史,但我们会给予较少的优先权。

回顾一下,我必须使用 bisect 追踪系统中上百个提交。这个错误的提交在一条未编译的提交链中间,因为一个错误的 rebase。这个不必要的并且今天可以避免的错误导致我花了一天的时间来追踪提交。

所以,我们怎样才能避免在 rebase 过程中出现错误的提交链呢?一个方法是在 rebase 结束后,测试代码来发现错误,然后回到我们引进错误的地方修复它。另一个方法是,在 rebase 过程中暂停每一个步骤,在继续处理之前测试并修复它。

这是一个笨重的,并且容易犯错的过程。这么做的唯一结果是获得一个线型的历史。还有更简单,更好的方式吗?

答案是:Git merge。它是一个简单的,一步到位的过程,所有的冲突都可以在一个单一的提交中解决。合并的提交清晰地显示了我们的分支之间的交互点,并且我们的历史叙述了实际上 发生的和 什么时候 发生的。

综上所述,推荐使用 merge 而不是 rebase。保持我们历史的真实性是不可低估的。

你可能感兴趣的:(为什么弃用Git rebase)