Search code examples
gitgit-rebase

Git rebase: Combine non-subsequent commits


by now, I know that there is a nice way how to combine commits and change the commit message by using 'git rebase --interactive'

Having the following situation:

$ git rebase --interactive HEAD^^^^
pick 5b7c140 commitA
pick 40ffd7c commitB
pick 5e7647d commitC
pick 78bea2d commitD

Rebase [...]

Is there also a possibility to handle the following requirements:

Combining commitA and commitC and commitB and commitD to new commits cAC and cBD?


Solution

  • It is possible - you can also rearrange the order of the commits with interactive rebase:

    pick 5b7c140 commitA
    squash 5e7647d commitC
    pick 40ffd7c commitB
    squash 78bea2d commitD
    

    or

    pick 5b7c140 commitA
    fixup 5e7647d commitC
    pick 40ffd7c commitB
    fixup 78bea2d commitD
    

    The difference between the two is that squash allows you to edit the commit message for the new commits, whereas fixup just throws away the second commit message leaving the preceeding pick commit message in place for the combined commit. (If your editor launches quickly enough, then having the habit of just choosing squash gives you a nice opportunity to review the commit message even if you think you would probably not need to use parts of the message of the fixup commit.)

    Reordering the commits brings the possibility of conflicts during the rebase; in the example this would happen if commitB and commitC changed a same part of a file. This in mind, I often do this kind of rebase in two steps by first just reordering the commits to deal with the conflicts (in the example pick A, C, B, D) and then doing the commit combinations (squash, fixup). I find the conflict management becomes easier this way, especially if I am interrupted in the middle of doing this.