查找两次提交的第一个孩子共同(Find first common child of two comm

2019-06-25 06:40发布

           :
           A
T         / \
i        B   C
m        :   :
e        D   E
          \ /
|          F
V          :

git merge-base B E allows to find where a the common ancestor A of the two commits. Is there a way to find the commit F where the two branches are merged again?

Answer 1:

哎呀。 没有阅读不够仔细。

在提交的唯一信息是它的父(或父母)的ID。 你不能从父项的子犯(这是存储库是一个DAG的定向部分)。

望着这-它看起来像--ancestry-path的git的日志能做到这一点的选择。 比如给定:

* 85d26ab When compiling vim, also compile & install gvim
*   3146e5d Merge remote-tracking branch 'origin/devel' into deve
|\
| * 28d08e5 rebasing-merge: specify all commits explicitly
* | 006d11d Help 'file' find its magic file
|/
* e68531d (tag: Git-1.7.6-preview20110720) Update submodules

我们可以用得到这两个提交的所有儿童

git log --oneline --ancestry-path B..E

如果你再扭转这种并摘下第一个 - 那就是F.

git rev-list --reverse --ancestry-path 28d08e5..006d11d | head -1

在我的情况下,返回3146e5d。



Answer 2:

这里不一定是唯一的回答这个问题,所以你必须决定对一些约束和/或启发,或接受可能不止一个“下游”的合并。 问题的心脏是一样多的合并基础考生使用的问题git merge-base --all全部列出来,否则的Git只是挑选哪一个在其算法首先弹出。 我们可以做同样的,或发现所有最好的合并候选者。

你画的是什么,我通常喜欢侧身呈现为,例如:

  B--...--D
 /         \
A           F--G--H   <-- branch1
 \         /
  C--...--E   <-- branch2

但我们可能有这样的:

  B--C---D--E--...   <-- branch1
 /    \ /
A      X
 \    / \
  F--G---H--I--...   <-- branch2

在这种情况下,两个合并DH同样的,如果你让两个“里的树枝重新合并的地方”很好的候选人branch1branch2加以考虑。 即使你不这样做,如果branch2合并回branch1后:

  B--C---D--E---J--...   <-- branch1
 /    \ /      /
A      X      /
 \    / \    /
  F--G---H--I--...   <-- branch2

然后就无法启动(或终止) branch1 ,既DH同样很好的候选人。

在任何情况下,我们需要的就是枚举中的一个或所有要考虑分支的结束的提交。 要做到这一点,我们就可以使用,例如:

git rev-list --ancestry-path ^B ^E branch1 branch2

这个发现是祖先提交branch1 branch2 ,而且还承诺的后裔B 承诺E

要真正得到正确的答案,我们要添加--children 。 这样,我们会得到每个哈希ID提交,与孩子们一起犯这个相同的方向走。 混帐达到--children通过反转从孩子到家长的向后连接,因为它穿越的联系,这是不够好; 但我们不会看到提交BE 。 这是怎样的一个问题。 若要显示它们,我们可以添加--boundary 。 这不是理想的: --boundary有时包括一些提交我们不希望。 幸运的是,他们都标有-所以我们可以排除额外的边界被淘汰那些不属于我们所关心的提交提交。

我不会表现出任何的是,但如果你这样做,你现在将有一个列表,每行一个条目中的每个节点(顶点)和其边缘连接到其子女。 现在,您可以问什么是DAG的这些(V,E)组形成的LCA?

这将是很好,如果我们可以只使用Git的LCA算法,但Git不会有一种方法来调用它的任意图形,我们只能调用它在提交时,实际提交有父母,而不是孩子。 所以,你将不得不自己编写。 见算法找到向无环图最低的共同祖先? (其中,不幸的是,还没有公认的答案)。 该算法看起来乍一看正确 ; 它具有在图形为LCA两种标准定义之一。

如果我们愿意接受一个不近-AS-很好的答案,但是,我们可以得到的东西,通过增加在大多数情况下,可能已经足够了--topo-order (以确保所有家长他们的孩子出来后)和--merges (省略一切,这不是一个合并提交)。 这将让所有合并的名单。

我在这里做一个简单的测试,如属库:

$ git log --all --decorate --oneline --graph
* 91fcef6 (HEAD -> master) J
* d1e5905 I
*   5bf18a0 merge
|\  
| * 49b2ba7 (sidebr) D
| * 725e5ea C
| * 36b830d (tag: B) B
* | 198a982 (tag: G) G
* | 216bc01 F
* | e905e59 E
|/  
* 5df9428 initial

所以,我现在的名字提交使用B和G BG ,我想对“在这个方向移动”分支就是master 。 所以:

$ git rev-list --topo-order --merges --ancestry-path ^B ^G master
5bf18a0797dfd78107928a9a4095f357cfabe914

这里的最后一行是这是“最接近”两次提交的合并。 在这种情况下,这也是唯一的线,这就是我们想要的合并。

这里的缺陷是非常明显的,一旦我们得出的。 假设我有一个更复杂的图形,如:

      I--J
     /    \
    H      M--N
   / \    /    \
  /   K--L      \
 /               \
A                 P--Q  <-- master
 \               /
  \   C--D      /
   \ /    \    /
    B      G--O
     \    /
      E--F

如果我现在运行git rev-list --topo-order --merges --ancestry-path ^B ^H master ,我会列举犯P ,那么这两个GM以某种顺序。 因此, 最后一行将要么被提交G或承诺M ,虽然两者都是合并,不符合正确的标准:他们不合并BH 。 只有提交P做到这一点。

因此,要检查你是否有一个正确的答案,不处理多个LCA问题,您应该采取每个输出线从这个git rev-list命令,可能以相反的顺序(考虑增加--reverse ),看看是否都提交各自的祖先。 “内部”合并像GM将只有一个承诺作为祖先。 要做到为始祖的测试,使用git merge-base --is-ancestor

if git merge-base --is-ancestor $commit1 $mergecommit &&
       git merge-base --is-ancestor $commit2 $mergecommit; then
    ... we've found a correct candidate
else
    ... move on to another candidate
fi


Answer 3:

适应all.awk从这个答案也随身而行号为每个裁判,那么当你遭遇双方父母看看他们的共同点裁判。



文章来源: Find first common child of two commits