合并 --squash 和 rebase 有啥区别?

Posted

技术标签:

【中文标题】合并 --squash 和 rebase 有啥区别?【英文标题】:What is the difference between merge --squash and rebase?合并 --squash 和 rebase 有什么区别? 【发布时间】:2011-01-26 12:02:02 【问题描述】:

我是 git 新手,我正在尝试了解 squash 和 rebase 之间的区别。据我了解,您在进行变基时会执行壁球。

【问题讨论】:

【参考方案1】:

Merge squash 将一棵树(一系列提交)合并为一个提交。也就是说,它压缩n 次提交中所做的所有更改到单个提交中。

变基就是变基,即为树选择一个新的基(父提交)。也许这方面的反复无常的术语更清楚:他们称之为移植,因为它就是:为一棵树选择一个新的基础(父提交,根)。

在进行交互式变基时,您可以选择压缩、选择、编辑或跳过要变基的提交。

希望这很清楚!

【讨论】:

什么时候应该变基,什么时候应该压缩? @MartinThoma 见:lwn.net/Articles/328436lwn.net/Articles/791284 使用哪个都没有关系,但我建议使用 rebase。 Rebase 更改了功能分支的父节点,但 merge 没有,我推荐它,因为它使提交结构更简单,但作为 git 用户,它没有什么不同。 ***.com/questions/2427238/….【参考方案2】:

git merge --squashgit rebase --interactive 都可以产生“压缩”提交。但它们的用途不同。

git merge --squash abranch

将在目标分支上生成一个压缩提交,而不标记任何合并关系。 (注意:它不会立即产生提交:您需要额外的git commit -m "squash branch"

如果您想完全放弃源分支,这很有用,从(从SO question 获取的模式):

git checkout stable

          X               stable
         /
a---b---c---d---e---f---g tmp

到:

git merge --squash tmp
git commit -m "squash tmp"


# In the following graph, G is c--d--e--f--g squashed together

          X-------------G stable
         /
a---b---c---d---e---f---g tmp

然后删除tmp 分支。


注意:git merge has a --commit option,但不能与--squash 一起使用。 从来没有可以同时使用--commit--squash。 自 Git 2.22.1(2019 年第三季度)以来,这种不兼容性已经明确:

请参阅commit 1d14d0c(2019 年 5 月 24 日)Vishal Verma (reloadbrain)。 (2019 年 7 月 25 日在 commit 33f2790 中由 Junio C Hamano -- gitster -- 合并)

merge:拒绝--commit--squash

以前,当--squash 被提供时,'option_commit' 是静默的 掉了。这对于试图覆盖的用户来说可能是令人惊讶的 明确使用--commit 的壁球的无提交行为。

git/git builtin/merge.c#cmd_merge() 现在包括:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

git rebase --interactive

在一个新的基础上重放您的部分或全部提交,允许您压缩(或最近“修复”,请参阅SO question),直接转到:

git checkout tmp
git rebase -i stable

   stable
      X----------------G tmp
     /
a---b

如果您选择压缩所有tmp 的提交(但是,与merge --squash 不同,您可以选择重放一些,并压缩其他的)。

所以区别是:

squash 不会触及您的源分支(此处为tmp)并在您想要的位置创建单个提交。 rebase 允许您继续使用同一源分支(仍然是 tmp): 新基地 更清晰的历史

【讨论】:

Gc--d--e--f--g 挤在一起了吗? @Wayne:是的,这些例子中的 G 代表 tmp 的提交被挤压在一起。 @Th4wn:由于 Git 使用所有项目的快照的原因,G 不会代表与 g 相同的内容,因为 X 引入了更改。 @VonC:不确定最后的评论。如果你有一个git merge --no-ff temp 而不是git merge --squash temp,那么你会得到一个更混乱的历史,但你也可以更容易地做git revert e 之类的事情。这是一段混乱但诚实务实的历史,主要分支仍然相当干净。 @naught101 我同意。正如***.com/a/7425751/6309 中所解释的那样,当使用太频繁时(如git pull --no-ff:***.com/questions/12798767/…),它也是关于不破坏git bisectgit blame。反正没有一种方法,这就是为什么本文描述了三种方法 (***.com/questions/9107861/…)【参考方案3】:

合并提交:保留分支中的所有提交并将它们与基分支上的提交交错

Merge Squash:保留更改但忽略历史中的单个提交

Rebase:这会将整个功能分支移动到 master 分支的顶端,有效地将所有新提交合并到 master 中

更多关于here


前两张图来自About pull request merges on the GitHub Docs

【讨论】:

我发现这比接受的答案更清楚。谢谢! 这是迄今为止几乎任何地方关于该主题的最佳答案。谢谢。 真的比公认的答案好。谢谢 你先生应该获得奖牌 第一张图在我看来完全错误。不知何故,提交 D 最终没有父节点。【参考方案4】:

让我们从下面的例子开始:

现在我们有 3 个选项可以将 feature 分支 的更改合并到 ma​​ster 分支

    合并提交 将保留 feature 分支 的所有提交历史并将它们移动到 ma​​ster 分支 将添加额外的虚拟提交。

    变基和合并feature 分支 的所有提交历史记录附加到 ma​​ster 分支的前面 不会添加额外的虚拟提交。

    压缩和合并 将所有功能分支提交分组到一个提交,然后将其附加到主分支的前面 将添加额外的虚拟提交。

您可以在下面找到 ma​​ster 分支 将如何处理它们中的每一个。

在所有情况下: 我们可以安全地删除功能分支

【讨论】:

你能解释一下第二张图片中的虚拟提交是什么吗?我是 git 的初学者。 @Yusuf,它只是一个包含两个分支更新的额外提交,它的默认提交消息 =“Megre 分支 XYZ 到 master” 对于“压缩和合并”:有一个包含所有分组提交加上一个“额外虚拟提交”的提交? @leticia 所有分组提交的提交 = “额外的虚拟提交”本身,如上图 那么我认为“压缩和合并”不会添加额外的虚拟提交,而只会在主分支前面“重新设置”/追加提交。您在上面描述的上下文中的虚拟提交与 1. 和 3. 中的虚拟提交不同,因为 1 中的虚拟提交是“将分支 XYZ 合并到生成此提交的 master 中”,而 3 中的虚拟提交是“压缩提交到这个提交不是由合并产生的额外提交'

以上是关于合并 --squash 和 rebase 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

在 Git 中,如何在不挑选新分支的情况下对历史中具有多个合并提交的分支进行 rebase + squash

git merge squash 和 rebase 区别

git merge时merge/squash merge/rebase merge的区别

git 交互式 rebase squash 进入下一个提交

Git rebase冲突

git merge 和 rebase难兄难弟,全程操作下来才能体会到git火爆不是没有理由的