git:将子树从一个分支合并到另一个分支

13

我在将开发分支的子树合并回集成分支时遇到了问题。

我有两个分支,一个用于开发,另一个用于集成。在开发分支上进行了大量开发工作,我想将其中的一部分合并回来。我要合并的特定部分都包含在开发分支的一个子树中。

我的目录结构如下:

[Branch A]              [Branch B]
    |                       |
    +--Dir1                 +--Dir1
    +--Dir2                 +--Dir2
        |                   |   |
        +--DirA             |   +--DirA
            |               |       |
            +--File1        |       +--File1
            +--File2        |       +--File2
                            |       +--File3
                            |       +--File4
                            +--Dir3

我希望将分支B/Dir2/DirA合并到分支A/Dir2/DirA中。我想要合并File1和File2,同时在分支A中创建File3和File4。我不想获取Dir3或Dir1中的任何更改。

我尝试了kernel.org上关于合并子树的步骤,但当我执行git read-tree时失败了:

error: Entry 'Dir1/DirA/File1' overlaps with 'Dir1/DirA/File1'.  Cannot bind.

我尝试使用托管在Github上的子树脚本,但是我并没有取得太多进展。当我执行以下操作时:

git checkout Branch_A
git subtree merge -P Dir2/DirA Branch_B

我发现Dir3已经合并,但是合并失败了,有冲突。
我可以挑选文件进行合并,但这看起来过于复杂,对于一个常见而直接的问题来说不应该如此。

你需要子树的历史记录吗?它本身是否有意义? - mabraham
4个回答

1
你想要的可能很简单:
git merge Branch_B -s ours  [OPTIONAL]
git checkout Branch_B Dir2/DirA

详情

此处的配方将从Branch_B复制一个子树到Branch_A,并(可选)在git项目历史中创建合并提交:

  1. 如果你还没有在Branch_A分支上,请切换到该分支。

    git checkout Branch_A

  2. (可选)建立一个合并提交,不更改工作区中的任何文件(merge策略为“ours”)。这个“空”提交只是将另一个分支添加为第二个父级,创建一个历史链接。如果这对你来说不重要,可以跳过此步骤;对于后续步骤而言,它不是必需的。

    git merge Branch_B -s ours

    注意:只在干净的工作区中执行此命令;如果有任何修改或暂存的文件,此命令可能会失败。

  3. 从Branch_B复制子树Dir2/DirA的内容到你的工作区,而不更改你当前所在的分支。

    git checkout Branch_B Dir2/DirA

  4. 将文件从Branch_B提交到Branch_A。如果省略了--amend,则会为此步骤创建一个新的提交;使用它将使新文件成为早期合并提交的一部分。

    git commit --amend

第三步中结帐的表单可能看起来不太熟悉,但官方文档指出,当未使用此表单时,通常的分支切换行为实际上只是一种方便:

如果没有给出路径,则git checkout还会更新HEAD以将指定的分支设置为当前分支。

因此,如果您提供了明确的路径,它将不会切换分支,而只是从该路径复制文件。


1
您所遇到的问题是git并不设计用于这种情况。考虑以下历史记录,可能导致您在问题中提到的两个分支AB:
C - D - E - F - G - H
 \
  H - I

分支A指向提交I,分支B指向提交H。现在你想将B中的一些更改合并到A中。

例如提交DF修改了Dir2EGHDir1Dir3进行了一些操作。因此,实际上,你只想将提交DF添加到你的集成分支A中。

这意味着分支B创建得不够仔细,你实际上想将其重新制作为(至少)两个干净的主题分支。类似于:

git checkout -b topic_I_want_to_merge_touching_Dir2 C
git cherry-pick D
git cherry-pick F
git checkout -b topic_I_dont_want_to_merge_now C
git cherry-pick E
git cherry-pick G
git cherry-pick H
git checkout B
git merge topic_I_want_to_merge_touching_Dir2

如果有提交同时涉及到 Dir1Dir2,那么这些提交是“坏的”,因为它们没有解决单个主题,而是同时做了几件事情。在这种情况下,您可能不仅需要重新安排提交,还需要使用 git-rebase -i 将提交更改为好的提交。

当然,您可以合并分支 A 并修复生成的树。但这将使得在 A 上继续工作的“未合并”更改几乎不可能,因为当您合并 A 的后代时,您将不得不再次修复生成的树,因为提交 EGH 已经被合并到树中。

0

-3

我会将dirA作为子模块,并引入第三个仓库。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接