合并和转换如何工作?

时间:2016-01-02 23:54:39

标签: git git-merge git-rebase

我试图理解merge和rebase在数学中的set操作方面做了什么。

在下文中," - "意味着diff(类似于数学中的设定差异,但是" A-B"意味着A中但不是B中的那些而减去B中而不是A中的那些)和" + "意味着patch(即在数学中采用不相交的联合。我之前没有使用patch,所以我不确定。)

  1. 来自Chacon的Pro Git,

    enter image description here

    最近的共同祖先C2在这方面的作用是什么 合并?

    C5 =(C4-C2)+(C3-C2)+ C2是否正确?

  2. 对于rebase而不是merge:

    enter image description here

    C4'是否正确? =(C4-C2)+ C3?

    C5来自合并和C4'来自rebase的内容相同吗?

  3. 使用Git by Loeliger进行版本控制

    enter image description here

    W' X',Y'和Z'产生

3 个答案:

答案 0 :(得分:6)

使用“diff”和“patch”语义无法正确解释Git。原因是Git没有跟踪变化;它跟踪内容。当你有一个父提交A的提交B时,对于Git,A不是BA之间的差异,即更改需要从BA,但A的实际内容。您可以自己进行提交,并且您可以在此时重建存储库。

出于这个原因,我不会遵循你的“提交算法”,而是试着用文字解释每个案例。

  1. C5是两个父母C3和C4的合并提交,它们都有C2作为父母。因此,假设没有冲突,并且Git能够自己解析整个合并,那么C5将包含由以下两个等效表达式表示的内容:

    • 使用了补丁的C3,可以让你从C2到C4。
    • 应用了补丁的C4,可以让你从C2到C3。

    所以在某种程度上,你可以用你的公式来表达它。

  2. 一个rebase基本上会让你处于完全相同的情况。唯一的区别是它实际上重写了它重新提交的提交,将它们的更改(补丁)重新应用到另一个提交。因此,结果C4将与(1)中的C5具有相同的内容。

    通过你的“算术”,我通常会说(C3-C2) + C2 = C3。所以这两个公式在这里也是等价的。

  3. 如上所述,rebase只是将提交补丁重新应用到另一个父级。 Git正在编写包含与原始提交相同的 change 的新提交,但这些新提交将应用于不同的父提交。

    因此,如果你想获得公式,它可能看起来像这样:

    W' = E  + (W - B)        (the patch from B to W, applied on E)
    X' = W' + (X - W)        (the patch from W to X, applied on W')
    Y' = X' + (Y - X)        (the patch from X to Y, applied on X')
    Z' = Y' + (Z - Y)        (the patch from Y to Z, applied on Y')
    

    因此,W的基数更改为E而不是B,所有后续提交都会更新,以代替新的提交W'

    但同样,结果Z'具有与合并提交相同的内容,合并提交已合并EZ

  4. 这一切都给我们留下了一个问题:如果两者产生相同的内容,那么合并和rebase之间有什么区别?由于您不会以两种方式丢失提交(rebase将创建新的提交对象,但这些将保留所有原始信息),基本上所有关于改变历史记录的方式:

    合并创建一个合并提交,允许清楚地看到历史分歧的位置(创建分支的位置)以及它再次联合的位置。这很好,因为你可以按照确切的发展。但它也可能变得混乱,特别是如果你有多个并发分支线,最终会合并多次。

    另一方面,重新定位使历史持平。它“伪造”它,所以一切都是线性发展,一切都接连不断。由于您总是在重新设置一个完整的分支,因此您可以将相关提交保持在一起,这样您仍然可以看到彼此之间存在的内容,但是您会丢失任何分支信息。此外,您正在创建新的提交对象,这将破坏已经知道这些提交对象的每个人的存储库(这就是为什么您不应该重新发布已发布的提交的原因)。

    两种方式都有利有弊。它在很大程度上取决于存储库工作流程和个人偏好。

答案 1 :(得分:2)

  

最近共同祖先C2在此合并中的作用是什么?

     

C5 =(C4-C2)+(C3-C2)+ C2?

是否正确

最新的共同祖先用于确定在experiment中尚未出现的分支master(在您的示例中)中进行了哪些更改(参数为在最后一个共同祖先之后,experiment分支的分支尖端可以访问的所有提交都不是主分支的一部分。

experiment分支合并到mastergit merge experiment时,Git会使用共同祖先和分支的分支尖端之间的差值进行合并(experiment ,在这种情况下)找出要在合并提交中应用的更改。

在您为问题选择的集合符号中,我将其表示为C5 = C3 +(C4 - C2)。

  

C4'=(C4-C2)+ C3?

是否正确?      

来自合并的C5和来自rebase的C4'具有相同的内容吗?

两种假设都是正确的。请记住git rebase保持提交的增量完整,因此在您的示例中,表达式(C4' - C3)=(C4 - C2)为真。

  

W',X',Y'和Z'是如何产生的?

如上所述,git rebase保持提交的增量。这意味着(例如) W 与其父提交 B (或 W-B )之间的差异,您也可以使用{生成{1}})。

然后,rebase只在新的父提交上应用相同的delta;所以在你的例子中(W' - E)=(W - B)(因此对于 X Y Z < / em>的)。

答案 2 :(得分:1)

  1.   

    最近共同祖先C2在此合并中的作用是什么?

  2. c2 c3+c4

    有两位家长

    rebase而不是merge的全部意义在于你将拥有一条“直线”而不是所有那些叉子(像蛇一样)。

    你接受你的工作并将它放在分支的顶部作为符号线,在合并中你将至少有2个父母(提交)到合并点。