在git中,merge --squash和rebase之间有什么区别?

GiH*_*GiH 336 git merge rebase git-rebase squash

我是git的新手,我正在努力理解壁球和篮板之间的区别.根据我的理解,你做一个篮板时做一个壁球.

Von*_*onC 340

双方git merge --squashgit rebase --interactive能产生"挤压"承诺.
但它们有不同的用途.

将在目标分支上生成压缩提交,而不标记任何合并关系.
(注意:它不会立即产生提交:你需要一个额外的git commit -m "squash branch")
如果你想完全丢弃源分支,那么这很有用(从SO问题中获取的模式):

 git checkout stable

      X                   stable
     /                   
a---b---c---d---e---f---g tmp
Run Code Online (Sandbox Code Playgroud)

至:

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

      X-------------------G stable
     /                   
a---b---c---d---e---f---g tmp
Run Code Online (Sandbox Code Playgroud)

然后删除tmp分支.

在新的基础上重放你的部分或全部提交,允许你压缩(或者最近"修复",看到这个SO问题),直接进入:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));
Run Code Online (Sandbox Code Playgroud)

如果你选择压缩所有提交--commit(但是,相反--squash,你可以选择重播一些,并压缩其他人).

所以差异是:

  • --commit不会触及您的源分支(--squash此处)并在您想要的位置创建单个提交.
  • reloadbrain允许你继续使用相同的源分支(仍然gitster):
    • 一个新的基地
    • 更清洁的历史

  • `G`是`c - d - e - f - g`压扁在一起? (8认同)
  • @Wayne:是的,这些例子中的G代表了压缩在一起的`tmp`提交. (7认同)
  • @ Th4wn:由于Git的原因是所有项目的快照,因为`X`引入的变化,`G`不会代表与`g`相同的内容. (3认同)
  • @VonC:不确定最后的评论。如果你有一个“git merge --no-ff temp”而不是“git merge --squash temp”,那么你会得到一个更混乱的历史记录,但你也可以更容易地做“git revert e”之类的事情。这是一段混乱但诚实务实的历史,而且主要分支仍然相当干净。 (2认同)
  • @ naught101我同意。如http://stackoverflow.com/a/7425751/6309中所述,这也与在频繁使用时不破坏`git bisect`或`git blame`一样(例如在git pull --no-ff中: http://stackoverflow.com/questions/12798767/fast-forward-when-using-pull-and-no-ff-when-pull/12798995#12798995)。无论如何,没有一种方法,这就是为什么本文描述了三种方法(http://stackoverflow.com/questions/9107861/git-merge-testing-branch-final-commit-to-master-branch/13470530#13470530) (2认同)

Md *_*ker 151

合并提交:保留分支中的所有提交,并将它们与基本分支上的提交交错在此输入图像描述

Merge Squash:保留更改但省略历史记录中的各个提交 在此输入图像描述

Rebase:这将整个功能分支从主分支的尖端开始,有效地将所有新提交合并到master中

在此输入图像描述

更多关于这里

  • 我发现这比接受的答案更清楚。谢谢你! (35认同)
  • 这是迄今为止几乎任何地方关于该主题的最佳答案。谢谢。 (9认同)
  • 确实比接受的答案更好。谢谢 (3认同)
  • 先生,你值得一枚奖章 (3认同)
  • 第一张图对我来说看起来完全错误。不知何故,提交 D 最终没有父提交。 (3认同)
  • 完美的图表和解释! (2认同)
  • 我没有看到“合并提交”和“挤压并合并”之间的区别。在这两种情况下,主分支在最终状态下看起来都是相同的。 (2认同)
  • @dgg 该链接没有“删除”,只是没有显示在那个非常具有误导性的图表上。git 中的提交是不可变的,因此如果提交 D 确实是同一个提交,则它永远具有相同的父级。我在这里针对 GH 文档提出了一个问题:https://github.com/github/docs/issues/21507 (2认同)

Mau*_*fer 77

合并壁球将树(一系列提交)合并为一个提交.也就是说,它会将n次提交中所做的所有更改压缩到一次提交中.

重新定位是重新基础,即为树选择新的基础(父提交).也许这个多变的术语更清楚:他们称之为移植,因为它就是这样:为一棵树选择一个新的基础(父提交,根).

在进行交互式rebase时,您可以选择压缩,选择,编辑或跳过要进行rebase的提交.

希望很清楚!

  • 什么时候应该改变什么时候我应该什么时候压扁? (5认同)

ahm*_*l88 7

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

在此处输入图片说明

现在,我们有3个选项将功能分支的更改合并到主分支

  1. 合并提交
    将保留功能分支的所有提交历史记录,并将它们移入主分支。
    将添加额外的虚拟提交。

  2. Rebase和merge
    将在master分支的前面附加Feature分支的所有提交历史记录。 不会添加额外的虚拟提交。

  3. 压入并合并
    将所有功能分支的提交分组为一个提交,然后将其追加到master分支的前面,
    将添加额外的虚拟提交。

您可以在下面找到master分支如何照顾每个分支

在此处输入图片说明

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

  • 然后我认为“挤压和合并”不会添加额外的虚拟提交,而只会“变基”/将提交附加到主分支前面。您在上面描述的上下文中的虚拟提交与 1. 和 3. 中的虚拟提交不同,因为 1 中的虚拟提交是“将分支 XYZ 合并到生成此提交的主分支”,而 3 中的虚拟提交是“压缩提交到此提交”提交不是由合并产生的额外提交' (7认同)
  • @Yusuf,这只是一个额外的提交,其中包含两个分支更新,它的默认提交消息=“Megrebranch XYZ into master” (4认同)
  • 你能解释一下第二张图片中的虚拟提交是什么吗?我是 git 的初学者。 (2认同)
  • @leticia 包含所有分组提交的提交=“额外的虚拟提交”本身,如上图所示 (2认同)

M H*_*M H 6

我学会理解squashmerge等之间的价值和区别的方法是为自己编写这个简短的教程。

\n
\n

如果你遵循这个,它将解释你想了解的关于挤压、合并、快进和变基的所有内容。

\n
\n

特色分支

\n

假设您在起源处有一个 Main分支,具有提交历史记录,A。

\n

在此输入图像描述

\n

您从Main拉取,并创建一个新分支FeatureA,以便您拥有提交历史记录:

\n
    \n
  • A、F1、F2、F3(FeatureA分支上的三个提交)
  • \n
\n

在此输入图像描述

\n

您希望将更改推送到 Origin 并合并到Main中。由于Origin 上的Main尚未更改,您也可以快进。

\n

合并快进

\n

将FeatureA分支的所有提交历史记录应用到Main\xe2\x80\x99s提交历史记录之上。

\n

在此输入图像描述

\n

与壁球合并

\n

当您的分支有多个提交时,可用的选项是压缩。与Main合并时,压缩将FeatureA分支的历史记录合并到单个提交中。

\n

在此输入图像描述

\n

如果 Main 上有其他更改,则无法快进\xe2\x80\x99。

\n

如果您对FeatureA分支进行了更改,同时其他人已推送到Main中,则 Commits 的 Origin 历史记录现在为:A、B、C

\n

在此输入图像描述

\n

您想要将更改推送到Origin 上的分支,并且您有几个不同的选项:

\n
    \n
  • 合并(不快进)
  • \n
  • 变基,
  • \n
  • 隐藏和拉动。
  • \n
\n

合并(又称不快进合并)

\n

如果您要获取 Origin\xe2\x80\x99s Main分支的本地副本并将其合并到本地FeatureA分支中,您将为该合并创建一个提交 M。您在FeatureA上的本地历史记录将是:A、F1、 F2、F3、M,其中 M 是合并提交。

\n

在此输入图像描述

\n

然后你可以合并到Main(如果你愿意的话可以压缩)。请注意,如果您不压缩\xe2\x80\x99t,您将在主提交历史记录中引入合并提交:

\n
    \n
  • A、B、C、F1、F2、M。
  • \n
\n

您可以通过在合并到Main时挤压分支来避免这种情况,如上面挤压部分所述,结果是: ABCF,如下所示:

\n

在此输入图像描述

\n

变基

\n

Rebase 是避免将合并提交引入历史记录的另一种选择。它本质上会接受您的更改,并使您好像已经开始使用最新的 Main,而不是开始使用过时版本的Main。例如,在变基后,您的功能分支将从 A、B、C 分支(而不是最初的 A)。结果:

\n
    \n
  • A、B、C、F1、F2、F3
  • \n
\n

在此输入图像描述

\n
    \n
  • A、B、C、F(带壁球)
  • \n
\n

在此输入图像描述

\n

注意,没有合并提交,M

\n

Git 实现此目的的方法是系统地(逐次提交)将 origin\xe2\x80\x99s Main中的更改应用到您的分支。最终结果就好像您过去没有基于提交 A启动您的FeatureA分支,但就好像您在最新的Main之上开始了所有更改。

\n

问题在于这样做的方式对于必须应用于您的FeatureA分支的每个提交,git都会检查合并冲突,并且您必须解决它们。如果自您的FeatureA分支以来,Origin上的Main发生了多次更改,您可以一次又一次地解决合并冲突。

\n

也许隐藏和拉动更容易?

\n

隐藏和拉动

\n

存储您的FeatureA ,从 Origin 获取/拉取Main的最新本地副本,然后创建一个新分支并应用您的存储。(或者将新的分支合并到您的分支中,并应用您的存储。如果执行后者,请挤压以避免在提交历史记录中合并。)然后您可以推送到 Origin / 创建拉取请求。

\n


归档时间:

查看次数:

130292 次

最近记录:

5 年,11 月 前