A blog about programming topics in general, focusing on the Java programming language.

How to squash regular and merge commits

Introduction

Have you ever had to work on some feature branch that took quite a long time to develop? You would have had to get the latest updates from another branch, such as main from time to time.

Maybe for the first updates, just rebasing the main branch onto your feature branch was enough, given that there were not many changes in main yet. This would create a regular commit in your branch and once the development of your feature would be done, you could just squash all your commits to a single one and open a Pull Request to the main branch. Everything looks good, you live to see another day and love your job!

However, if the development takes more time, you might end up in a situation where rebasing main onto your feature branch turns out to be 20 step rebase with multiple files in each step.

As a developer, this is quite painful to deal with because every time you need to sync your branch with main you will spend a lot of time on this.

Fear no more! I will talk about my proposed workaround for this kind of situation:

How to squash regular commits

If you just have regular commits on your branch you can easily squash all of them down to one with the git rebase -i command

In this example, we can see how we have one commit “1” in main and three commits in feature-foo branch: “2“, “3” and "4“.

If we want to squash all commits in feature-foo branch, down to one we would just run the command

$ git rebase -i HEAD~3

that will enter the VIM editor (or the one that you have configured)

Changing pick to squash will (obviously) squash that commit into the next one

We will just have to edit the commit message and there we have our squashed commit

Pro tip: You can actually do this simple operation with your favorite git tool, such as IntelliJ Git window:

Just select all commits you want to squash and click on Squash Commits, edit the commit message and the result will be the very same.

How to squash merge commits

Imagine we have the following situation:

We have been working in the feature-foo branch but we were forced to regularly update it with main work. As a result, we now have several regular commits and 2 merge commits.

We still want to squash all the commits in the feature-foo branch in order to have a single commit before we merge our feature branch to main. However, we can no longer use the git rebase -i command due to the merge commits.

My workaround for this kind of scenario consists of a list of steps:

  • Create a temporal branch from main.
 $ git checkout -b temp main
  • Merge with the --squash flag
$ git merge --squash feature-foo
  • Commit the changes
$ git commit
  • (Optional) Edit the commit message that has just popped up.
  • Move to your feature branch ->
$ git checkout feature-foo
  • Hard reset to the temporary branch
    • TIP: If you wanna test this works before actually pushing to your branch, you can even create a temporary branch from your feature branch and do the git reset there.
$ git reset --hard temp
  • Push the changes
    • Note that we have to specify -f flag because of the hard reset
$ git push -f
  • Now you can remove the temporary branch
$ git branch -d temp

As you can see, our feature-foo branch now contains all the commits squashed into a single one, the 8 commit.

Additional tip: If you have been working on the feature branch for so long, the squashed commit will have the date of the first commit you pushed. That is to say, the one with the older date.

To fix this you can run the command

$ git commit --amend --date="now"

Do you use some other workaround for these situations? Let me know in the comments, I’ll be happy to check them out!

2 Comments

  1. Belen

    What’s the difference between merge and rebase?

    • andrestascon

      Hello Belen, I’ll make a blog post specifically about this topic. I’ll let you know once it is published 🙂