“git merge”和“git rebase”有什么区别?

git mergegit rebase什么区别?

假设原来有3个提交, ABC

A-B-C

然后开发者Dan创build了提交D ,而开发者Ed创build了提交E

A-B-C-d-E

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

MERGE

A-B-C-d-E-M

这两个提交DE仍然在这里,但我们创build合并提交M ,inheritanceDE变化。 但是,这样会产生钻石形状,许多人都觉得很混乱。

REBASE

A-B-C-d-E-R

我们创build提交R ,实际的文件内容与上面的合并提交M相同。 但是,我们摆脱了提交E ,就像它从来没有存在(由点 – 消失线表示)。 由于这个问题, E应该是开发人员Ed的本地人员,并且从来没有被推到任何其他的仓库。 重build的好处是避免了钻石的形状,历史保持不错的直线 – 大多数开发人员都喜欢它!

我真的很喜欢这个我讨厌git的10件事的摘录(在第二个例子中,它给出了rebase的简单解释):

3.蹩脚的文件

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

 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 

这是一个很好的描述。


未经审查的原件

就我个人而言,我不觉得标准的图表技术非常有用 – 箭头似乎总是给我指出错误的方式。 (他们通常指向每个提交的“父母”,最后是时间倒退,这很奇怪)。

用文字来解释:

  • 当你把你的分支重新分支到分支上时,你告诉Git使它看起来好像你干净地检查了他们的分支,然后从那里开始所有的工作。 这使得一个干净的,概念上简单的变化包可以被人们审查。 当分支有新的改变时,你可以再次重复这个过程,并且总是最终得到一组干净的“分支尖端”变化。
  • 当你分支合并到你的分支时,你将这两个分支历史联系在一起。 如果稍后再做更多的更改,则会开始创build一个交错的历史logging:其中一些更改,一些更改以及一些更改。 有些人觉得这很混乱或不可取

由于我不明白的原因,Git的GUI工具从来没有做过太多的工作来更清晰地呈现合并历史,抽象出单个合并。 所以如果你想要一个“清洁历史”,你需要使用rebase。

我似乎回想起只读过使用rebase的程序员的博客文章和其他从未使用rebase的博客post。

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

 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。

如果您将代码重新编码到主服务器上而不是合并它,则会显示如下所示:

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

所有提交都在顶部(最新),其次是master分支的其余部分。

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

虽然接受和最有回报的答案是伟大的,我另外发现它是有用的试图解释仅仅用字的差异:

合并

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

变基

  • “把主分支的变化(不pipe它的名字)给我的特性分支。 假装我的特色工作是在晚些时候开始的,实际上就是主要分支的现状。
  • “重写我的变化历史以反映这一点” (需要强制推送它们,因为通常版本控制都不是篡改给定的历史logging)
  • “”如果我所看到的变化与我的工作无关,历史实际上不会发生太大的变化,如果我通过差异来看待我的承诺(你也可能会想到“补丁”)。

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

因为? ➝您的特色工作可以作为一个大的“补丁文件”(aka diff)表示,而不必“解释”多个父母:至less有两个来自一个合并,但可能还有更多,如果有几次合并。 与合并不同,多个rebase不加起来。 (另一大优势)

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

  • 本地提交从分支临时移除。
  • 运行git pull
  • 再次插入你所有的本地提交。

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