好的,首先,我有这个权利吗?:
假设您有本地分支A和B,并且它们没有共同的提交。
当我这样做时
git checkout A
git merge B
除了合并B中尚未在A分支上的所有提交外,Git还在A分支上创建一个新提交。
现在假设分支C和D至少有一个共同的提交。当我运行相同的两个命令时,Git不会创建额外的提交。它只是将现有的提交从D合并到C中。
假设这一切都是真的......为什么?
答案 0 :(得分:12)
运行git merge
时,发生的实际行为取决于您正在合并的两个分支提示之间的提交的图拓扑。
如果您要合并的分支B
已经是您A
的分支的祖先:
u -- v -- w [B]
\
x -- y -- z [A]
...然后B
中的所有工作都已包含在A
中,因此git报告Nothing to be done
,并且没有提交。
如果情况发生逆转且A
是B
的直接祖先,那么git需要做的就是将A
压缩到B
所在的位置。由于B
的历史记录已包含A
所做的所有工作,因此不存在冲突的可能性。此外,移动分支指针后,来自A
和B
的所有提交仍然可以访问。因此,创建提交不是必需的。
之前
u -- v -- w [A]
\
x -- y -- z [B]
后
u -- v -- w -- x -- y -- z [A, B]
顺便说一句,你可以通过将--no-ff
标志传递给git merge
来强制git在这种情况下创建合并提交。如果您希望始终在master
之外的特征分支上保留提交,这有时很有价值。
另一方面,您也可以传递git merge
--ff-only
标志,如果此情况不,则会失败。如果你想绝对肯定你的合并是一个微不足道的并且赢得创建一个新的提交,比如当你合并{{1}时,这很有用。进入origin/master
并且您不应该在master
上完成任何本地工作。
在master
和A
两者都有未包含在其他历史记录中的提交的更一般情况下,git的真正合并机制被调用。遍历提交图以查找共同的祖先B
,并调用three-way merge算法来解决更改。如果存在任何冲突,则冲突标记将留在工作副本中供用户解析和暂存。如果没有,则创建一个新的提交,同时C
和A
作为父项记录合并并保留两个分支的历史记录。
之前
B
后
u [C] -- v -- w [A]
\
x -- y -- z [B]
您可能会遇到其他策略 - 例如,在合并两个以上的分支时会发生章鱼合并 - 但这些是基础知识。所以你有它: git是否创建合并提交,具体取决于所讨论的分支拓扑是否需要它。
顺便说一句,如果u [C] -- v -- w -- m [A]
\ /
x -- y ------- z [B]
和A
真正没有共享提交,那么合并算法没有共同的祖先可以使用并且回到相当丑陋的猜测这导致了许多虚假的冲突。它有很多方法(例如伪造一个空的共同祖先),但它们相当先进和不常见。