检查post-rewrite hook中是否存在冲突

时间:2016-08-26 19:52:52

标签: git rebase git-rebase githooks

post-rewrite挂钩的上下文中,有没有办法知道导致挂钩的rebase是否存在需要解决的冲突,还是只是重放更改?

1 个答案:

答案 0 :(得分:2)

简短的回答是" no"。

更长的答案仍然是"否......但你可以通过重复操作来接近,也许足够接近。但请注意警告。"

概括

让我们概括一下,这样我们不只是讨论重写后的钩子,因为这个问题也适用于重复git rebase(例如在修复日志消息后重新重新定义) )或执行git rebase -p(保留合并,必须重复先前的合并)。

每当Git调用其三向合并机制时,它的作用相当于:

ours=$(git rev-parse HEAD) # or equivalent
theirs=$(git rev-parse $something_else)
base=$(something) # usually git merge-base, but this varies as well
git diff $base $ours > our.change
git diff $base $theirs > their.change
combine_our_change_and_their_change

(用伪shell写的)。

对于常规git mergebase=$(something)部分确实使用git merge-base,或者更确切地说,使用git merge-base允许您使用的相同代码。完全 它如何使用它取决于合并策略:

  • 对于-s resolve,Git以git merge-base的方式选择其中一个合并基础并使用它。
  • 对于-s recursive,Git选择所有的合并基础,合并它们(递归地,使用它们自己的合并基础进行这些合并)到达a"虚拟合并基地"。在大多数情况下,无论如何只有一个合并基础,这意味着它与-s resolve完全相同。在大多数剩余的情况下,有两个合并基础,并且合并这两个合并基础产生与随机选择这两个合并基础中的一个相同的事情,这意味着此仍然做同样的事情为-s resolve。在少数情况下,合并基础会产生与合并基础略有不同的东西,在特别有问题的情况下,合并合并基础会导致合并冲突,并且在可能仅在使用手工精心设计的场景中出现的情况下构造的多维提交图,我们可以有两个以上的合并基础,事情变得非常疯狂。但大多数情况下这与-s resolve完全相同。
  • 对于-s ours,Git实际上并没有进行合并,整个问题就消失了。
  • 对于-s octopus,Git找到一个多路合并基础,如果存在冲突则中止合并,并且只有在没有合并冲突时才结束,这样问题就会以与{{1}相同的方式消失}}。

归结为我们需要知道使用了哪种策略。不幸的是,Git无论如何都不记录这些信息。所以这是一个警告#1。我们可以猜测,如果有两个合并父母,策略为-s ours,如果有两个以上,则为-s recursive,但这只是猜测。 1

如果合并是由-s octopus完成的,那么这对于任何程度都是有用的,但是如果三向合并操作是git merge或等效的结果会怎么样?在这种情况下,git apply -3可能根本不是提交,而不是两个base命令来比较两个提交,我们可能只想做相同的事情:

git diff

查找有问题的三个文件有点棘手。在简单的情况下,它们在三次提交中都具有相同的名称,和/或,我们有完整的blob哈希ID,以便我们可以通过哈希ID提取文件内容,而不必担心路径名。我们仍然遇到git merge-file $options $ourfile $basefile $theirfile 的问题,可能是以下之一:

  • 没有:正常合并:在发生冲突时因冲突而停止
  • $options--ours -X ours的{​​{1}}参数:赞成"我们的"在冲突的情况下
  • git merge--theirs -X theirs的{​​{1}}参数:赞成"他们的"在冲突的情况下
  • git merge:进行联合合并(目前只能通过--union指定,即使存在冲突,联合合并也会成功)

与策略一样,Git无法记录此信息。这个警告#2:在重复操作时,你必须猜测其他策略参数。

警告#3是.gitattributes:如果发生冲突,Git可能会重新使用重新有线重新解决方案因此你不会看到冲突。这对您来说意义重大取决于您的目标/需求。

应用于重写后挂钩

现在让我们回到the post-rewrite hook。此钩子目前仅在执行git rereregit commit --amend后调用,并且可以通过检查其参数来告诉使用了哪个命令

然后,它在标准输入上接收重写列表:

git rebase
     

extra-info再次依赖于命令。如果它是空的,那么     在SP之前也省略了。目前,没有命令通过任何命令     额外的信息。

此&#34;额外信息&#34;可能是我们可能会得到一些缺失的项目(例如战略和选项) - 但我们不会。但是,我们确实知道rebase基本上会做一系列的挑选。它还默认使用完整的提交范围差异(<old-sha1> SP <new-sha1> [ SP <extra-info> ] LF -m等)以检测重命名。换句话说,当我们找到要赋予--merge的文件名以重复任何给定的文件级合并操作时,我们需要两个git-diffs-against-a-base方法。

我们甚至不必走那么远。我们有两个提交哈希:原始提交,以及新产生的提交。我们可以切换到临时分支 - 例如匿名分离的HEAD - 和临时工作树,并将新原始提交的另一个git merge-file(旧SHA1)转换到新提交的父级(新SHA1)加上帽子后缀),使用git cherry-pick来阻止提交本身,并查看是否存在冲突。模拟我们的所有警告,这可以让我们看看用户是否必须解决一些冲突。

但是,我们必须注意-n的另一个问题:交互式 rebase允许用户将git rebasesquash几个原始提交合并为一个单个最终的新提交。再次引用githooks文档:

  

对于 squash fixup 操作,所有被压缩的提交都被列为被重写为压缩提交。这意味着将有多行共享相同的 new-sha1

一些中间结果(来自应用一个或多个原始提交)可能分别具有或缺少一些冲突,这些冲突分别来自或现在出现在最终重写的提交中。对于我来说,对于这些案件你想做什么并不是很清楚。 (就此而言,我根本不清楚你想要做什么&#34;首先要解决的问题是什么?#/ p>

1 如果合并提交是由fixup创建的,它有两个以上的父母,那肯定来自git merge-s ours。其他合并策略只能解决两个&#34; head&#34; (承诺就好像它们是分支的尖端一样)。但我们可以创建合并提交,而无需运行-s octopus。例如,git merge命令执行此操作。在任何意义上,这些都不是正常的合并:git stash简单地(ab?)使用Git的各种机制以方便紧凑的形式记录一堆信息,以便以后解除隐藏。尽管如此,一些提交对象git stash使得合并提交