21

假设我们有以下修订图:

A-X-Z--B
     \
      \-C

A 在 B 和 C 之前。进一步假设我从上游变基 A,创建一个新的提交 A*,然后将 B 和 C 变基到 A*。生成的修订图如下:

A*-X'-Z'-B
 \
  \-X"-Z"-C

请注意,共享历史不再共享。有没有一种简单的方法来解决这个问题,比方说,重新定位 B 然后明确地将 C 重新定位到 Z' 上。换句话说,是否有更好的方法可以同时自动重新设置多个分支以保留共享历史记录?不得不人为地在分割点放置一个标签,或者手动检查图表以找出提交的 sha1 以重新设置 C 以保留共享历史,这似乎有点尴尬,更不用说打开可能性了错误,特别是因为我每次变基时都必须这样做,直到我将更改检查到上游分支。

4

2 回答 2

18
git rebase --committer-date-is-author-date --preserve-merges --onto A* A C
git rebase --committer-date-is-author-date --preserve-merges --onto A* A B

这应该保留具有相同 sha1 和任何合并的常见提交。在这种情况下不需要保留合并,但会成为历史不那么重要的问题。

要对历史中包含 A 的所有分支执行此操作,请执行以下操作:

git branch --contains A | xargs -n 1 git rebase --committer-date-is-author-date --preserve-merges --onto A* A 

希望这可以帮助。

更新:

这可能是更简洁的语法:

for branch in $(git branch --contains A); do git rebase --committer-date-is-author-date --preserve-merges --onto A* A $branch; done
于 2011-04-12T06:53:06.080 回答
2

一般情况下的问题

我担心一个类似的问题:重新定位整个子历史——几个分支,它们之间的一些链接是由合并产生的:

A--B-B2-B3 <--topicB
\   /
 \-C-C2-C3 <--topicC

如果我顺序运行几个git rebase(对于 topicB 和 topicC),那么我怀疑分支之间的合并是否可以正确保留。所以我需要一次重新调整所有分支,希望能正确重建它们之间的合并。

在特定子案例中工作的“解决方案”

就我而言,我很幸运,topicC它实际上被合并到了topicB

A-B-----------B2-B3 <--topicB
   \         /
    \-C-C2-C3 <--topicC

所以要重新定义整个子历史,我可以运行

git rebase -p A topicB --onto A*

A*新的基础在哪里,而不是A,如您的问题中的那样;topicB是最初指向旧提交 B3 和B3'之后重写的提交的分支名称;-p是选项的简称--preserve-merges),获得如下历史记录:

A-B-----------B2-B3
   \         /
    \-C-C2-C3 <--topicC

A*-B'-------------B2'-B3' <--topicB
    \            /
     \-C'-C2'-C3'

然后将所有剩余的分支引用(和标签)重置为新的相应提交(在新的子历史中),例如

git branch -f topicC C3'

有效:

A*-B'-------------B2'-B3' <--topicB
    \            /
     \-C'-C2'-C3' <--topicC

(移动分支引用和标签也许可以通过脚本来完成。)

受特定案例启发的一般案例的“解决方案”

如果topicC没有合并到topicB,我可以创建一个假的顶级提交来合并我想要重新设置的所有分支,例如:

git checkout -b fake topicB
git merge -s ours topicC

然后以这种方式重新设置它:

git rebase -p A fake --onto A*

并将主题分支重置为新提交,删除假分支。

其他答案

我相信另一个答案也是好的--committer-date-is-author-date和明智的,但是根据我使用 Git 的经验,我没有这个想法并解决了在我在附加答案中描述的方式重新设置基础后保持共享历史真正共享的问题这里。

于 2012-03-14T17:00:01.213 回答