03 May 2023
Saying goodbye to messy git history: Git Interactive Rebase
Hey, have you heard about Git interactive rebase? If you haven't, let's dive into it together. It's a true game-changer! You can use it to clean up your commit history and make it easier to understand at a glance. You also get more control over your commits, which means you can fix mistakes in your commit messages or break up big, complicated commits into smaller, bite-sized chunks.
It's like being a wizard who can shape the history however you want. Don't get me wrong, merging is cool and perfectly okay, but if you really want to take your Git history to the next level, you gotta try out Git interactive rebase.
What is rebasing, and how does it differ from traditional merging?
So, when you merge branches in Git, you take all the changes from one branch and apply them to another. This creates a new "merge commit" that combines the changes from both branches. The downside is that your commit history can get cluttered with a bunch of these merge commits, which can make it harder to follow the evolution of your code.
Rebasing, on the other hand, lets you apply the changes from one branch onto another, as if they had been developed in sequence. This makes it look like the changes were always part of that branch from the beginning. Rebasing is great for cleaning up your commit history, because it can help you avoid creating a bunch of unnecessary merge commits. Plus, it can make it easier to keep track of the changes in your code over time.
So, while merging can be useful for bringing changes together, rebasing can help you keep your commit history cleaner and more organized. Both have their place in the Git world, but if you want to make your commits more coherent and easier to understand, rebasing might just be your new best friend!
Interactive rebase: The hidden superweapon
Now that you have a concept of how traditional rebasing works, it's time to introduce a new champion into the arena: Interactive Rebase. Interactive rebasing allows selectively editing, reordering, combining, or deleting commits, providing more control over the Git history, while using the traditional rebasing under the hood to make it all possible.
The way it works is that it gets rid of the past commits and mimics them with the changes that you ordered when making new ones. And all while doing that, it rebases all the changes on the branch of your choosing. It's a perfect way to modify your own git history while staying up-to-date with the underlying base branch. Perfect!
Let's look at how a PR's commit history can look when using the merge strategy for keeping it up to date. Also, if we don't use interactive rebase, once a commit is pushed onto the remote, it's there - forever. There's no going back once it's whooshed up there.
There's a lot of commits, small one-liner fixes that I've found when developing other things, and merge commits that keep the branch up to date with the base branch. Yuck. While you can see how I proceeded with my work, the history is really cluttered and if all of those commits were pasted onto the master branch without squashing the commits, I bet it would confuse the soul out of my colleagues.
Now let's build a PR with Interactive rebasing in mind
I'll be using the Fork git client to better illustrate what I'm doing with the commits. Here's how I created the commits. This isn't something that I'd like my colleagues or clients to see! Let's interactively rebase this branch on “master”, to get the ability to edit our existing commits, while pulling the latest changes from master to stay up-to-date.
So, how do we make this mess look beautiful? Take a look at the dropdown menu with the green indicator and “Pick” word on it.
All of these options indicate a transformation for the commit that will happen during the rebasing process. If we were to rebase this branch straight-away, all of our commits will be “Picked”, meaning that nothing will change. Fork nicely explains how each of the actions transform the commit.
This is what we will do with this particular branch, to simplify things a little bit:
We used the “Fixup” action to meld our commits one-by-one into the first one. When that was done, we had only one commit, but with an out-of-date (and quite ugly) commit message. So we reworded it into a nicely formatted, simple commit message. Yay! Now we can push the branch and create a PR. This is how the commit history looks now:
It feels good to have absolute control over your commits, doesn't it? If you find something to fix in retrospect, you absolutely can do it properly and add the fixing change into the former commit.
If you want, you can have more commits in your PR's, for example one for your components, second for your type definitions, and a third for a helper function that you've just implemented. Or you can have it all at once in one bigger commit, that will be self-explanatory when merged onto the master branch. It's your call - you have all the freedom and tools to do it.
Handle with care!
As powerful as Git interactive rebase is, it's sadly not all-mighty. There's definitely some borders to stay in when you're going ham on your git history.
The most important thing to remember is that you can only edit your local commits.
You can feel free to do whatever you want with commits that aren't yet on the origin, but once they're pushed onto the origin, you should take great care when manipulating them. If you really need to overwrite git history that's already pushed on the origin, you'll have to pull the branch, overwrite your commits locally with the interactive rebase, and then do a force push back onto the branch.
Solely the fact that you have to force push is an exclamation mark by itself, but let me emphasise on this once again:
In this case you'll be overwriting history that someone else could've based their work on.
Be sure to double check with the rest of your team that it's ok to overwrite the section you're working on, and that it won't cause any headaches for someone.
Now that you know about Interactive rebasing and what it can do, there's nothing stopping you from making your git history clear and purposeful. Your mates will love to do code reviews on your branch because of the clarity, trust me on that. I was surprised how such a powerful feature is not so widely known among developers. It certainly changed my approach to commits, and I hope to have brought you fresh new information, so you can perhaps change yours.
Let’s stay connected
Do you want the latest and greatest from our blog straight to your inbox? Chuck us your email address and get informed.