6

我们的 git 开发工作流程是主题分支不断地重新基于最新的 master 直到它们被合并。

然而,一位新开发人员创建了主题分支,他在其中多次将 master 合并到他的主题分支中,以使它们保持最新。

    A---B---C---D---E topic
   /       /   /
  F---G---H---I master

虽然将这个主题分支合并到 master 是完全正确的,但它会导致一个非常混乱的历史。我想将这些主题分支转换为一个干净的线性 rebased 历史,它可以通过一个--no-ff合并提交干净地合并到 master 中,即:

                A'---B'---E' topic
               /
  F---G---H---I master

理想情况下,会有一些 git-fu 允许我进行变基,按原样接受主题分支上的提交,同时自动应用主题合并提交中已经可用的合并冲突解决信息,例如 C 和 D。

我知道我可以简单地应用“git diff master..topic”的补丁,然后使用 rebase 向后工作并手动将单个补丁拆分为单独的提交,但是有没有更简单和更优雅的方法?

我已经尝试过直接git rebasegit rebase -p命令,但没有运气。

4

2 回答 2

4

我发现以下过程似乎运行良好,尽管并不完美。可能需要一些小的冲突解决方案——见下文。

  1. 如果尚未完成,请通过从 master 进行最终合并,确保主题分支与最新的 master 是最新的:

    git checkout topic
    git merge master
    
  2. 通过排除合并来简化主题分支的历史:

    git log --no-merges
    
  3. 从上面的日志中,确定分支点(第一个主题分支commit之前在master上的commit,应该是commit F)。

  4. 将主题分支重新定位master 上,忽略合并(这是默认设置,即不使用--preserve-merges/-p选项),解决任何冲突。

    git checkout master
    git rebase --onto HEAD F topic
    

    我发现在 rebase 期间,通常会发生冲突,导致文件处于冲突的“Both Modified”状态,但它不包含冲突标记,因此简单git addgit rebase --continue足以解决冲突并继续。我相信 git 正在使用以前的解决方案来解决冲突。

    此外,在一些更复杂的分支中,git rebase --onto HEAD ...将需要多个命令,或者git cherry-pick可用于挑选单个提交。只需通过步骤 #2 中给出的日志,将范围重新定位到 HEAD 和/或根据需要可能会挑选个别提交。

  5. 当前的 HEAD 现在应该代表重新定位的主题分支。通过检查 diff 是否没有输出来验证结果是否与原始主题分支匹配:

    git diff topic..HEAD
    
  6. 将 HEAD 命名为重新定位的主题分支名称:

    git checkout -b rebased-topic
    
于 2012-06-20T06:53:57.300 回答
1

拉曼的回答对我来说非常有用,但我想我会在第 4 步周围添加更多细节,这对我来说很棘手......

我有一个更复杂的回购,就像这样

        Q-R-S-T-U-V-W-X
       /   /     /   /
A-B-C-D-E-F-G-H-I-J-K

我想要这个:

                      Q'-R'-S'-T'-U'-V'-W'-X'
                     /
A-B-C-D-E-F-G-H-I-J-K

什么工作git rebase --onto HEAD Q R,然后,所以基本上抓住了我合并到git rebase --onto HEAD S U的地方之间的提交范围。在我这样做的整个过程中,我都处于超然状态,所以如果你看到这一点,请不要担心。有几次我遇到合并冲突,但它们都是我希望看到的合法冲突。mastertopic

最后,我有一个看起来正确的分支(拉曼回答中的第 6 步),但由于某种原因,我不得不再次重新定位到 master 以实际移动提交。我不知道为什么我必须这样做,但它进行得很顺利。

我认为这样做基本上相当于摘樱桃,所以这样做可能更简单。

于 2015-04-08T23:24:36.327 回答