'git merge'和'git rebase'有什么区别?

时间:2013-05-21 09:06:09

标签: git merge git-merge rebase git-rebase

git mergegit rebase之间有什么区别?

8 个答案:

答案 0 :(得分:795)

假设最初有3次提交,ABC

A-B-C

然后开发人员Dan创建了提交D,开发人员Ed创建了提交E

A-B-C-D-E

显然,这种冲突应该以某种方式解决。为此,有两种方式:

<强>合并

A-B-C-D-E-M

提交DE仍在此处,但我们创建合并提交M,继承DE的更改。但是,这会创建菱形形状,很多人会觉得很困惑。

<强> REBASE

A-B-C-D-E-R

我们创建了提交R,其实际文件内容与上面的合并提交M相同。但是,我们摆脱了提交E,就像它从未存在过一样(用点表示 - 消失线)。由于这种消失,E应该是开发人员Ed本地的,并且应该从未被推送到任何其他存储库。 rebase的优势在于避免了菱形形状,并且历史保持良好的直线 - 大多数开发人员都喜欢它!

答案 1 :(得分:139)

我真的很喜欢10 Things I hate about git中的这段摘录(它在第二个例子中给出了关于rebase的简短解释):

  

3。蹩脚的文档

     

手册页是一个万能的“f *** you” 1 。他们从计算机科学家的角度描述命令,而不是用户。一个很好的例子:

git-push – Update remote refs along with associated objects
     

以下是对人类的描述:

git-push – Upload changes from your local repository into a remote repository
     

更新,另一个例子:(谢谢cgd)

git-rebase – Forward-port local commits to the updated upstream head
     

翻译:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

然后我们

git-merge - Join two or more development histories together

这是一个很好的描述。


1。未经审查的原始

答案 2 :(得分:112)

就我个人而言,我没有发现标准图表技术非常有用 - 箭头似乎总是指向我错误的方式。 (它们通常指向每个提交的“父”,最终会及时倒退,这很奇怪)。

用文字解释:

  • 当您>你的分支重新分支到他们的分支上时,你告诉Git让它看起来好像你干净地检查了他们的分支,然后从那里开始你的所有工作。这使得人们可以查看一个简洁,概念上简单的变更包。当分支上有新的更改时,您可以再次重复此过程,并且您将始终在其分支的“提示”上进行一组干净的更改。
  • 当您合并他们的分支到您的分支时,您将此时将两个分支历史绑定在一起。如果稍后再进行更多更改,则会开始创建一个交错的历史线程:一些更改,一些更改,一些更改。有些人觉得这很乱或不受欢迎。

由于我不明白的原因,Git的GUI工具从未花费太多精力来更清晰地呈现合并历史,从而抽象出各个合并。因此,如果您想要“干净的历史记录”,则需要使用rebase。

我似乎记得读过那些使用rebase的程序员和从不使用rebase的其他程序员的博客文章。

实施例

我会用一个简单的例子来解释这个问题。假设您项目中的其他人正在使用用户界面,并且您正在编写文档。没有rebase,你的历史可能看起来像:

Write tutorial
Merge remote-tracking branch 'origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

也就是说,文档中间的合并和UI提交会提交。

如果您将代码重新设置为master而不是合并它,它将如下所示:

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

所有提交都位于顶部(最新),然后是master分支的其余部分。

免责声明:我是“我讨厌Git的10件事”的作者,在另一个答案中提及了

答案 3 :(得分:37)

虽然接受且最受欢迎的答案很棒,但我还发现尝试用单词解释差异很有用:

<强>合并

  • “好吧,我们的存储库有两个不同的开发状态。让我们将它们合并在一起。两个父母,一个孩子。“

<强>底垫

  • “将主分支(无论其名称)的更改提供给我的功能分支。通过假装我以后开始的功能工作来实现,实际上是在主分支的当前状态。“
  • “重写我的更改历史以反映这一点。”(需要强制推送它们,因为通常版本控制都是关于篡改给定历史记录) < / LI>
  • “可能 - 如果我所做的改变与我的工作没什么关系 - 历史实际上不会有太大变化,如果我通过差异查看我的提交差异(你也可能会想到'补丁')。” / LI>

摘要:如果可能,rebase几乎总是更好。使重新集成到主分支更容易。

由于? ➝您的功能工作可以显示为主要分支的一个大'补丁文件'(又名差异),而不必“解释”多个父母:至少两个,来自一个合并,但如果有几次合并,可能会更多。 与合并不同,多个rebase不会相加。 (另一大优点)

答案 4 :(得分:13)

Git rebase更接近合并。 rebase的区别在于:

  • 本地提交暂时从分支中删除。
  • 运行git pull
  • 再次插入所有本地提交。

这意味着在所有远程提交之后,所有本地提交都会移动到最后。如果你有合并冲突,你也必须解决它。

答案 5 :(得分:5)

为了便于理解,可以看看我的身材。

Rebase将更改提交哈希,因此如果您想避免大量冲突,只需在完成/完成该分支时使用rebase。

enter image description here

答案 6 :(得分:1)

合并与变基的并排说明

请注意上述变基场景中 C5C6 的更新哈希值。

有关该主题的完整详细信息和动画,我已经单独写了一篇文章:https://betterprogramming.pub/differences-between-git-merge-and-rebase-and-why-you-should-care-ae41d96237b6

答案 7 :(得分:0)

我在git rebase vs merge 上发现了一篇非常有趣的文章,认为要分享它here

  • 如果您想查看与发生的历史完全相同的历史,则可以 应该使用合并。合并保留历史记录,而重新设置则保留历史记录。
  • 合并会向您的历史记录添加新的提交
  • 重定基最好简化复杂的历史记录,您可以通过交互式变基来更改提交历史记录。