TSDrake
TSDrake

Reputation: 191

Git squash commits in middle of branch with child branches after that

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?

Upvotes: 8

Views: 234

Answers (1)

j6t
j6t

Reputation: 13377

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.

Upvotes: 6

Related Questions