I have the following repo:
A--B--C--D--E--F--G--H--I--J
\
K--L--M
main -> J
DEV -> M
I want to squash the commits between B and E so the repo looks like this:
A--N--F--G--H--I--J
\
K--L--M
main -> J
DEV -> M
I tried to do some interactive squash but the best i got was something like this:
N--F'-G'-H'-I'-J'
/
A--B--C--D--E--F--G--H--I--J
\
K--L--M
remote/main -> J
main -> J'
DEV -> M
so the DEV branch its not atached where it supossed to be.
What is the way to do that?
You can use an interactive --rebase-merges
after having a throw-away merge commit at the top:
We construct this history:
A--B--C--D--E--F--G--H--I--J--X <-- main
\ /
K--L----M <-- DEV
using
git checkout main
git merge --strategy ours DEV # constructs X
The merge result (X
) is irrelevant as we are going throw it away anyway. Using merge strategy ours
guarantees that the merge command succeeds.
Now you can do an interactive rebase:
git rebase -i --rebase-merges --update-refs -- A
In the "todo" script, specify the squash of B
to E
and also delete the merge command in the last line as shown here:
label onto
# Branch DEV
reset onto
pick b844192 B
squash b844193 C
squash b844194 D
squash b844195 E
pick b844196 F
pick b844197 G
label branch-point
pick bb393a5 K
pick c213a54 L
pick b844198 M
update-ref refs/heads/DEV
label DEV
reset branch-point # G
pick b918c51 H
pick b918c52 I
pick b918c53 J
# merge -C 9e9d655 DEV # Merge branch 'DEV' into main
--updated-refs
ensures that branch DEV
is reseated on top of the rewritten side branch. You need Git version 2.38 for this. If yours is older, leave away the option and reseat the branch label manually.
BTW, the script that git rebase
prepares rebuilds commits B
to G
on the "side" branch DEV
. This must not surprise you: the commits are on that branch.