git merge和git rebase有什么区别?
假设最初有3个提交,A,B,C:
然后开发人员Dan创建了提交D,开发人员Ed创建了提交E:
显然,这种冲突应该以某种方式解决。对此,有两种方法:
走:
提交D和E仍然在这里,但是我们创建了合并提交M,它继承了D和E的更改。然而,这创建了菱形,许多人对此感到非常困惑。
变基:
我们创建提交R,其实际文件内容与上面合并提交M的内容相同。但是,我们摆脱了提交E,就像它从未存在过一样(用圆点-消失线表示)。由于这种删除,E对于开发人员Ed来说应该是本地的,并且不应该被推送到任何其他存储库。rebase的优点是避免了菱形,历史保持良好的直线-大多数开发人员都喜欢这样!
就我个人而言,我不认为标准的图表技术非常有用——箭头似乎总是指向错误的方向。(它们通常指向每次提交的“父”,这最终会在时间上倒退,这很奇怪)。
用语言解释一下:
When you rebase your branch onto their branch, you tell Git to make it look as though you checked out their branch cleanly, then did all your work starting from there. That makes a clean, conceptually simple package of changes that someone can review. You can repeat this process again when there are new changes on their branch, and you will always end up with a clean set of changes "on the tip" of their branch. When you merge their branch into your branch, you tie the two branch histories together at this point. If you do this again later with more changes, you begin to create an interleaved thread of histories: some of their changes, some of my changes, some of their changes. Some people find this messy or undesirable.
出于我不理解的原因,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
你所有的提交都在顶部(最新的),后面跟着主分支的其他部分。
(免责声明:我是另一个答案中提到的“我讨厌Git的10件事”帖子的作者)
虽然被广泛接受且获得最多好评的答案很棒,但我发现仅用语言来解释两者的差异是有用的:
走
“好吧,我们的存储库有两种不同的开发状态。我们把它们合并在一起。两个父母,一个孩子。”
变基
“Give the changes of the main branch (whatever its name) to my feature branch. Do so by pretending my feature work started later, in fact on the current state of the main branch.” “Rewrite the history of my changes to reflect that.” (need to force-push them, because normally versioning is all about not tampering with given history) “Likely —if the changes I raked in have little to do with my work— history actually won't change much, if I look at my commits diff by diff (you may also think of ‘patches’).“
总结:在可能的情况下,rebase几乎总是更好的。使重新集成到主分支更容易。
因为?➝你的特性工作可以呈现为一个大的“补丁文件”(又名diff)相对于主分支,不需要“解释”多个父:至少两个,来自一个合并,但可能更多,如果有几个合并。与合并不同,多个rebase不能叠加。(另一个大优点)
Git rebase更接近于merge。rebase的区别是:
本地提交被临时地从分支中移除。 运行git pull 再次插入所有本地提交。
这意味着所有本地提交都被移动到最后,在所有远程提交之后。如果您遇到合并冲突,也必须解决它。
我发现了一篇关于git rebase vs merge的非常有趣的文章,想在这里分享一下
如果你想看到完全相同的历史,你 应该使用归并。Merge保存历史,而rebase重写历史。 合并会向历史记录中添加一个新的提交 重基可以更好地简化复杂的历史记录,你可以通过交互的重基来改变提交历史。
merge和rebase的区别是什么?
阅读官方Git手册,它指出“rebase在另一个基本分支上重新应用提交”,而“merge将两个或多个开发历史连接在一起”。换句话说,merge和rebase之间的关键区别在于merge保留历史,而rebase重写历史。
让我们用一个并列的例子来说明这些陈述!
如上所述,合并操作通过创建一个新的合并提交(C7)将分支交织在一起,从而产生菱形非线性历史—本质上保留了发生的历史。通过将这个结果与rebase操作的结果进行比较,我们看到没有创建合并提交,相反,两个提交C5和C6只是被倒带并直接在C4上重新应用,保持历史记录的线性。
如果我们进一步仔细检查两次重新应用的提交,我们可以看到哈希值发生了变化,这表明rebase确实重写了历史。
值得注意的
每当你重新建立一个分支时,即使内容可能仍然相同,也总是会生成新的提交!也就是说,如果没有其他指针(分支/标记)引用它们,任何以前的提交最终(垃圾收集后)将从历史记录中删除。
能力越大,责任越大
我们已经看到了rebase如何重写历史,而merge如何保存历史。但从更广泛的意义上来说,这意味着什么呢?这两种操作有哪些可能性和潜在的缺陷?
冲突性的变更
比方说,您在尝试集成这些更改时遇到了一些严重的冲突。在合并场景中,您只需要在C7提交中直接解决一次冲突。另一方面,使用rebase,您可能被迫在每次提交(C5和C6)中解决类似的冲突,因为它们被重新应用。
发布分支
另一个与改基相关的潜在问题发生在您要改基的分支已经远程发布,而其他人的工作已经基于该分支进行了。然后,重新基于的分支可能会给所有相关方带来严重的困惑和头痛,因为Git会告诉您,您的分支同时处于领先和落后状态。如果发生这种情况,使用rebase标志拉出远程更改(git pull——rebase)通常可以解决问题。
此外,无论何时您要基于一个已经发布的分支进行重基,无论其他人是否基于它进行工作,您仍然需要强制推送它以将您的更新发送到远程服务器—完全覆盖现有的远程引用。
数据丢失(对您有利)
最后,由于rebase重写历史,而merge保留历史,因此在rebase时实际上可能会丢失数据。当重新应用新的提交时,旧的提交将被删除(最终,在垃圾收集之后)。同样的特性实际上是rebase如此强大的原因——它允许您在公开之前整理您的开发历史!
结论
而从潜在的数据丢失的角度来看,使用合并是安全的,并且感觉使用起来更直接。这里有一些提示,可以帮助您避免与改基相关的最常见问题。
不要对远程发布的分支进行重基… 除非你知道你是唯一一个在做这件事的人(而且你觉得推这件事很安全) 在重基之前,从将要重基的分支的顶端创建一个备份分支,因为它将允许您轻松地比较结果(一旦完成),并在必要时跳回到重基前的状态。
来源:以上节选自这篇关于“Git Merge和Rebase之间的区别-以及为什么你应该关心”主题的完整文章
假设你已经在你的特性分支中提交了3次,当你想要将你的特性分支更改发送到主分支时。 你有两个选择
git merge:在这种情况下,主分支将只接收1次提交(合并3次提交) git rebase:在这种情况下,main branch将接收3次提交
推荐文章
- Visual Studio代码如何解决合并冲突与git?
- 无法推送到远程分支,无法解析到分支
- Git:如何将数据库重置为特定的提交?
- 如何在合并期间使用Git和命令行保存本地文件或远程文件?
- 能够用一个命令推到所有git遥控器?
- 重新基于Git合并提交
- 忽略已经签入目录的内容?
- 如何从windows cmd保存git提交消息?
- (Mac) -bash: __git_ps1:命令未找到
- 如何删除多个已删除的文件在Git仓库
- 使用vimdiff查看所有' git diff '
- 如何拉特定的目录与git
- 本地存储库中的文件与源文件之间的差异
- 将Git存储库内容移动到另一个存储库,保存历史记录
- 如何在GitHub上创建自己的存储库?