5

假设我们有以下修订图:

A-B (master)
   \
    C (feature-a)
     \
      D (feature-b) [depends on feature a]
       \
        E (feature-c) [depends on feature b]

然后修改 master 以跟随 commit F是否有任何简单的方法可以重新定位EF(master) 上,以便分支feature-afeature-b最终feature-c结果如下:

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

?

在现实世界的情况下,每个特性之间显然有多个补丁,因此手动重新连接中间的分支以重新设置历史记录是乏味且容易出错的工作。我知道我可以用一个简单的方式变基E,但这会留下分支并指向提交,而不是and 。Rebase 应该拥有移动所有分支的所有信息,对吧?E'git checkout feature-c && git rebase masterfeature-afeature-bCDC'D'

4

4 回答 4

2

git 没有内置任何东西来执行此操作,但它肯定是可编写脚本的。

你需要做的是:

  • 确定要重新定位的分支(此处feature-a为 、feature-bfeature-c)。
  • 对于每个分支,确定哪些要重新设置的分支“包含”它们(我们称其为“前身”)。分支XYifY的后代的前身X(并在此处选择一些东西来处理/中断关系 - 具有标识相同提交的两个分支名称)。在这种情况下,feature-a是两者的前身feature-bfeature-c而是(仅)feature-b的前身。feature-c保存前辈的“后退距离”值(追逐父链的距离)。
  • 进行拓扑排序。(实际上你可以作弊然后找到叶子。如果你通过某种方法选择分支名称,而不是观察提交 DAG,你只需要循环检查。)
  • 对于每个叶子(在这种情况下只是feature-c):
    • 重新设置它。
    • 对于这片叶子的每个前身,将它从现在的任何地方移动到新叶子尖端的 N-parents-back。

(就是这样,一切都完成了。)

git merge-base --is-ancestor使用(pairwise) 或(en mass)进行前驱测试很容易git branch --contains,但需要过滤掉未重新设置的分支。找到“N back”值有点棘手,但我相信可以使用git rev-listpiped to来完成wc -l,例如。

编辑:我看到链接的答案(在上面的评论中)使用了类似的算法——包括拓扑排序/周期性检查,因为分支选择方法不是“从提交 DAG 中获取”——但需要更多的工作,明确地重新设置每个按照指示进行分支。如果您从 DAG 工作,叶子变基已经完成了所有工作,并且前辈可以简单地重新标记,正如我所指出的。

于 2013-11-08T14:12:19.683 回答
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)
于 2013-11-08T14:46:20.007 回答
0

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

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

但是,每当您遇到这样的问题时,请再想一想,如果您真的想要这样做并了解后果。

于 2013-11-08T16:01:18.893 回答
0

应该很简单。重新定位EF使用提交CD.

git checkout B
…
git commit -m 'F'
git checkout E
git rebase F
于 2015-01-29T09:33:53.273 回答