's the difference between ' git merge ' and ' git rebase'?
提问于
浏览
次
430
git merge 和 git rebase 有什么区别?
6 回答
762
假设最初有3个提交, A , B , C :
然后开发人员Dan创建了commit D ,开发人员Ed创建了commit E :
显然,这种冲突应该以某种方式解决 . 为此,有两种方法:
MERGE :
两个提交 D 和 E 仍然在这里,但我们创建合并提交 M ,它继承了 D 和 E 的更改 . 然而,这会产生钻石形状,许多人发现这种形状非常混乱 .
REBASE :
我们创建commit R ,其实际文件内容与上面的merge commit M 相同 . 但是,我们摆脱了提交 E ,就像它从未存在过一样(用点表示 - 消失线) . 由于这种消除, E 应该是开发人员Ed本地的,并且应该从未被推送到任何其他存储库 . 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 分支的其余部分 .
(免责声明:我是另一个答案中提到的"10 things I hate about Git"帖子的作者)
6 回答
假设最初有3个提交,
A
,B
,C
:然后开发人员Dan创建了commit
D
,开发人员Ed创建了commitE
:显然,这种冲突应该以某种方式解决 . 为此,有两种方法:
MERGE :
两个提交
D
和E
仍然在这里,但我们创建合并提交M
,它继承了D
和E
的更改 . 然而,这会产生钻石形状,许多人发现这种形状非常混乱 .REBASE :
我们创建commit
R
,其实际文件内容与上面的merge commitM
相同 . 但是,我们摆脱了提交E
,就像它从未存在过一样(用点表示 - 消失线) . 由于这种消除,E
应该是开发人员Ed本地的,并且应该从未被推送到任何其他存储库 . rebase的优势在于避免了钻石形状,历史保持了良好的直线 - 大多数开发人员都喜欢这样!我非常喜欢这个摘录自10 Things I hate about git(它在第二个例子中给出了一个关于rebase的简短解释):
然后我们有
这是一个很好的描述 .
1.未经审查的原件
就个人而言,我没有发现标准图表技术非常有用 - 箭头似乎总是指向我错误的方式 . (它们通常指向每个提交的“父”,最终会在时间上倒退,这很奇怪) .
用文字解释:
当你将你的分支放到他们的分支上时,你告诉Git看起来好像你干净地检查了他们的分支,然后从那里开始你的所有工作 . 这使得人们可以查看一个简洁,概念上简单的变更包 . 当分支上有新的更改时,您可以再次重复此过程,并且最终会得到一组干净的更改"on the tip" .
当你将它们的分支分支到你的分支时,你将这两个分支历史绑定在一起 . 如果稍后再进行更多更改,则会开始创建一个交错的历史线程:一些更改,一些更改,一些更改 . 有些人发现这个混乱或不受欢迎 .
由于我不明白的原因,Git的GUI工具从未花费太多努力来更清晰地呈现合并历史,抽象出各个合并 . 因此,如果您想要“干净的历史记录”,则需要使用rebase .
我似乎记得曾经读过程序员的博客帖子,他们使用rebase和其他 never 使用rebase .
示例
我会用一个简单的例子来解释这个问题 . 假设您项目中的其他人正在使用用户界面,并且您正在编写文档 . 没有rebase,你的历史可能看起来像:
也就是说,在文档中间提交合并和UI提交 .
如果您将代码重新设置为master而不是合并它,它将如下所示:
所有提交都在顶部(最新),然后是
master
分支的其余部分 .(免责声明:我是另一个答案中提到的"10 things I hate about Git"帖子的作者)
虽然接受和最受欢迎的答案很棒,但我还发现尝试用单词解释差异很有用:
merge
rebase
“将主分支(无论其名称)的更改提供给我的功能分支 . 通过假装我以后开始的功能工作来实现,实际上是在主分支的当前状态 . “
“改写我的历史更改以反映这一点 . “(需要强制推送它们,因为通常版本控制都是关于 not 篡改给定的历史记录)
“可能 - 如果我所做的改变与我的工作没什么关系 - 历史实际上不会有太大变化,如果我通过差异查看我的提交差异(你也可能会想到'补丁') . ”
summary: 如果可能,rebase几乎总是更好 . 使重新集成到主分支更容易 .
因为? ➝你的功能工作可以作为主要分支的一个大'补丁文件'(又名差异)呈现,而不必“解释”多个父母:至少两个,来自一个合并,但可能更多,如果有几次合并 . Unlike merges, multiple rebases do not add up. (另一个大加号)
Git rebase更接近合并 . rebase的区别在于:
本地提交暂时从分支中删除 .
运行git pull
再次插入所有本地提交 .
这意味着在所有远程提交之后,所有本地提交都会移动到最后 . 如果您有合并冲突,您也必须解决它 .
为了便于理解可以看到我的身材 .
Rebase将更改提交哈希,因此如果您想避免大部分冲突,只需在该分支完成/完成时使用rebase稳定 .