如何通过多个步骤按目录进行分支合并目录



我们的 Git 源存储库有多个模块。每个模块驻留在不同的目录中。每个模块都有一个专门的开发人员.
例如

src
|--module A --
|--module B --
|--module C --

现在我们有 2 个分支。假设工作分支是"开发",其他分支是"其他"(最不活跃的分支)。我们想将"其他"合并为"发展"。是否可以明智地执行此目录?

例如,我现在只想合并"模块 B"。然后对合并的代码进行新的更改并提交"开发"。然后一段时间后(比如 2-3 个月),不同的开发人员需要将模块 A 和 C 从"其他"合并到"开发"。

即简单地说,是否可以通过子目录将 Git 合并分解为多个步骤?

请注意,"其他"分支有大量提交。因此,识别导致"模块 B"更改的所有提交并逐个挑选是不可行的。


到目前为止我能想到的答案是

  1. 启动另一个 -> 开发合并
  2. 仅在"模块 B"中解决合并冲突。将"模块 B"目录备份到其他位置。
  3. 丢弃 #1 开始合并。
  4. 在开发上创建一个新分支 ->删除"模块 B"目录 ->将上面 #2 支持的"模块 B"复制到此分支 ->提交 ->合并以开发分支 ->继续我在"模块 B"中的新更改

缺点是,
将来完成"其他->开发"合并时,"模块B"仍然会有合并冲突。这些冲突将不得不被忽略(即必须在 git gui 中使用"使用本地文件"选项)。然后,在"模块 B"的"其他"分支中所做的任何新更改都必须手动挑选/复制。

简短的回答是否定的。 但这个答案是(a)不令人满意,(b)遗漏了你能做些什么来实现你的最终目标。

我认为这最好通过制作一些图纸来说明。 让我们简化你的问题,以Git看待它们的方式展示事物,逐个提交。 我们从一些提交序列结束时的一些常见提交开始:

...--F--G--H   <-- main

我们现在创建一些分支(暂时完全停止使用名称main),在这些侧分支上,我们进行一些提交:

I--...--J   <-- branch1
/
...--G--H

K--...--L   <-- branch2

这里可能有很多关于两个非main分支的提交,即使我们只显示两个。

当你合并这些时,Git实现合并结果的方式是这样的:

Git 提取H的快照,
  • 然后提取J的快照,并将两者进行比较以查看branch1上发生了什么变化。
  • Git 提取H的快照,
  • 然后提取L的快照,并将两者进行比较以查看branch2上发生了什么变化。

在您的情况下,这是...很多变化。:-) 它太多了,你不想全部处理它们。但是,Git坚持处理所有这些问题。 如果你遇到冲突,git merge会在工作中间停下来并退出并迫使你解决所有冲突。 不管你怎么做,一旦你完成了,Git 就会相信生成的文件是正确的合并结果

要在解决所有问题后完成合并,请运行git merge --continuegit commit。 这使得一个新的合并提交M

I--...--J
/         
...--G--H           M
         /
K--...--L

提交M,像每次提交一样,具有所有文件的完整快照。根据定义,这是此合并的正确结果。这就是为什么简短的回答是否定的。

现在开始诀窍

但是——这就是为什么简单的"否"答案是不完整的——你会注意到我在上面省略了所有分支名称。 假设,在开始合并之前,我们创建一个新的分支名称,并将其作为我们当前的分支名称,如下所示:

I--...--J   <-- branch1, merge-A (HEAD)
/
...--G--H

K--...--L   <-- branch2

当我们完成合并时,我们将得到这个:

I--...--J   <-- branch1
/         
...--G--H           M   <-- merge-A (HEAD)
         /
K--...--L   <-- branch2

请注意,没有更改任何现有提交,只有名称merge-A已更改,以指向新的合并提交M

这意味着您现在可以使用所有三个分支继续工作,无论您喜欢什么程度。 然后,在第二天(或周或月),您可以返回到branch1并创建另一个新名称,例如merge-B,并将其设置为当前分支:

I--...--J   <-- branch1, merge-B (HEAD)
/
...--G--H

K--...--L   <-- branch2

(这假设branch1branch2没有移动。 如果它们已经移动,那么找到提交JL的哈希ID并在此处使用它们可能是明智的。 请注意,它们可以作为合并提交的两个父级找到M它仍然存在- 我只是选择暂时停止绘制它

我们现在运行相同类型的git merge,进行提交MBM2,其中我们实际上只解析模块 B 文件。 就Git而言,这是此合并的正确结果,即模块 A 和模块 C 文件都正确合并(无论我们在MB快照中卡在它们中的内容)。我们必须记住模块 A 和 C 是错误合并的,就像我们制作M时一样,我们必须记住模块 B 和 C 被错误合并。 但无论如何,我们都会得到这个结果:

I--...--J   <-- branch1
/         
...--G--H           MB   <-- merge-B (HEAD)
         /
K--...--L   <-- branch2

MB是一个新的提交,与M分开(如果我们想开始这样称呼它,则MA)。

稍后,我们可以重复此操作以进行MC合并。

如果我们试图将它们全部吸引进来,它会变得非常混乱:

...--J____
|   
|    MA
|   /
|   X
 / 
X   MB
/  /
|   X
|  / 
| /   MC
|/___/
...--K

(显然,这使用图形绘制工具会更好)。

您现在可以自由地从三个MAMBMC提交中提取特定文件,并将它们组合起来生成一些新的合并提交。 具体如何做到这一点取决于你自己。 您在记录此内容的新提交方面所做的确切内容取决于您。 我自己可能会只使用父JL进行新的合并提交 - 即第四次合并,其方式与这三个合并中的每一个相同,但通过提取三个合并结果来构建其快照。

请注意,这不是"免费">

如果在合并三个单独的MAMBMC后继续开发,您仍然会坚持在MA后、MB后和MC后提交中进行合并。 这需要再次运行git merge并获得更多合并冲突。 在MAMBMC中记录非常明确的合并消息可能非常重要,甚至可能在随后的一些提交中,以提醒您自己和/或其他人将来仍有工作要做。 然后,当您对合并所有三个模块进行"正确"合并时,您需要执行额外的合并工作,也许将 post-MA、post-MB和 post-MC提交的分支提示提交记录为这些不同合并的第二次提交。

最终的图表将非常纠结和混乱。 这在这里是不可避免的。 使用章鱼合并,就最终结果而言,章鱼的许多腿中的每一条腿都可能具有相同的"地位"或"优先级",但这也是一种令人困惑的工作方式。 Git 的内置-s octopus策略(这是 Git 通常进行章鱼合并的方式)是否可以处理这个问题是值得怀疑的;如果不能,您可以使用git commit-tree手动进行这些合并提交,或者仅使用常规的一次合并两次来构建最终结果。

这种章鱼合并的好处(如果有的话)不是很大。 这是一张手工ASCII绘图,在三个M合并的基础上构建:

...--J____
|   
|    MA
|   /  
|   X    
 /     
X   MB--MM   <-- main
/  /    /
|   X    /
|  /   /
| /   MC
|/___/
...--K

但请注意,自从三个单独的M合并以来,没有发生任何工作。 在完成了MM(所有模块的主合并)之后,现在是时候处理这项工作了。

最新更新