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

acruukt9  于 2022-12-02  发布在  Git
关注(0)|答案(8)|浏览(223)

git mergegit rebase有什么区别?

umuewwlo

umuewwlo1#

假设最初有3个提交,ABC

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

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

合并

提交DE仍然在这里,但是我们创建了合并提交M,它继承了来自DE的修改。然而,这会创建一个 * 菱形 * 形状,很多人会觉得很混乱。

重建

我们创建了提交R,它的实际文件内容与上面的合并提交M完全相同。但是,我们删除了提交E,就像它从未存在过一样(由点-消失线表示)。由于这种消除,E对于开发人员艾德应该是本地的,并且不应该被推送到任何其他存储库。和历史保持良好的直线-大多数开发人员喜欢!

h9vpoimq

h9vpoimq2#

就我个人而言,我并不觉得标准的图表技术很有帮助--箭头似乎总是指向错误的方向。(它们通常指向每个提交的“父”,这最终会在时间上倒退,这很奇怪)。
用文字来解释:

  • 当你把分支rebase到他们的分支上时,你告诉Git让它看起来像是你干净地 checkout 了他们的分支,然后从那里开始做你所有的工作。这就形成了一个干净的,概念上简单的修改包,让其他人可以查看。当他们的分支上有新的修改时,你可以再次重复这个过程,并且您将总是在其分支的“尖端”得到一组干净的更改。
  • 当你把他们的分支合并到你的分支中时,你就把两个分支的历史记录联系在了一起,如果你以后再做更多的改变,你就开始创建一个交叉的历史记录线程:他们的一些变化,我的一些变化,他们的一些变化。有些人觉得这很乱或不受欢迎。

由于我不明白的原因,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件事”帖子的作者 *)

zpjtge22

zpjtge223#

  • 虽然被接受的和最高投票的答案是伟大的,我还发现它有用的尝试解释的差异,只是文字:*
    合并
  • “好了,我们得到了两个不同发展状态的储存库。让我们把它们合并在一起。两个父,一个结果子。”
    重定基准
  • 给予主分支(不管它得名称是什么)得更改提供给我得功能分支.这样做得方式是假装我得功能工作是在主分支得当前状态下开始得.
  • “重写我的更改历史以反映这一点。”(需要强制推送它们,因为通常版本控制都是关于而不是篡改给定历史)
  • “很可能--如果我收集的变化与我的工作没有什么关系--历史实际上不会改变太多,如果我逐个查看我的提交差异(你也可以想到”补丁“)。”
    **总结:**如果可能的话,重定基几乎总是更好的。使重新集成到主分支更容易。

因为你的特性工作可以呈现为一个大的补丁文件(也就是diff),而不需要“解释”多个父分支:至少有两个,来自一个合并,但可能更多,如果有几个合并。***与合并不同,多个重基不加起来。***(另一个大优点)

2w3kk1z5

2w3kk1z54#

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

  • 局部提交被临时地从分支中移除。
  • 跑git拉力
  • 再次插入所有本地提交。

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

uoifb46i

uoifb46i5#

为方便明白可以看到我的身影。
重定基会改变提交哈希,所以如果你想避免很多冲突,只要在分支完成/完成稳定时使用重定基。

8cdiaqws

8cdiaqws6#

mergerebase之间有什么区别?

阅读官方Git手册,它指出**“rebase在另一个基础分支上重新应用提交”,而“merge将两个或多个开发历史连接在一起”**。换句话说,merge和rebase的关键区别在于merge保留历史,而rebase重写历史。
让我们用一个并列的例子来说明这些陈述!

如上所述,merge操作通过创建新的单个合并提交将分支交织在一起(C7),导致菱形的非线性历史记录-本质上保留了发生的历史记录。通过将此结果与rebase操作的结果进行比较,我们可以看到没有创建合并提交,相反,两个提交C5C6被简单地倒带并直接在C4的顶部重新应用,保持历史线性。
如果我们进一步仔细检查这两个重新应用的提交,我们可以看到哈希值已经改变,这表明rebase确实重写了历史。

值得注意

每当你rebase一个分支,新的提交总是会产生,即使内容可能仍然是相同的!也就是说,任何以前的提交最终(后垃圾收集)将从历史中删除,如果没有其他指针(分支/标记)引用它们。
权力越大责任越大
我们已经看到了rebase是如何改写历史的,而merge是如何保存历史的。但是,从更广泛的意义上讲,这意味着什么呢?这两种操作会带来哪些可能性和潜在的缺点呢?

恩怨的变更

比如说,你在整合变更时遇到了一些严重的冲突。在合并的情况下,你只需要解决一次冲突,直接在C7提交中解决。另一方面,在rebase的情况下,你可能会被迫在每次提交(C5C6)中解决类似的冲突。

已发布的分支

另一个与rebase相关的潜在问题是当你的分支已经被远程发布,并且其他人已经基于它进行了工作。那么,你的分支可能会给所有相关方造成严重的混乱和头痛,因为Git会告诉你你的分支同时领先和落后。如果发生这种情况,使用rebase标志(git pull --rebase)拉取远程更改通常可以解决这个问题。
此外,无论何时,当您对一个已经发布的分支进行重定基时,不管是否有其他人基于它进行工作,您仍然需要强制推送它,以便将您的更新发送到远程服务器--完全覆盖现有的远程引用。

数据丢失(对您有利)

最后,由于rebase重写了历史,而merge保留了它,所以在rebase时可能会丢失数据。当新的提交被重新应用时,旧的提交会被删除(最终,在垃圾收集后)。事实上,这同样是rebase如此强大的特性--它允许你在公开之前整理你的开发历史!
结论
虽然merge从潜在数据丢失的Angular 来看是安全的,而且使用起来更直接。下面是一些可以帮助您避免与rebase相关的最常见问题的提示。

  • 不要对已远程发布的分支重定基底...
  • ......除非你知道你是唯一一个在做这件事的人(并且感到安全,用力推)
  • 在重定基之前,从你将要重定基的分支的尖端创建一个备份分支,因为它将允许你轻松地比较结果(一旦完成),并在必要时跳回到重定基之前的状态。
    ***来源:***以上摘录摘自此主题的完整文章:Differences Between Git Merge and Rebase — and Why You Should Care
7uzetpgm

7uzetpgm7#

我发现了一篇关于gitrebase与merge的非常有趣的文章,我想把它分享给大家

  • 如果你想看到完全相同的历史,你应该使用合并。合并保留历史,而rebase重写它。
  • 合并会将新的提交添加到历史记录中
  • 重定基可以更好地简化复杂的历史,您可以通过交互式重定基来更改提交历史。
svmlkihl

svmlkihl8#

假设你已经在特性分支中做了3次提交,当你想把特性分支的更改发送到主分支时,你有两个选择

  1. git merge:在这种情况下,主分支将只接收1个提交(合并3个提交)
  2. git rebase:在这种情况下,主分支将接收3次提交

相关问题