【问题标题】:How to automatically resolve all conflicts in git rebase, "git add ."如何自动解决 git rebase 中的所有冲突,“git add .”
【发布时间】:2020-03-02 08:01:42
【问题描述】:

我正在处理的项目是一个包含父模块和子模块的 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 .,并始终默认冲突为“他们的”更改。

【问题讨论】:

    标签: bash git rebase git-rebase git-add


    【解决方案1】:

    重要的第一个注意事项:您的git update-index 在这里不是很实用。如果底层合并操作需要接触标记为--skip-worktree 的文件,Rebase 将需要接触它们。如果没有,它就不会碰它们。标记文件可能在cherry-pick操作期间给你一个有用的错误(我没有测试过,但你可以自己测试一下)。


    rebase 重复git cherry-pick(或有时是等价的)。每个cherry-pick都使用合并过程——我喜欢将其称为作为动词的合并,或合并——正如您所见,合并可能会产生合并冲突。 git cherry-pick 与普通合并的两种不同之处是:

    1. 合并基础只是被挑选的提交的父级。
    2. 最后将进行的提交是常规(非合并)提交。

    启用rerere 将产生与任何其他git merge 相同的效果,因为记录的分辨率的重复使用以相同的方式发生。它对您的案件没有帮助,因为您已经在使用 -X theirs,它抢占了 rerere 可以解决的那种冲突。

    合并期间的冲突来自我所说的高级操作、整个文件树或低级合并工作。我使用这两个短语来区分 Git 合并引擎中的两个不同代码段。合并实际上是通过运行两个 git diff 操作来实现的:

    git diff --find-renames <base> <tip1>
    git diff --find-renames <base> <tip2>
    

    这些diff是git merge内部的,内置了不同的引擎,可以传递各种命令行难以实现的选项,但原理是一样的:

    1. 重命名查找查看添加和/或删除的文件,并尝试将左侧(合并基侧)“删除”文件与右侧“添加”文件进行匹配。如果是这样,Git 会确定此文件已重命名

    2. 像这样匹配文件名会产生身份映射:名为 FB 的基本文件具有新名称 FL 在左侧,FR 在右侧。所有三个名称可能相同,或者两个或所有三个名称可能不同,但无论哪种方式,这是“相同”的文件。它还为我们留下了在任一侧添加和/或删除的文件,以及在一侧或两侧可能会或可能不会修改的文件。

    3. 现在我们必须合并所有更改...但这首先发生在文件名和存在级别:

      • 如果左边删除了文件Fd,而右边不改,没关系。但是如果左边删除它而右边修改它,我们就有一个删除/修改冲突。 (如果右边删除它,左边修改它,我们有同样的冲突,相反。)

      • 如果左侧重命名文件而右侧将其删除(或与交换边相同),我们会发生重命名/删除冲突

      • 如果双方从头开始添加一个新文件但名称相同,我们就会发生添加/添加冲突

      • 如果双方都重命名基础文件FB,但是改成两个不同的名字*FLFR,我们有一个重命名/重命名冲突


      Git 自己没有解决这些冲突。这些是高级冲突。

      无论是否解决了任何高级树操作,我们现在都遇到了相同的文件已从基础传送到两个分支提示的情况 - 使用“相同文件”解释上述重命名 - 但已被双方修改双方。 Git 现在从名为 ll-merge.c 的单独文件中运行代码:低级合并代码。

      LLMerge 允许用户定义合并驱动程序。使用这些时,整个操作取决于合并驱动程序,它只获取所有三个输入文件的数据(基础、左/头和右/他们的)。使用内置合并驱动程序时,可以自动解决冲突,使用 -X 扩展选项:-X theirs 选择右侧更改,丢弃左侧(基-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,合并基础只是当时选择的提交的父级,因此使用此方法可能是可靠的。无论哪种方式,您都必须编写代码。

    【讨论】:

      猜你喜欢
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-31
      • 2011-10-07
      • 2018-05-15
      • 2017-07-14
      相关资源
      最近更新 更多