Git Interactive Rebase: How I Clean Up Messy Commit History Before Going to Production

Git tutorial - IT technology blog
Git tutorial - IT technology blog

The 2 AM Nightmare and Meaningless Commit Lines

Have you ever looked back at your git log and felt… embarrassed? It’s 2 AM, eyes glued to the terminal, getting ready to merge an important feature into the main branch. Typing git log --oneline, I suddenly stop. Before me is a complete mess:

a7b2c3d fix typo
9e8f7g6 update
5h4i3j2 fix bug
1k2l3m4 fix bug again
0n9o8p7 I swear it works this time
6q5r4s3 add payment logic

Leaving this mess as a Pull Request (PR) would definitely get me “roasted” by the Lead tomorrow morning. Who leaves 4 commits just to fix a single typo? It makes the Git history look incredibly unprofessional. Later, if you need to use git bisect to trace a bug, this pile of “junk” commits will be a major obstacle. This is exactly where Git interactive rebase comes in as a lifesaver.

What exactly is Git interactive rebase?

Basically, git rebase is the process of placing your commits on top of a new base. When adding the -i (interactive) flag, Git opens an editor interface. Here, you have the power to directly intervene in each past commit.

This tool allows you to perform powerful actions such as:

  • Squash: Combine 10 small, scattered commits into a single large one.
  • Reword: Edit messages like “asdfgh” into something meaningful.
  • Drop: Completely remove commits containing messy test code.
  • Reorder: Change the order of commits for better logic.

It’s like editing a movie. You cut out unnecessary scenes and rearrange segments so the viewer can understand it most easily. If you’re unsure whether to use rebase or merge in the first place, check out Git Rebase vs Merge: Don’t Let Your Commit History Look Like a Mess of Wires.

Practice: Starting the Cleanup

First, determine how many commits back you want to go. Suppose I need to clean up the last 5 commits:

git rebase -i HEAD~5

Immediately, Git will open your default editor (Vim or Nano) with the list of commits. One thing to note: the order here is the reverse of git log. The oldest commit is at the top, and the newest is at the bottom.

pick 6q5r4s3 add payment logic
pick 0n9o8p7 I swear it works this time
pick 1k2l3m4 fix bug again
pick 5h4i3j2 fix bug
pick 9e8f7g6 update
pick a7b2c3d fix typo

1. Squashing Commits (Squash & Fixup)

This is the feature I use most. Instead of leaving 4 separate bug-fix commits, I’ll squash them into the main commit. Change the word pick to f (fixup) for the child commits. fixup will discard that commit’s message and merge the content into the previous commit.

pick 6q5r4s3 add payment logic
f 0n9o8p7 I swear it works this time
f 1k2l3m4 fix bug again
f 5h4i3j2 fix bug
f 9e8f7g6 update
f a7b2c3d fix typo

2. Editing Messages (Reword)

Accidentally named a commit “fix bug” but want to change it to “Fix: Handle memory leak during image upload”? Change pick to reword (or r). After saving the file, Git will open another window for you to enter a more proper message.

3. Deleting Commits (Drop)

If you see a commit containing test code or personal config files, change pick to drop (or d). You can also simply delete that line in the rebase file. That commit will disappear as if it never existed.

Resolving Conflicts and Finishing Up

After editing, save the file and exit (:wq in Vim). If everything goes smoothly, you’ll see a success message. However, reality is often messier. Sometimes you’ll encounter conflicts.

Don’t panic. Git will pause for you to fix the code. Once fixed, simply type:

git add .
git rebase --continue

If you feel like everything is getting out of hand, use the “escape” command to return to the previous state:

git rebase --abort

A Hard-Learned Lesson: Never Mess Around with Force Push

Once the rebase is done locally, your commit history is completely different from the remote server. At this point, a normal git push will be rejected. You are forced to use --force.

I once lost an entire morning’s work because I force pushed to the wrong branch. Instead of pushing to my personal branch, I accidentally typed the team’s develop branch. The result was overwriting the code of 3 other colleagues. I had to sweat it out using git reflog for 2 hours to recover everything.

My advice: Use --force-with-lease. It checks if anyone else has pushed code to the remote while you were rebasing. If so, it will block the push so you don’t overwrite someone else’s work.

git push origin feature/payment --force-with-lease

When Should You Avoid Interactive Rebase?

While extremely powerful, there is one golden rule: Never rebase commits that have already been pushed to a shared branch.

Rebasing essentially creates new commit IDs. If you change the history of the main branch, your colleagues will have a nightmare dealing with it when they git pull. Only use it on your personal branch before creating a Merge Request. A solid Git workflow for individuals and small teams will help you establish clear boundaries around which branches are safe to rebase.

Conclusion

Git interactive rebase is how you show professionalism to your code reviewers. A clean commit history helps the team quickly understand what you did and why. Future code maintenance will also be much smoother because of it.

Next time, before pushing code to production, take 5 minutes to tidy up. And if you want to automate quality checks so messy commits never slip through in the first place, explore Git Hooks to automate your workflow. Trust me, your colleagues will thank you!

Share: