在将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
包括反转每个文件的每一行上的文本,而提交H
是G
的还原。然后,在G
上重新定基实际上保证会有冲突(没有行匹配(,但在H
上重新定基则不会有冲突(H
中的快照与C
中的快照匹配(。事实上——无论是高兴的、悲伤的还是中性的——提交G
在历史上只是与提交C
和H
相关的;它有完全不同的源文件。
当然,我们通常不会发现一个完全打乱每个文件的提交,然后是一个恢复以前状态的提交。我们确实偶尔会发现已被还原的提交,因此,通过一些冲突的程序测试,我们可能会发现不相关的提交(例如我们的理论示例中的提交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>
,并检查输出是否提到冲突。