如何将一系列分支进行变基?

7
假设我们有以下修订图:
A-B (master)
   \
    C (feature-a)
     \
      D (feature-b) [depends on feature a]
       \
        E (feature-c) [depends on feature b]

然后主分支被修改以跟随提交F有没有简单的方法将E重新基于F(主分支),以使分支 feature-a feature-b feature-c 最终如下:

A-B-F (master)
     \
      C' (feature-a)
       \
        D' (feature-b)
         \
          E' (feature-c)

在现实世界中,每个功能之间显然有多个补丁,因此在重新基于历史记录的情况下手动重新连接分支是一项繁琐且容易出错的工作。我知道我可以使用简单的 git checkout feature-c && git rebase masterE 重新基于 E',但这会使分支 feature-afeature-b 指向提交 CD 而不是 C'D'。重新基于应该具有移动所有分支所需的所有信息,对吗?


1
看看这个问题,我认为问题很相似:https://dev59.com/WG035IYBdhLWcg3wJccv?rq=1 - Rudy Bunel
4个回答

2
Git本身没有这个功能,但是可以通过脚本实现。
需要执行以下步骤:
1. 确定要rebase的分支(这里是feature-a、feature-b和feature-c)。 2. 对于每个分支,确定包含它们的“前继”分支(如果Y是X的子孙,则称X是Y的前继)。在这种情况下,feature-a是feature-b和feature-c的前继,而feature-b仅是feature-c的前继。保存前继的“距离后退”值(追溯父级链的距离)。 3. 进行拓扑排序。(实际上,你可以作弊,只需找到叶子节点。如果你选择的分支名称不是从提交DAG中观察到的,则只需要进行循环检查。) 4. 对于每个叶子节点(在这种情况下只有feature-c): - 对其进行rebase。 - 对于该叶子节点的每个前继,将其从当前位置移动到新叶子节点末端N个父级之前。
前继测试可以使用git merge-base --is-ancestor(成对)或git branch --contains(批量,但需要过滤掉未rebase的分支)轻松完成。找到“N back”值有点棘手,但我相信可以使用git rev-list管道传输到wc -l等方法来完成。
编辑:我看到上面的链接答案使用了类似的算法——包括拓扑排序/循环性检查,因为分支选择方法不是“从提交DAG中获取”。但是如果你从DAG中工作,叶子rebase已经完成了所有工作,前继可以简单地重新标记,如我所说。

我想你是指的答案是 https://dev59.com/WG035IYBdhLWcg3wJccv#5600770 吧?那个脚本比我原本希望的要复杂得多。 - Mikko Rantalainen
是的,但该脚本可以(并且应该能够)重新定位最初无关的树节。例如,即使“experimental”分支基于提交“K”,该提交在向后跟随后最终加入提交“A”的“master”上,它也可以将分支“experimental”重新定位到“feature-b”的顶部。您在问题中提出的方案要简单得多:“保持现有关系不变”,而不是“创建全新的关系”。 - torek
@torek 感谢您精确而美妙的解释。我想尝试实现一个脚本来使用您版本的算法(不进行每个前任的额外重定位工作),但是我有一个可能会破坏您算法的更多情况,我需要您的意见。请见:http://i.imgur.com/xU5G0le.png - Ankur
@Ankur:啊,我明白了。对于这种情况,有两个需要重新定位的“分支”。可以使用git filter-branch一次完成,但这可能更加困难(尽管在您的图表中的情况下,它实际上应该更容易,因为您只是在许多分支中到达一个单独的提交上插入一个新的父提交)。 - torek

1
尝试这个:

git checkout featurea
git rebase
git branch --contains (sha1 of your old commit C) |xargs -n 1 git rebase --onto (sha1 of your new commit C') (sha1 of your old commit C)

这非常接近。不幸的是,这需要定位feature-a的SHA-1,而当前的HEAD通常指向feature-c,我知道我想要整个集合重新基于新的master。有什么建议可以找到最接近master的分支名称以自动编写脚本吗?(也就是说,在这种情况下,当给出feature-cmaster时,我需要feature-a作为答案。) - Mikko Rantalainen

0

我目前能想到的最好方法是一个接一个地进行变基:

git rebase --onto master B feature-a
git rebase --onto feature-a C feature-b
git rebase --onto feature-b D feature-c

但是每当你遇到这样的问题时,请再次考虑一下,你是否真的想要这个,并理解后果。


0

这应该很简单。将EF上进行变基将会包含提交CD的整个分支。

git checkout B
…
git commit -m 'F'
git checkout E
git rebase F

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