给定两个任意提交,如何检测git merge是否会导致空提交?

时间:2018-12-20 05:09:26

标签: git git-merge is-empty libgit2sharp

如果我使用LibGit2Sharp的“差异(Diff)”功能比较两个分支提交,则差异有变化,而与我比较它们的顺序无关。

var newBranch = repository.Branches[currentBranchName];
var oldBranch = repository.Branches[name];

var patch = repository.Diff.Compare<Patch>(oldBranch.Tip.Tree, newBranch.Tip.Tree);
var patchChanges = patch.Count();

如果在上面的代码中交换newBranch和oldBranch,则会返回相同/相反的补丁。例如,如果第一个补丁是+300 -200之类的东西,那么以相反的顺序扩散分支将得到-300 +200的补丁。

另一方面,如果我将一个分支合并到另一个分支中,则可能不会引入新的更改(即将导致一个空的合并提交),而如果我以相反的顺序进行合并,则会有更改。

我实际上只是在尝试检测一个分支是否缺少另一个分支的修补程序,这与回答是否将一个分支合并到另一个分支会导致合并合并提交的问题相同。我可以得到前/后计数,但是通常,当一个分支一次提交在另一个分支之后时,该提交是一个空的合并提交,因此它实际上并不在后面(即新的合并提交将是空的),因此后面的count并没有真正告诉我是否缺少修补程序更改。我以为也许我可以只比较两个提交,但是正如我发现的那样,在两个方向上总是有相同/相反的变化,而我需要一些操作来检测一个特定方向上没有变化(即“提前” commit为空)。我在LibGit2Sharp中找不到任何可以告诉我合并提交是否为空的内容。

1 个答案:

答案 0 :(得分:2)

可能会发生空合并,但除其他外,它需要定义我们所说的空合并

合并有三个输入,而不是两个。差异有两个 输入,而不是三个。

当Git执行合并时,通常的合并是真正的合并,不是章鱼合并,不是快进操作或git merge可以执行的其他一些操作,而是真正的三项合并-与两个分支技巧和一个合并基础的合并方式-Git必须运行 two git diff个操作,而不是一个,因为每个git diff都只比较 two 树木,我们需要比较三棵。

三个输入中的第一个是两个分支提示。相反,它是两个提示之间的合并基本提交

          C--D--E   <-- ourbranch (HEAD)
         /
...--A--B
         \
          F--G   <-- theirbranch

在这里,每个大写字母代表一个实际的提交哈希ID。要进行合并,Git必须:

  • 找到提交B,合并基础
  • BE进行比较:我们有什么变化?
  • BG进行比较:它们发生了什么变化?
  • 结合这些变化!

合并完成后,假设一切顺利,Git进行了一个新的提交,该提交具有两个父母,而不是一个父母:

          C--D--E
         /       \
...--A--B         H   <-- ourbranch (HEAD)
         \       /
          F-----G   <-- theirbranch

如果合并后将HE进行比较,您将看到通过theirbranch进行的更改:B vs {{1 }},减去GB中已经存在的任何内容。如果将EH进行比较,您将看到通过G进行的更改:ourbranchB,减去在{{ 1}}与E

如果我们将空合并定义为BG不会产生任何区别(即H中的快照与{{ 1}}){em>和 EE不会产生任何区别,那么E必须匹配H。 (G的内容与此定义无关!)

如果我们将空合并定义为EG不会产生任何差异的值,而不考虑BH是否产生一些差异差异,那么有更多的方法可以到达这里。一种是在运行E时使用H,因为它指示Git完全忽略第二个diff(实际上,不必费心运行它):只需使用{{1 }}作为G的快照,同时仍使历史链接将-s ours向后连接到git merge G。另一个是要确保HH差异中的内容只是EG差异中的内容的子集,这样,将两个diff组合在一起的过程最终只会得到B -vs-G diff。

如果我们将空合并定义为BH相匹配的内容,则约束会更加严格。唯一自然的方法是让B也匹配H,如果我们不使用H,则让B匹配E为{好吧。

(请注意,我们可以运行B来阻止Git自动提交合并结果。在这种情况下,我们随后可能会弄乱索引的内容(Git将根据该内容进行下一次提交,这样一来,无论-s oursG和/或B中的内容如何,​​我们都可以根据git merge --no-commit来构建树,使其看起来像我们喜欢的样子。通过任何常规设置。)

因此,如果您想预先计算合并将执行的操作,那么您的工作就是这样:

  1. 找到合并基础提交H。 (还要考虑如果从两个分支技巧中向后走来的两个历史记录之间没有共同的提交,或者如果有多个最佳的共同提交,会发生什么情况。)
  2. 已经定位了B,或者以E的方式进行了递归合并(对于基于多重合并的情况),请运行Git会执行的两个diff操作。记住要启用重命名检测。
  3. 合并两个差异。

(此处不包括:当两个分支提示都针对合并基础修改文件时,Git将使用在G文件中选择的任何合并驱动程序。如果要模拟合并,您也应该这样做。)

只需合并并查看会发生什么,通常要简单得多。如果您不想更新当前分支,请在进行合并之前分离B,或使用B进行合并,然后使用git merge -s recursive停止合并并重置。