将使用合并的git主题分支的修改历史更改为使用变基

6
我们的git开发工作流程是将主题分支不断地rebase到最新的master分支,直到它们被合并。
然而,一个新的开发人员创建了主题分支,在这些分支中,他已经进行了多次将master合并到主题分支以保持它们的最新状态。
    A---B---C---D---E topic
   /       /   /
  F---G---H---I master

尽管将此主题分支合并到主分支是完全正确的,但会导致非常混乱的历史记录。我想将这些主题分支转换为干净的线性重新基于历史记录,以便可以使用单个--no-ff合并提交干净地合并到主分支中,即:

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

理想情况下,应该存在一些git-fu可以让我进行rebase,并将主题分支上的提交保持不变,同时自动应用主题合并提交(例如C和D)中已经可用的合并冲突解决信息。
我知道我可以简单地应用“git diff master..topic”补丁,然后使用rebase向后工作并手动将单个补丁拆分为单独的提交,但是否有更简单、更优雅的方法?
我已经尝试了直接使用“git rebase”和“git rebase -p”命令,但没有成功。
2个回答

4
我发现以下过程似乎相当不错,虽然不是完美的。可能需要进行一些小的冲突解决--请参见下文。
  1. Ensure the topic branch is up-to-date with the latest master by doing a final merge from master, if not done already:

    git checkout topic
    git merge master
    
  2. Simplify the history of the topic branch by excluding merges:

    git log --no-merges
    
  3. From the above log, determine the branch point (the commit on master before the first topic branch commit, which should be commit F).

  4. Rebase the topic branch onto master, ignoring merges (which is the default, i.e. do not use the --preserve-merges / -p option), resolving any conflicts.

    git checkout master
    git rebase --onto HEAD F topic
    

    I found that during rebasing, often a conflict would result in which a file was in a conflicted "Both Modified" state, but it contained no conflict markers, so a simple git add and git rebase --continue was sufficient to resolve the conflict and continue. I believe git was using the previous resolution to resolve the conflicts.

    Also, in some more complex branches, multiple git rebase --onto HEAD ... commands will be required, or alternatively git cherry-pick can be used to pick out individual commits. Simply work through the log given in Step #2, rebasing ranges onto HEAD and/or potentially cherry-picking individual commits as necessary.

  5. The current HEAD should now represent the rebased topic branch. Verify that the result matches the original topic branch by checking that the diff results in no output:

    git diff topic..HEAD
    
  6. Name HEAD to the rebased topic branch name:

    git checkout -b rebased-topic
    

1
Raman的回答对我来说基本有效,但我想在第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,基本上获取在将master合并到topic的位置之间提交的范围。整个过程中,我一直处于分离头状态,所以如果你看到了这个,不用担心。有几次我遇到了合并冲突,但它们都是我预期会出现的合法冲突。
最后,我得到了一个看起来差不多的分支(Raman答案中的第6步),但由于某种原因我必须再次对主分支进行rebase才能移动提交。我不知道为什么我必须这样做,但它进行得很顺利。
我认为这样做基本上等同于cherry picking,所以可能更简单些。

嗯,你确定这真的是你想要的吗?在你的图表中,S、V和X似乎是合并提交,因此不应该出现为S'、V'和X'在你所期望的状态中。除非它们包含了大量手动冲突解决。 - Raman

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