如何将两个(或更多)完全不相关的线性分支祖先"splice"为一个新的?



我正在尝试将两个分支组合成一个新的空分支,每个分支具有不同的根提交。这不是通常的合并,因为我不想只在最后一次提交中合并分支(在这种情况下,新分支将有一个合并提交,并且"下面"仍然是两个单独的历史记录。新分支仍将有两个根提交。

在我的场景中,一个重要的事实是这两个分支完全不相关。任何一个分支的提交都不会影响其他分支提交的路径 => 不会有冲突。

让我们假设以下分支:

A---B-----C-D
  X---Y-Z

这就是我正在寻找的:

A-X-B-Y-Z-C-D

重点是我想按时间顺序提交。如何实现?

你写道:

在我的场景中,一个重要的事实是这两个分支完全不相关。任何一个分支的提交都不会影响其他分支提交的补丁 => 不会有冲突。

当然,如果您预计会出现许多冲突,那么您建议的"拼接"操作可能是一个坏主意。让我们假设,确实不会发生任何坏事。

如果在开始时,您的存储库如下所示

A---B------C--D [branch1]
  X---Y--Z [branch2]

您可以按照下面概述的过程自动将两个分支的提交"拼接"到单个分支中,同时保持时间顺序。

"拼接"两个不相关的分支

  1. 确保您处于干净的工作状态;然后签出branch1并将branch2合并到其中:

    git checkout branch1
    git merge branch2
    

    这将产生

    A---B------C--D---E [HEAD=branch1]
                     /
      X---Y--Z------- [branch2]
    

    现在,我知道这不是你想要的,但请耐心等待我一秒钟。我们将使用合并提交E来立即访问"双方的祖先"。

  2. 签出branch2并将其重置为提交A

    git checkout branch2
    git reset --hard A
    

    您将处于以下情况:

    A [HEAD=branch2]
     
      ---B------C--D---E [branch1]
                      /
       X---Y--Z------- 
    
  3. 生成一个列表(按时间顺序(,列出可从branch1访问但不能从branch2访问的所有非合并提交:

    git rev-list --no-merges --reverse branch2..branch1
    

    这应该产生以下提交列表:XBYZCD;在步骤 1 中创建的提交E将不会在该列表中,因为我们使用了 --no-merges 标志。

  4. branch2 (A( 之上挑选这些提交。

    git cherry-pick `git rev-list --no-merges --reverse branch2..branch1`
    

    然后,您的存储库将如下所示:

    A--X'--B'--Y'--Z'--C'--D' [HEAD=branch2]
     
      ---B-----C-D---E [branch1]
                    /
       X---Y-Z------ 
    
  5. 删除branch1

    git branch -D branch1
    

    编辑:正如您正确指出的,由于branch1没有完全合并到当前分支(branch2(,因此仅使用-d在这里是行不通的;您需要改用-D标志。

    然后,您的回购将简单地

    A--X'--B'--Y'--Z'--C'--D' [HEAD=branch2]
    
  6. (可选(重命名branch2

    git branch -m branch2 <more_meaningful_name>
    

泛化到两个以上的分支

假设你有 n 个完全不相关的分支:branch1branch2、...、branchn ,其中 branch1 对应于根提交是整个仓库中最早提交的分支;让我们称该提交为A

A ----- o ---- o [branch1]
   o ----- o ---- o -- o [branch2]
...
 o ----- o - o [branchn]

如果您不知道哪个提交A,您可以通过运行来识别它

git rev-list --reverse --max-parents=0 --all

A 的提交 ID 将是该命令输出中列出的第一个。您可以通过运行以下命令来识别branch1哪个分支:

git branch -r --contains `git rev-list --reverse --max-parents=0 --all | head -1`

然后,两个分支案例中的程序概述变为:

  1. 通过将除branch1以外的所有分支合并到branch1中,创建一个可以访问所有分支祖先的提交。

  2. (与双分支案例相同(

  3. (与双分支案例相同(
  4. (与双分支案例相同(
  5. 删除除 branch2 以外的所有分支。
  6. (与双分支案例相同(

快速简单的合并解决方案是,

假设 A---B-----C-D(是分支 1(和 X---Y-Z(是分支 2(。从分支 2 (git format-patch -n( 获取所有补丁,然后将所有补丁应用到分支 1 (git am *.patch( 之上,然后在您希望序列使用 git rebase -i HEAD~n 的位置进行洗牌

希望对您有所帮助!

最新更新