我们的Git存储库中有一个相当复杂的情况。我们有两个团队在使用同一个软件。一个团队正在对3.0版本进行维护,而另一个团队正在进行一个长期运行的项目,这将导致3.1版本很快就会发布。
3.1团队开始在他们自己的分支上,他们决定合并3.0分支的所有更改,每次从3.0分支发布新版本时,通常每隔一周发布一次。因此,当3.0团队重新发布他们的第一个版本时,提交了R1并将其合并到3.1中,从而产生了M1。
3.1---o---o---M1
/ /
3.0---o---o---R1
两周后,3.0团队在R2发布了他们的第二个版本,而3.1团队将其合并,从而产生了M2。
3.1---o---o---M1---o---o---M2
/ / /
3.0---o---o---R1---o---o---R2
这已经持续了一段时间,但最终3.0团队进行了重构,并在提交R3中发布了这个。在这次重构中,3.0团队将一个大型Constants.java
文件拆分为两个较小的文件:Constants.java
和MoreConstants.java
。 (这些不是实际的文件名。)Constants.java
文件先前已被两个团队更改并成功合并。然而,当他们尝试将R3合并到他们的分支中时,这种重构导致了3.1团队的冲突。 3.1团队决定他们并不想解决这个冲突,他们认为他们可以推迟#34;无视重构,坚持自己的版本解决问题。这不仅意味着他们没有将MoreConstants.java
添加到他们的存储库,而且他们也没有合并现在导入MoreConstants.java
而不是Constants.java
的文件中的更改}。他们做的是:
$ git merge 3.0
$ git status
然后,对于每个列出的冲突,他们决定是否要解决它。如果他们不想解决冲突,他们确实
$ git checkout --ours <file they wanted to ignore>
$ git add <file they wanted to ignore>
这导致在3.1分支上提交C3:
3.1---o---o---M1---o---o---M2---o---o---C3
/ / / /
3.0---o---o---R1---o---o---R2---o---o---R3
从那时起,他们每次都在做着#--ours
&#34; -trick,因为他们每次都希望忽略冲突。同样重要的是要注意3.1团队不断对Constants.java
- 文件进行更改。所以随着时间的推移,情况就变成了这样:
3.1---o---o---M1---o---o---M2---o---o---C3---o---o---C4---o---o---C5
/ / / / / /
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5
现在两个分支都有Constants.java
的不同版本,有一个共享祖先,这是在R2之前的某个地方的提交。此时,我们可以通过运行
$ git merge-base --all C5 R5
现在是复杂的部分。 3.1团队即将完成创建3.1版本的产品。 3.0团队将接管。 3.1发布后,3.0团队将立即发布3.2。因此,3.0分支创建了一个新的3.2分支:
3.1---o---o---M1---o---o---M2---o---o---C3---o---o---C4---o---o---C5
/ / / / / /
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5
\
3.2 A5
当然,版本3.2需要包含3.0和3.1的所有更改。所以我们做了合并:
$ git checkout 3.2
$ git merge 3.1
导致:
3.1---o---o---M1---o---o---M2---o---x3--C3---o---o---C4---o---o---C5
/ / / / / / \
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5 \
\ \
3.2 A5---A6
现在令人讨厌的惊喜:3.0团队在A6提交中缺少大量修复。事实证明,所有缺失的东西都可能与Constants.java
- 重构有关。当然,3.2中缺少新的MoreConstants.java
,但3.2分支上缺少导入新MoreConstants.java
的文件的大量更改。
在阅读How to revert a merge which used strategy=ours?和How to revert a faulty merge(特别是ADDENDUM)后,我想我明白为什么会这样:3.1团队通过选择&#34;我们的&#34;解决了很多冲突。 。这样,事实上他们告诉Git,3.0中的冲突变化是错误的&#34;。因此,正如上述文件中所提到的那样,这实际上是某种形式的恢复合并。不是整个合并都被还原,而只是它的一部分。
这两个文件都包含很多关于如何解决这个问题的线索。但是,两者都专注于修复一个错误合并。在这个简化的示例中,我们讨论的是三个错误合并。实际上,我猜,我们有15到20个错误的合并。
我知道3.1团队不应该忽略冲突,但他们确实如此。所以我们必须找到一个解决方案。到目前为止我唯一能想到的是:
我们可以在3.1行上挑选每一个提交到3.2行,除了合并的提交。听起来很简单,但是由于我们在现实中有大约20个错误的合并和,合并之间的提交比简化图中显示的要多得多,我们正在讨论数百个提交的提交。手动执行此操作非常繁琐且容易出错。我认为这个解决方案只有在生成所有提交列表的方法才能生效,并自动将该列表提供给(系列)git命令。
一系列连续的rebase
。鉴于错误合并的数量,这仍然容易出错且乏味,但可能比之前的建议少一点。在专业方面,这可能会导致更清晰的历史。我认为这个过程如下:
$ git checkout x3
$ git rebase --no-ff 3.0
3.1---o---o---M1---o---o---M2---o---x3--C3---o---o---C4---o---o---C5
/ / / / / / \
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5 \
\ \ \
\ 3.2 A5---A6
\
3.1'--o--o--M1'--o--o--M2'---o---x3'
$ git merge R3
3.1---o---o---M1---o---o---M2---o---x3--C3---o---x4--C4---o---o---C5
/ / / / / / \
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5 \
\ \ \ \
\ \ 3.2 A5---A6
\ \
3.1'--o--o--M1'--o--o--M2'---o---x3'---D3
$ git checkout x4
$ git rebase --no-ff R3
3.1---o---o---M1---o---o---M2---o---x3--C3---o---x4--C4---o---o---C5
/ / / / / / \
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5 \
\ \ \ \ \
\ \ C3'--o--x4' 3.2 A5---A6
\ \
3.1'--o--o--M1'--o--o--M2'---o---x3'---D3
$ git merge D3
3.1---o---o---M1---o---o---M2---o---x3--C3---o---x4--C4---o---x5--C5
/ / / / / / \
3.0---o---o---R1---o---o---R2---o---o---R3---o---o---R4---o---o---R5 \
\ \ \ \ \
\ \ C3'--o--x4'--D4 3.2 A5---A6
\ \ /
3.1'--o--o--M1'--o--o--M2'---o---x3'---D3----------o
Etcetera ......
第三种解决方案可能是生成&#34;补丁&#34;,仅包含某些提交之间的更改。当我们再一次想象树时:
3.1---o---o---M1---o---o---M2--y2--o--x3--C3--y3--o--x4--C4--y4--o--x5--C5
/ / / / / /
3.0---o---o---R1---o---o---R2--o---o--o---R3--o---o---o--R4--o---o---o--R5
\
3.2 A5
这意味着创建包含以下&#34;范围&#34;:
中所做的所有更改的修补程序[y2 - x3]
,[y3 - x4]
和[y4 - x5]
。然后,我们可以在A5之上应用这些补丁,而不是进行合并。
所以这些是我的问题:
答案 0 :(得分:1)
我们可以在3.1行上挑选每一个提交到3.2行,除了合并的提交。 ...我认为这个解决方案只有在生成所有提交列表的方法才有可行,以便自动将该列表提供给(系列)git命令。
您可以将一系列提交传递给cherry-pick
,例如git cherry-pick 16234..351be
,您还可以指定-m 1
仅跟随第一个父项,这允许您通过合并提交正确传递,因此您不需要跳过它们。当你在每一步解决合并冲突时,它们应该在未来解决,所以希望你只是在每个冲突步骤中遇到常规的合并冲突,事情将更加自动化并且不易出错。