变基功能时跳过已经合并的提交

Skip already merged commits when rebasing feature

考虑以下场景:

    F1---F2----M1----F3  (feature)
   /            /
  C1-----C2----C3  (main)

我想变基功能分支,所以它们显示为在 main 之后添加的提交,但还没有合并它。问题是, main 在过去已经合并(而不是重新定位),并且这些提交现在也在功能中。我希望 rebase 自动跳过 main 和 feature 中已经存在的提交。

这就是我想要的:

              F1---F2---F3  (feature)
             /
  C1---C2---C3  (main)

然后像这样与合并提交正常合并

              F1---F2---F3  (feature)
             /            \
  C1---C2---C3-------------M1---F1'---F2'---F3' (main)

这道题有点像,但是不想合并。只需变基然后强制推送分支本身。
Git rebase, skip merge-commits

编辑:
我发现情况要复杂得多。 考虑三个分支,feature1(F) feature2(G) 和 main(C)。 S 代表 squash,M 代表合并提交。

现状

main     C1--------------S1 
           \            /
feature1    F1---F2---F3
              \         \
feature2       G1---G2---M1---G3---G4

我想将 feature2 变基到 main 但跳过来自 feature1 的所有提交,因为它们已经在 main 中(作为壁球)并且也在 feature2 中(合并提交)

问题包含两个不同的场景;为了完整起见,我将同时解决这两个问题,但我将从最近添加的一个开始,因为我想这就是 OP 需要回答的问题。所以我们有这样一张图片:

C1 -- F123 <--(main)
  \
   F1---F2---F3 <--(feature1)
    \         \
     G1---G2---M1---G3---G4 <--(feature2)

我更改了符号以反映有关 git 工作原理的一些事情。

在 OP 的图表中,main 包含 S1,link 到 C1F3。从上下文中我了解到这是 F1..F3 的“挤压合并”。但是壁球合并并不是真正的合并;使它成为“壁球合并”的原因是它没有 link 回到 F3。所以我将它重命名为 F123 以显示它包含的内容,并删除了 link.

(此外,分支的这种表示法更好地显示了它们在 git 中的行为方式。)

所以问题是如何重新设置 feature2 并以

结束
C1 -- F123 <--(main)
  \
   F1 -- F2 -- F3 <--(feature1)
     \           \
      G1 -- G2 -- M1 -- G3 -- G4 <--(feature2)

现在 OP 说

I want to rebase feature2 onto main but skip all commits from feature1, since they are already in main (as a squash) and also in feature2 (merged commits)

所以这应该给我们类似的东西

           G1 -- G2 -- G3 -- G4 <--(feature2)
          /
C1 -- F123 <--(main)
  \
   F1 -- F2 -- F3 <--(feature1)

所以当我们 rebase 时,我们可以使用 --onto 将“上游”(用于定义我们重写的提交的边界)与新的基本提交分开。在这种情况下

git rebase --onto main feature1 feature2

这改变了 feature2 但使 feature1 成为上游;所以我们重写 feature2 中的提交,而不是 feature1 中的提交(基本上我们总是跳过合并提交本身),所以我们得到 G1G2G3, 和 G4.

但是 onto 说“即使 feature1 是上游,我想基于 main.

重写的提交

可能存在冲突,因为补丁不一定会干净地应用。


最初的问题(在我写这篇文章时仍然在上面显示)是一个更简单的案例

   F1 -- F2 -- M1 -- F3  (feature)
  /            /
C1 -- C2 -- C3  (main)

请注意,在这种情况下,rebase 将简单地执行预期的操作

git rebase main feature

(又可能有冲突。)

               F1 -- F2 -- F3  (feature)
              /
C1 -- C2 -- C3  (main)