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)
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)