当 git rebase 两个具有共享历史记录的分支时,有没有一种简单的方法可以让共同历史保持共同?

发布于 2024-10-31 19:36:39 字数 433 浏览 1 评论 0原文

假设我们有以下修订图:

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

Suppose we have the following revision graph:

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

with A preceding both B and C. Further suppose I rebase A from upstream, creating a new commit A*, and then rebase both B and C onto A*. The resulting revision graph is the following:

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

Note that the shared history is no longer shared. Is there a simple way to fix this, other than, say, rebasing B and then rebasing C onto Z' explicitly. In other words is there a better way to automatically rebase multiple branches at the same time in order to preserve shared history? It just seems a little bit awkward to have to either artificially place a tag at the split point, or manually inspect the graph to find out sha1 of the commit on which to rebase C to keep the shared history, not to mention opening up the possibility of mistakes, especially since I have to do this every time I rebase until I check the changes into the upstream branch.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

饮惑 2024-11-07 19:36:39
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 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

This should keep the common commits having the same sha1 and any merges preserved. Preserve merges is not required in this case, but will become an issue with a less trivial history.

To do this for all branches that contain A in their history do:

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

Hope this helps.

UPDATE:

This may be cleaner syntax:

for branch in $(git branch --contains A); do git rebase --committer-date-is-author-date --preserve-merges --onto A* A $branch; done
往昔成烟 2024-11-07 19:36:39

一般情况下的问题

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

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* 是新的基础,而不是您问题中的 AtopicB 是最初指向旧提交 B3 和之后重写的提交 B3'--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 的经验,我没有这个想法,并解决了在 rebase 后保持共享历史记录真正共享的问题,就像我在此处的附加答案中描述的那样。

The problem in the general case

I was concerned with a similar problem: rebasing a whole subhistory -- several branches, with some links between them resulting from merge:

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

If I run several git rebase sequentially (for topicB and topicC), then I doubt the merges between the branches can be preserved correctly. So I would need to rebase all the branches at once, hoping that would reconstruct the merges between them correctly.

A "solution" that worked in a specific subcase

In my case, I had luck that topicC was actually merged into topicB:

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

so to rebase the whole subhistory, I could just run

git rebase -p A topicB --onto A*

(where A* is the new base, instead of A, as in your question; topicB is the branch name that would initially point to the old commit B3 and to the rewritten commit B3' afterwards; -p is a short name for --preserve-merges option), obtaining a history like:

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

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

and then reset all remaining branch refs (and tags) to the new corresponding commits (in the new subhistory), e.g.

git branch -f topicC C3'

It worked:

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

(Moving the branch refs and tags could perhaps be done with a script.)

A "solution" for the general case inspired by that specific one

If topicC was not merged into topicB, I could create a fake top commit to merge all the branches I want to rebase, e.g.:

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

and then rebase it that way:

git rebase -p A fake --onto A*

and reset the topic branches to the new commits, delete the fake branch.

Other answers

I believe that the other answer with --committer-date-is-author-date is also good and sensible, but in my experience with Git, I hadn't had that idea and solved the problem of keeping the shared history really shared after a rebase the way I have described in my additional answer here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文