【问题标题】:git: merging a subtree from one branch to anothergit:将子树从一个分支合并到另一个分支
【发布时间】:2011-06-21 23:58:27
【问题描述】:

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

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

我的目录结构是这样的:

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

我想将 Branch B/Dir2/DirA 合并到 Branch A/Dir2/DirA。我希望合并 File1 和 File2,并且应该在分支 A 中创建 File3 和 File4。我不想选择 Dir3 或 Dir1 中的任何更改。

我已经尝试了 kernel.org 为 merging subtrees 概述的步骤,但是当我使用以下命令执行 git read-tree 时它们失败了:

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

我尝试使用托管在 github 上的 subtree script,但我运气不佳。当我这样做时:

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

我看到 Dir3 已合并的证据,但合并失败并出现冲突。

我可以挑选要合并的文件,但这对于本应是常见且直截了当的问题来说似乎是不必要的复杂化。

【问题讨论】:

  • 你想要子树的历史吗?它本身有意义吗?

标签: git branching-and-merging


【解决方案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 策略“我们的”)。这个“空”提交只是将另一个分支添加为第二个父分支,创建一个历史链接。如果这对您不重要,您可以跳过此步骤;后续步骤不需要。

    git merge Branch_B -s ours

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

  3. 将子树 Dir2/DirA 的内容从 Branch_B 复制到您的工作区,而不更改您的活动分支。

    git checkout Branch_B Dir2/DirA

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

    git commit --amend

第 3 步中checkout 的形式可能看起来不熟悉,但官方文档指出,习惯的分支切换行为实际上只是在使用这种形式时的一种方便:

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

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

【讨论】:

    【解决方案2】:

    你遇到的问题是 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 不会包含在 git 为您准备的树中,因为这些提交已经合并。

    【讨论】:

      【解决方案3】:

      合并子树实际上是指将外部项目的一部分合并到您的项目中。我会参考这篇博文来完成你想做的事情:http://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/

      【讨论】:

        【解决方案4】:

        我只需将 dirA 设为子模块并为其引入第三个 repo。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-21
          • 1970-01-01
          • 2010-12-15
          • 2017-08-04
          相关资源
          最近更新 更多