In Git I can use an interactive rebase to re-write history, this is great because in my feature branch I made a ton of commits with partially working code as I explored differen
It is indeed possible to squash a commit into the following commit during interactive rebase, and fully preserve the identity of the second of those commits (including author, date etc.).
The method is somewhat involved however, so native support by git rebase -i
would still be appreciated nevertheless.
I'll demonstrate with just three commits aaaaaaa A
, bbbbbbb B
and ccccccc C
, where we want to fold A
into B
and preserve B
's identity: (The method easily generalises to more commits)
git rebase -i aaaaaaa^
B
and exit the editor:
pick aaaaaaa A
edit bbbbbbb B
pick ccccccc C
B
, revert the latest commit twice, then continue:
git revert HEAD
git revert HEAD
git rebase --continue
Because reverting the revert restores the previous state, all following commits will apply cleanly.
The sequence of B
and Revert "B"
together has no effect, but the first of those commits carries the full identity of commit B (in fact, at this stage it still is commit B
). B
and Revert "B"
could be squashed together to form a no-op commit carrying the identity of commit B forward with a separate rebase -i --keep-empty aaaaaaa^
. However we'll skip that step and just keep the commits together. Revert "Revert "B""
which will carry all the changes originally made by B
.rebase -i aaaaaaa^
again to move A
past both B
and Revert "B"
, while squashing B
into both Revert "B"
and A
:
pick bbbbbbb B
squash b111111 Revert "B"
squash a222222 A
squash b333333 Revert "Revert "B""
pick c444444 C
Because the sequence of B
and Revert "B"
has no effect, you can move any commits past it while creating only trivially resolvable merge conflicts.git mergetool
with a tool that can automatically resolve trivial conflicts, and let the tools do just that.git rebase --continue
and you are done.