Squashing and renaming commits with git rebase

Squashing and renaming commits with git rebase

How to make use of interactive git rebases to squash, rename commits and more
Clean code
Date posted
Apr 24, 2022
Git has been a tool that I have constantly been using throughout my career and in my opinion is a skill that every developer should master. My personal preference for finding my way around things is using the CLI instead of an app that provides a GUI. In this blog post we’re going to get a bit more familiar with git rebase and see how we can use it to squash, reorder and rename commits.

Why even bother?

You might be wondering why do we even need to do that. When we open a Pull Request on Github, it will give us an option at the end to squash and merge. why would we need to do that manually? I also had the same question until recently a colleague pointed out to me how he personally looks at commits when reviewing code.
He gave me a few examples of why having a clean git history with messages grouped by domain helps a lot with reviewing. If we do that, we won’t have to squash and merge our PR which will give us more commits related to specific changes. If we identify an issue, that will make it easier to revert smaller pieces of code instead of a commit that refers to entire PR.
We want our commit history to tell a story of everything that happened to the codebase until that point. If you’re getting stressed when your commits looks like the following, then that blog post is for you.
notion image

Squashing commits

Let’s learn how we can squash commits. We can use the git rebase command which provides with plenty of options for rewriting history. First let’s run git log which will show us the following.
notion image
There are many things that are wrong here so let’s take things one step at a time. First one that I see is that we have 2 commits related to the readme file. Let’s squash them into one.
To do that, we would have to rebase to the commit before the commit we want to change. This is a bit confusing but with rebase if you want to modify a commit, you have to rebase to the one before it in terms of time. Git log shows us the commits ordered from the most recent to the oldest, so in this screen the commit we are looking for is the commit below the one we want to modify. That commit SHA isd7960486857147b1a9d0c2bdd67272f635681c7a. Let’s rebase interactively to that commit with the --interactive or -i flag.
git rebase -i d7960486857147b1a9d0c2bdd67272f635681c7a
Once we do that, the following window will pop up.
notion image
The commands in the comments give us an idea of things we can do with interactive rebases. Git rebase works top to bottom so if want to squash 2 commits, they have to be one after the other. In that case, we can replace the word pick on the second line with squash or s and save the file.
pick cd060b9 Add readme
squash b881366 update readme
pick 3185343 yada yada yada
pick 016af7a Setup repo (#1)
Once we do that another screen will appear with the new commit message of these 2 commits. We can rename our commits here but let’s see how we can do that later. Be aware that the default way these pages open is with vim, so to save and exit you have to type :wd 😆.
notion image
Now if we do git log our commit history will look like the following.
notion image
Our commit history looks cleaner already. Now let’s rename some commits.

Renaming commits

If you’re like me, the yada yada yada commit that is there must really annoy you. Let’s go and rename it. By opening it, it looks like it is a commit that initialised the package.json file. Same logic as before we need to interactively rebase to the commit prior to the one we want to modify.
git rebase -i 98eb28a3126de0d41711098d8b48babe848fbca1	
This time, in the rebase screen that opens we want to replace pick with reword or r. And save the page.
notion image
The next screen that appear is the commit message we want to change to. Let’s give it some more meaningful description and save the page.
notion image
Now our git history looks cleaner makes even more sense.
notion image

What if I mess up

No matter how sweet that sounds, git rebases are dangerous and you can easily mess up. When changing commit history please always do that in a new branch which then aims to get merged into main and remember to not push your changes until you are done.
If we follow these 2 simple rules and we still mess up we can go reset to our original stage of our branch if we pulled it from remote. Even better, if you have a brand new branch delete it and create a new one.
git reset --hard origin/HEAD
That command will reset everything you’ve done and is a good way to escape the mess caused by rebasing.

Combining multiple actions

Instead of doing all the above step by step we can make multiple changes all at once.
notion image
This will open multiple screens for each action but the result will be the same.

That’s it!

Git rebase does not sound that complicated anymore isn’t it? Even in cases where we mess up, we can easily just reset to our original state of the remote branch. Here’s a link to the repo prior to all these changes so feel free to practice what we mentioned in this blog post.
Squashing commits is a great practice to keep the git history clean so that in the future we can introduce conventional commits (future blog post spoiler alert).