Git Rebase:跳过合并提交

27

开始使用

    hack---F1----M1----F2  (feature)
   /            /
  C1-----C2----C3  (master)

我希望最终得到

    hack---F1----M1----F2  (feature)
   /            /
  C1-----C2----C3---F1'---F2'  (master)

到目前为止,我拥有的最好的是

git checkout feature  
git checkout -b temp  
git rebase -i --onto master hack temp
   * Big drawback: manually remove the merged-in C2 and C3 from list of commits *
git checkout master  
git merge temp  
git branch -d temp  

我希望即使这是一个可疑的工作流程,也有人可以回答。


1
在这里,你需要执行 git checkout master,然后执行 git cherry-pick F1git cherry-pick F2 - jub0bs
1
是的,在这种情况下,使用两个提交的 Cherry-pick 是不错的选择,但如果有多个提交,我更喜欢另一种方式。也许可以使用“Cherry-pick range”(https://dev59.com/ImUo5IYBdhLWcg3w5Syl#15688940),并带有某种排除选项? - Grastveit
我正在尝试弄清楚您在一般情况下实际想要做什么...您能否将您想要做的事情表述为master分支上,挑选hack(不包括)和feature分支顶端(包括)之间的所有非合并提交 - jub0bs
2个回答

26

简单情况

如果您的代码库状态为

  hack---F1----M1----F2 [feature]
 /            /
C1-----C2----C3 [master]

而且你想要到达

  hack---F1----M1----F2 [feature]
 /            /
C1-----C2----C3----F1'----F2' [HEAD=master]

你应该使用git cherry-pick,而不是git rebase -i(这里没有必要使用交互式rebase):

git checkout master
git cherry-pick <commit-ID-of-F1> <commit-ID-of-F2>

一般情况

如果我理解得不对,请指出。我理解你所说的一般情况为:

master上,将hack(不包括)和feature的最新提交(包括)之间的所有非合并提交进行手动挑选。

接下来,我假设这确实是你的意思。

正如你在评论中指出的那样,上述方法随着需要手动挑选的提交数目增加而变得不太优雅:

  hack---F1---F2--- .... --- F68--M1---F67---...---F99 [feature]
 /                               /
C1-------------C2---------------C3 [master]

不过,您可以使用git rev-list命令自动生成感兴趣的修订版本列表,方法如下:

git rev-list --reverse --no-merges --first-parent <commit-ID-of-hack>..feature

编辑:你还需要使用--first-parent标志来避免收集像C1C2这样的提交,并使用--reverse标志,以使提交按所需顺序被挑选出来。

您可以将该命令的输出传递给git cherry-pick

git checkout master
git cherry-pick `git rev-list --reverse --no-merges --first-parent <commit-ID-of-hack>..feature`

这将产生

  hack---F1---F2--- .... --- F68--M1---F67---...---F99 [feature]
 /                               /
C1-------------C2---------------C3---F1'---F2'---...---F99' [HEAD=master]

谢谢!这正是一般情况。但我遇到了问题。在F2处,rev-list命令列出了F2、C2、C1和F1的ID。即使我尝试使用cherry-pick,但不幸的是,在F2上发生冲突后它停止了。如果我在问题中忽略了某些细节,我将在github上的测试库中放置。 - Grastveit
@Grastveit 你说得对,我的修订范围有问题。让我想一想... - jub0bs
@Grastveit 请看我的编辑:如果你使用 --first-parent 标志,它应该可以工作。 - jub0bs
2
太好了,这就解决了问题。我还添加了--reverse以便将rev-list按照时间顺序排列。使用标记为“hack”的hack命令在主分支上运行的命令变成了:git cherry-pick `git rev-list --no-merges --first-parent --reverse hack..feature` - Grastveit
@Grastveit 你说得对。我会在我的答案中加入那个标记。 - jub0bs

2

从您最初的工作流程来看,似乎您想要忽略合并操作,唯一的问题是使用交互式变基的-i选项会保留合并操作。

git checkout -b temp  
git rebase --onto master hack temp
   * Big drawback is gone!
git checkout master  
git merge temp  
git branch -d temp

应该完全按照您的要求工作。不过,这可能并不能完全解决您的“一般情况”。


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