Git rebase并保留所有子分支

12

我正在尝试将一个CVS存储库导入到git中。不幸的是,我们一直使用一种非常古老的方法从我们的CVS repo创建发布版本,这并不涉及任何实际的CVS分支或标记,但将该信息保存在单独的系统中。因此,几乎所有的开发都发生在CVS主干上。所以,一个文件可能在历史早期被添加,但在6个月后才成为发布的一部分。

我想做的是将这个CVS repo导入git,并使用rebase将这些提交移动到开发分支中。虽然我确实有一些来自CVS的分支,但我真的想移动所有分支。

假设我有这样一个结构:

                  F---G---H topic
                 /
A---B---C---D---E---I---J master

B是我想要移动到它自己的分支的提交。我希望结果看起来像这样:

                F`---G`---H` topic
               /
A---C`---D`---E`---I`---J` master
 \
  B some_unfinished_feature

但是仅在master上进行变基会产生以下结果:

git checkout -b some_unfinished_feature B
git rebase --onto A B master

A---C`---D`---E`---I`---J` master
 \
  \               F---G---H topic
   \             /
    B---C---D---E
     \-some_unfinished_feature

在一个rebase命令中,我能否让git将topic变基到E'?我可能有很多分支需要移动到相应的新提交上。或者我是否可以获得EE'之间的映射关系?


你想要按时间顺序遍历整个主干,手动选择当前提交应该“汲取”到哪个主题分支(如果有的话),还是只想查找要移动到分支的提交。 换句话说,移动提交有多常见? 如果很常见,filter-branch可能是有意义的,否则最好自动化汲取过程。 我编写了一个名为ggrbm(“Git Rebase Multiple”)的实用程序,可以帮助解决这个问题,但可能需要进一步开发。 - Adam Spiers
4个回答

2
               F---G---H topic
              /
 A---B---C---D---E---I---J master

 git checkout B
 git branch BRANCH-B
 git checkout master
 git rebase -i  HEAD~6

(删除提交 B)

 git rebase --onto D' D topic

这应该可以做到,假设没有冲突 ;)

1
在你的问题中,你想要从C提交开始移动。基于A的分支留作为B
首先,我们应该给它一个名称:
git branch -b some_unfinished_feature <B-ish>

这个命令将从<B-ish>提交开始创建some_unfinished_feature分支。 <C-ish>是上游。您可以查看所有将被变基的提交:
git log <C-ish>..topic

你可以注意到,IJ不会被rebase,因为它们在不同的分支中。你应该稍后单独rebase它们。
现在将你的topic<C-ish>开始rebase到<A-ish>
git rebase -p --onto <A-ish> <C-ish> topic

-p 标志将保留从 <C-ish>topic 的任何合并。

当此命令完成时,您将获得:

       some_unfinished_feature
     /
A---B---C---D---E---I---J master
  \
   C`---D`---E`
              \   
                F`---G`---H` topic

现在你应该将master变基到从<I-ish><E-ish>
git rebase -p --onto <E-ish> <I-ish> master

Voila:
A---B some_unfinished_feature
  \
   C`---D`---E`--I`---J` master
              \   
                F`---G`---H` topic

0

移动 topic 的命令将是:

git rebase --onto E' E topic

不幸的是,没有办法自动完成大量不同分支的此操作,这是有意为之的。每次变基都可能引入必须手动解决的冲突。

或者,您可以使用git filter-branch与您的配置管理软件一起编写脚本以实现所需更改,但这可能需要大量工作。可能更明智的做法是将master保留为开发分支,并使用filter-branch创建发布分支,而不是相反。


我怎么知道 E' 是什么?在变基完成后,EE' 之间没有任何联系。我如何让 Git 告诉我旧的提交 SHA1 和变基后的提交 SHA1 之间的映射关系? - Chris
匹配日志消息,我想。在将master变基之前,您可以创建一个“旧主”以便同时查看两个版本。 - Karl Bielefeldt
这看起来最多也只是脆弱的。完全有可能有两个提交具有相同的日志消息。我猜我可以使用git rev-list获取old-mastermaster上的修订列表,因为提交数量和提交顺序应该是相同的...但那是很多工作。 - Chris
要从E到E'构建地图,请使用git filter-branch,并使提交过滤器记录旧的和新的SHA1。(无论如何,这都不会很漂亮....) - torek

0
首先,给出一个建议:在变基时,请使用临时分支进行操作:
git branch wip_topic
git checkout wip_topic

一旦您成功地进行了变基(并检查它是否有效...),您可以将原始头移动到工作提交:

git checkout topic
git reset --hard wip_topic
git branch -d wip_topic

(如果你没有这样做,而发生了一些不好的事情,git reflog仍然可以拯救你的情况...)


在进行rebase操作时,Git会跳过那些提交的文本差异与目标分支上已有提交相匹配的提交。

如果你的master rebase操作没有引入太多冲突,应用:

git rebase --onto A B wip_topic

这应该会给你想要的结果。

通常情况下,大多数冲突将出现在重新基于提交列表“开头”附近(<-- 不要过于依赖此规则)。假设在构建提交 C' 时存在冲突,但之后没有冲突,您可以重新基于 C..topic 部分:

git rebase --onto C' C wip_topic

不管怎样:试一下,看看 git 的黑魔法是什么。

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