我正在处理的项目是带有父子模块的Maven应用程序。对父模块的更改进入开发分支。每个子模块都有自己的分支,该分支从开发基础上重新继承以继承这些更改。
截至目前,我正在尝试设置一个变基脚本。为此,我试图找出一种自动解决所有冲突且不会中断的方法。作为测试的一部分,我将始终根据自己的更改来重新设置我从开发中获得的测试分支:
git ls-files -z *_child | xargs -0 git update-index --skip-worktree #I do not want the child module to be touched
git rebase -X theirs development
但是,重新定位过程仍然被冲突打断,通常是因为几个月前已解决的非常古老的提交。为了解决这个问题,我使用:
git add .
git rebase --continue
在我遇到另一个冲突之前,这一直有效。目前,我正在考虑使用git rerere
来记录我采取的解决措施:
git config --local rerere.enabled true
但是,我仍在尝试弄清重新定基的实际工作方式。您对git rerere或其他一些git命令有任何建议来解决此问题吗?理想情况下,我想一并剔除git add .
,并始终将默认冲突更改为“其”更改。
答案 0 :(得分:1)
重要的注意事项:您的git update-index
在这里不是很有用。如果基础合并操作需要触摸标记为--skip-worktree
的文件,则Rebase将需要触摸它们。如果没有,它将不会碰到它们。标记文件可能会在执行自动选择操作时给您一个有用的错误(我尚未测试过,但您可以自己对其进行测试)。
重复进行基础git cherry-pick
(有时是等效的)。每个小巧的选择都使用合并过程(我喜欢称谓 merge作为动词或 merge ),并且您会看到,合并可能会有合并冲突。 git cherry-pick
与普通合并不同的两种方式是:
启用rerere
与在其他git merge
上具有相同的效果,因为记录的分辨率的重用以相同的方式发生。这不会对您有帮助,因为您已经在使用-X theirs
,因此可以避免rerere
可以解决的那种冲突。
合并期间的冲突可能是由于我所说的高级操作,整个文件树上的冲突或低级合并工作引起的。我使用这两个短语来区分Git合并引擎中的两个不同的代码部分。合并实际上是通过运行两个git diff
操作进行的:
git diff --find-renames <base> <tip1>
git diff --find-renames <base> <tip2>
这些差异位于git merge
的内部,该差异具有内置的差异引擎,并且可以传递很难通过命令行实现的各种选项,但是原理是相同的:
重命名查找将查看添加和/或删除的文件,并尝试将左侧(合并基础侧)“已删除”文件与右侧“已添加”文件进行匹配。如果是这样,Git决定将该文件重新命名为 。
像这样匹配文件名会生成身份映射:名为 F B 的基本文件具有新名称 F L 位于左侧, F R 位于右侧。这三个名称可能相等,或者两个或三个名称可能不同,但是无论哪种方式,这都是“相同”的文件。它还使我们可以在任一侧添加和/或删除文件,并且可以在一侧或两侧修改或不修改的文件。
现在我们必须结合所有更改……但这首先发生在文件名和存在性级别:
如果左侧删除文件 F d ,而右侧未更改文件,则可以。但是,如果左侧将其删除而右侧对其进行了修改,则我们将发生删除/修改冲突。 (如果右侧删除了它,而左侧修改了它,则我们有相同的冲突,相反)。
如果左侧重命名文件而右侧删除文件(或两边互换),则我们会出现重命名/删除冲突。
如果双方从头开始添加新文件但名称相同,则我们会发生添加/添加冲突。
如果双方都重命名了基本文件 F B ,但重命名为两个不同的名称* F L 和 F < sub> R ,我们有一个重命名/重命名冲突。
Git单独解决了这些冲突。这些是高级冲突。
已经解决(或未解决)任何高级树操作,现在我们遇到了以下情况:同一文件已从基础转移到两个分支提示中,其中“同一个文件”按上述方式进行了重命名,但已被两个文件修改双方。 Git现在从名为ll-merge.c
的单独文件中运行代码:低级合并代码。
LLMerge允许用户定义合并驱动程序。使用这些文件时,整个操作取决于合并驱动程序,合并驱动程序仅获取所有三个输入文件的数据(基本,左/ HEAD和右/它们的)。使用内置的合并驱动程序时,可以使用-X
扩展选项自动解决冲突 :-X theirs
选择右侧更改,放弃左侧更改侧(base-vs-HEAD)更改。 -X ours
选择左侧更改。没有这些选项,当更改重叠或邻接时,Git只会声明冲突。
由于您正在使用-X theirs
并发生冲突,因此我们可以得出结论,您肯定会遇到高级冲突。 Git的rerere代码不会记录,也不能重复使用这些分辨率。
要在合并由于冲突而停止后发现它们,可以使用git status
或使用git ls-files --stage
检查索引/暂存区。不幸的是,Git在记录实际发生的高级别冲突方面做得很差(大多数情况下不存在)。它打印冲突,因此,如果您捕获了输出,则可以对其进行解析;或者,您可以运行自己的git diff --find-renames --name-status
命令来查看合并所看到的内容。
在合并的一般情况下,git diff --find-renames
存在问题,因为git merge
可能会建立一个临时提交,其中包含Git所说的虚拟合并基础。但是,对于Cherry-pick,合并基础只是当时选择的提交的父级,因此使用此方法可能是可靠的。您将不得不以任何一种方式编写代码。