0

Consider the following scenario:

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

I want to rebase the feature branch, so they appear as commits added after main, but not merge it yet. The problem is, main was already merged (not rebased) in the past and those commits are now in feature too. I want the rebase to automatically skip the commits already present in main and feature.

This is what I want:

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

And afterwards just merge normally with a merge commit like so

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

It's a bit like in this question, but I don't want to merge. Just rebase and then force push in the branch itself.
Git rebase, skip merge-commits

EDIT:
I found out that the scenario is way more complex. Consider three branches, feature1(F) feature2(G) and main(C). S stands for squash, M for merge commit.

Current situation

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

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)

uloco
  • 2,283
  • 4
  • 22
  • 37
  • I think the problem here is more, that the commits were squash merged from a different feature2 into main and not merged normally. – uloco Feb 19 '21 at 14:13
  • I don't understand your comment about squash merges. If the pictures in your question are accurate, then you're describing the default behavior of `rebase` (`git rebase main feature`). If main contains the result of squash merging `C1` through `C3` (rather than *actually* `C1 through C3`) then the pictures need to be clarified so we know what we're trying to solve. – Mark Adelsberger Feb 19 '21 at 14:51
  • I didn't know, rebase would automatically skip the already merged changes (throug a normal merge without rebase). But after thinking about it, I have understood that the changes made to main (that are also in feature) have been squash merged into it from another third branch. Does this make more sense? I will update the diagrams – uloco Feb 19 '21 at 14:57
  • Hope the new diagrams make it more clear... – uloco Feb 19 '21 at 15:11
  • That explains it; thanks. Answer to follow shortly – Mark Adelsberger Feb 19 '21 at 15:34

1 Answers1

0

The question contains tow different scenarios; for completeness I'll address both, but I'll start with the more recently added one, since I guess that's the one OP needs answered. So we have a picture like this:

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

I've changed the notation to reflect some things about how git works.

In OP's diagram, main contained S1, with links to C1 and F3. From context I understand that to be a "squash merge" of F1..F3. But a squash merge is not really a merge; what makes it a "squash merge" is that it has no link back to F3. So I've renamed it F123 to show what it contains, and removed the link.

(Also this notation for branches better shows how they behave in git.)

So the question would be how to rebaes feature2 and end with

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

And now OP says

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)

So that should give us something like

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

So when we rebase, we can use --onto to separate the "upstream" (the boundary used to define what commits we rewrite) from the new base commit. In this case

git rebase --onto main feature1 feature2

This rebases feature2 but makes feature1 the upstream; so we rewrite commits in feature2 but not in feature1 (and basically we always skip the merge commits themselves), so that gives us G1, G2, G3, and G4.

But onto says "even though feature1 is the upstream, I want to base the rewritten commits from main.

There may be conflicts since the patches are not necessarily going to apply cleanly.


The original question (still shown above as of the time I'm writing this) was a simpler case

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

Note that in this case, rebase will simply do what's intended

git rebase main feature

(Again there may be conflicts.)

               F1 -- F2 -- F3  (feature)
              /
C1 -- C2 -- C3  (main)
Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • What do I do if the feature1 branch no longer exists? – uloco Feb 19 '21 at 15:53
  • 1
    @uloco Then you need some other expression that refers to commit `F3`. That could be the commit ID ("hash") for `F3`. Or in the example it could be `feature2~2^2` (the 2nd parent of the merge commit found 2 commits before the head of `feature2`) – Mark Adelsberger Feb 19 '21 at 16:03