【问题标题】:When git rebasing two branches with some shared history, is there an easy way to have the common history remain common?当 git rebase 两个具有一些共享历史的分支时,有没有一种简单的方法可以让共同的历史保持通用?
【发布时间】:2011-04-11 22:20:36
【问题描述】:

假设我们有以下修订图:

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 以保留共享历史,这似乎有点尴尬,更不用说打开可能性了错误,特别是因为我每次变基时都必须这样做,直到我将更改检查到上游分支。

【问题讨论】:

标签: git git-rebase


【解决方案1】:
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

【讨论】:

  • 你用的是什么版本的git?
  • 酷,不知道 --contains。然而,同样的问题发生了,奇怪的是git branch --contains A在for循环中使用时除了分支之外还打印文件,而不是在其他地方。
  • 查看手册页以了解变基。也许有一个不应该出现的连字符,或者存在拼写错误。
  • 有一天我必须坐下来了解这一切。与此同时,这是一场噩梦。
  • 对我来说,如果存在--preserve-merges--committer-date-is-author-date 无效。我测试了 2.6.3 和 2.7.2 版本。
【解决方案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

(移动分支引用和标签也许可以完成with a script。)

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

如果topicC 没有合并到topicB 中,我可以创建一个虚假的顶级提交来合并所有我想变基的分支,例如:

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

然后以这种方式变基:

git rebase -p A fake --onto A*

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

其他答案

我相信 the other answer--committer-date-is-author-date 也是好的和明智的,但是根据我使用 Git 的经验,我没有这个想法并解决了在变基后保持共享历史真正共享的问题,我的方式已在我的附加答案中进行了描述。

【讨论】:

  • 我听不懂你的回答。您说 topicC 已经合并到 topicB 中,但图表显示并非如此。另外,你为什么还要在 rebase 之后保留一个已经合并的分支头?
  • @kynan:这只是一般问题的一个特定子案例,其中工作解决方案更简单。然后这个案例激发了更通用解决方案的想法(所有内容的虚假合并)。
  • @kynan: 至于保留一个已经合并的分支——分支有它们的意图,例如,一个是为上游提交准备的简单错误修复,另一个(包含的)是一个全新的实验性功能的实现(但取决于错误修复)。如果它们还没有被上游拉动,我想在 rebase 之后保留它们(这是为了上游的清洁和清晰)。
  • 看了this answer that explains git's “rebase --preserve-merges”中的例子后,这个答案变得更容易理解了。
  • @sampablokuper 我现在已经以更明确的方式编写了我的答案的第一部分,以便更准确地复制(由读者)。至于第二部分,我不知道为什么我省略了--preserve-merges;恐怕,这只是因为我的回答仓促而粗略。我应该解决这个问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
  • 2010-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多