确定目标分支中的哪个提交导致了冲突

  • 本文关键字:提交 冲突 目标 分支 git
  • 更新时间 :
  • 英文 :


在将foo重定为master的基础时遇到冲突时,是否有方法以编程方式确定master上的哪些提交导致冲突?

要手动执行此操作,我基本上会找到冲突的行,签出master,运行git blame,然后查看哪些提交在合并基础之后更改了这些行。

有没有一种简单的方法可以通过编程来完成这个过程?

这不是重复的问题

与这些其他问题不同,我想知道目标分支上的哪些提交会导致冲突,而不是我正在重新建立基础的分支上的提交。

  • git-rebase冲突是由哪个提交引起的
  • 如何在git rebase过程中通过hash来识别冲突的提交
  • 确定哪些提交会导致冲突

假设您可以中止rebase来进行此测试,我会通过在master上临时创建一个新分支来处理它,尝试将其重新绑定到foo上,并提取在该操作中首先发生冲突的提交。

#!/bin/bash
# Make these command line parameters if you want
dest=master
source=foo
# Find the conflict commit
git checkout $dest
tmp_branch=$(mktemp -u | sed 's/.*///') # Not strictly safe, I know, but it works
git checkout -b $tmp_branch
if git rebase $source; then
conflict_commit=None
else
conflict_commit=$(git am --show-current-patch | head -1 | sed 's/ *commit *//')
git rebase --abort
fi
git checkout $source
git branch -D $tmp_branch
# Use $conflict_commit as needed
echo Conflict at "$conflict_commit"

在将foo重定为master的基础时遇到冲突时,是否有方法以编程方式确定master上的哪些提交导致冲突?

正如Tim Biegeleisen在评论中指出的那样,简短的答案是否定的。这有点太简短了,因为理论上这是一个答案,而实践中通常有一个机器可以找到的答案。("在理论上,理论和实践是一样的。在实践中,它们不是。"(

理论问题的根源在于Git中的每个提交都只是一个完整的快照。因此,如果我可以稍微滥用这个术语的话,每个提交都是幂等的。例如,假设我们有以下提交序列:

...--B--C---------G--H   <-- master

D--E--F   <-- feature

我们现在决定将feature重定为master的基础,即在提交H之后。我们可能会发生冲突,也可能不会发生冲突。如果我们选择在G而不是H之后重新建立基础,我们可能会也可能不会得到一组完全不同的冲突。

例如,假设提交G包括反转每个文件的每一行上的文本,而提交HG的还原。然后,在G上重新定基实际上保证会有冲突(没有行匹配(,但在H上重新定基则不会有冲突(H中的快照与C中的快照匹配(。事实上——无论是高兴的、悲伤的还是中性的——提交G在历史上只是与提交CH相关的;它有完全不同的源文件。

当然,我们通常不会发现一个完全打乱每个文件的提交,然后是一个恢复以前状态的提交。我们确实偶尔会发现已被还原的提交,因此,通过一些冲突的程序测试,我们可能会发现不相关的提交(例如我们的理论示例中的提交G(,但如果是这样,那通常不是什么大问题,因为我们稍后会看到它们被还原。因此,如果我们正在进行一些重新基准,并且一些提交X未能应用,那么我们所需要做的就是:

...--B--C---------[sequence]   <-- master

D--X--F   <-- feature

并尝试对序列中的每个提交重新设置基准。棘手的部分是选择要尝试的提交,以提高效率并处理序列中的合并气泡(如果存在(。然而,强力git rev-list --reverse --topo-order feature..master会给我们一个合理的起点:我们现在会尝试重新调整提交的基础,直到每个提交都包含X,直到其中一个失败。

joanis的方法利用了对称性(不是严格保证的,尤其是在存在回复的情况下(,并且可能更有效。我们可以检查每种方式需要重新基于的提交N的数量,并选择其中较短的一个。不过,一般来说,为了提高效率,我会使用平分方法,因为这通常能够在log2N个步骤中识别问题,其中N是潜在冲突提交的数量。

不过,第一件事可能是让蛮力方法发挥作用。为了避免干扰现有的工作树(到目前为止,其中有冲突的rebase(,我建议一个这样做的工具——据我所知,它还没有编写出来——通过使用git worktree add创建一个分离的HEAD工作树来工作。

如果您正在重新创建数据库,您将无法轻松调用git merge(或者可能使用单独的索引文件?(。

使用git merge-tree可能会有一些运气:您可以连续调用

# while rebaseing, REBASE_HEAD points to the commit being replayed :
git merge-tree REBASE_HEAD^ REBASE_HEAD <commit>

对于master分支中的每个<commit>,并检查输出是否提到冲突。

最新更新