不是git merge --squash真的git rebase -squash?

时间:2016-12-27 04:44:48

标签: git git-merge git-rebase git-commit

试图理解为什么命令

git merge --squash mybranch

不被称为

git rebase -squash mybranch

因为看起来它的操作更像是一个rebase而不是一个合并。我的理解是它在提交树中搜索,直到找到当前分支和mybranch的公共基础提交。然后,它将从该基节点到mybranch的头部的所有提交重新应用(重新绑定)到当前分支的头部。但这是否进入索引/工作区,因此它可以作为单个提交应用。完成后,没有合并节点,因为正常合并显示合并的两个分支。我有正确的理解吗?

1 个答案:

答案 0 :(得分:2)

嗯,合并和变基是根本不同的操作。合并,我的意思是创建新的合并提交的常规git merge - 确实通过提交图搜索最近的常见提交:

...--o--*--o--o--A   <-- mainbr
         \
          B--C--D--E   <-- sidebr

此处,最新的常见提交是*。然后,合并过程将比较(如git diff)commit *和commit A以找出“我们做了什么”,并将diff *与提交E进行比较找出“他们做了什么”。然后,它使用两个父项进行新的单个合并提交:

...--o--*--o--o--A---M   <-- mainbr
         \          /
          B--C--D--E   <-- sidebr

加入两个历史,并结合“我们做了什么”和“他们做了什么”,以便差异* vs M给出“每个变化之一”。

请注意,您在此处无法选择合并基础:Git将其计算出来,就是这样。

另一方面,Rebase可以分别告知哪些提交要复制,哪些复制。确实,默认情况下,它再次找到提交* 1 - 然后使用git cherry-pick逐个复制原始提交或同等的;最后,它将分支标签移动到指向最后一次复制的提交。

...--o--*--o--o--A   <-- mainbr
         \        \
          \        B'-C'-D'-E'   <-- sidebr
           \
            B--C--D--E

原始提交链(在这种情况下为B-C-D-E)仍然在存储库中,并且仍然可以找到:它们可以通过哈希ID找到,也可以在sidebr的reflog中找到,如果任何其他分支或标记名称都可以访问它们,它们仍然可以通过该名称访问。

git merge --squash做的是稍微修改合并过程:而不是像往常一样进行合并提交M,Git像往常一样浏览合并机器,使合并基础不同 - 您无法选择 - 反对当前提交和另一个提交,并组合索引和工作树中的更改。然后 - 没有明显的原因 2 -stops并让你运行git commit来提交结果,当你这样做时,它是一个普通的非合并提交,所以整个图-fragment看起来像这样:

...--o--*--o--o--A--F   <-- mainbr
         \
          B--C--D--E   <-- sidebr

现在,提交F内容 - 合并产生的快照树与提交M的内容相同当我们进行真正的合并时, - 这是真正的踢球者 - 当我们进行重组时,它的与commit E'的内容相同。

此外,假设在分支B上只有一个提交(sidebr)。现在,mergemerge --squashrebase中的所有三个都会为您提供一张图片,其中的结尾可能是我们可能会画出的内容:

...--o--*--o--o--A--B'   <-- ???
         \          ?
          B?????????   <-- ???

和新提交B'内容,即最终快照,在所有三种情况下都是相同的。但是,对于git merge,新提交将位于分支mainbr上,并将指回提交AB,其中sidebr指向{{1} }};对于B,新提交将在git merge --squash上,并且仅指向mainbr;对于A,新提交将在git rebase上,没有明显指向sidebr,我们应该将其绘制为:

B

因为...--o--*--o--o--A <-- mainbr \ \ B B' <-- sidebr 将继续指向提交mainbr

最后,这看起来更像是一个合并而不是像一个rebase。 (但是,如果它根本不被称为“壁球合并”,我会更高兴。)

1 Git找到A的方法有些不同:它实际上不是单个提交,而是最后一个(通常)非常大的提交,即,从*参数到<upstream>可以到达的所有参数。 (令人困惑的是,合并基础也可以是一组提交,但它是一个更受限制的集合。最好不要深入研究图论。:-))

2 如果我们它停止,我们可以像使用常规非挤压git rebase一样使用--no-commit。那么 为什么会自动停止?