Interactive rebase is a one-stop shop for revising history: combining, removing and reordering commits. It’s one of those things where you learn it, and afterward wonder how you got by without knowing it. I use it almost every day when preparing a topic branch for review. If I have to make changes during review, I commit them as incremental patches, then squash them with an interactive rebase before I commit.
In this post, I’ll explain a bit about how it works. Let’s forget about topic branches right now, and just assume you’re working directly on the master.
Say you’ve been working a bit, and you have a recent history that looks like this (most recent to oldest):
masterFix a bug when you foo the bar
origin/master(Ancient history that’s in the upstream repo)
We’ve added five commits here, so we want to run the following command:
git rebase -i HEAD~5
(If we were using a topic branch, we could do
git rebase -i master — this also has the effect of rebasing the topic branch if the master has been updated)
This will open up your editor, with something that looks like this:
pick 39a2bef Implement part of feature XYZ pick 4bc987e Oops, forgot to add this file pick f9282bc Implement the remainder of feature XYZ pick 2c5dd33 Fix typo pick a524b5c Fix a bug when you foo the bar
On each line, you have the command (“pick” here), the commit ID, and the description. At the bottom of the file, you’ll see a list of commands you can use:
pick— leave the commit as-is
reword— change the commit summary only (this is a recent addition)
edit— change the commit contents, much like doing a git reset –mixed
squash— keep the changes in this commit, but merge it with the commit on the previous line, and append the commit messages and allow the message to be edited.
fixup— keep the changes, as with squash but throw away the log message.
You can also delete a line to discard a commit entirely, or reorder them. The idea is that you edit this file so it shows the history you wish you created, then write the file and close your editor. Let’s change it so it looks like this:
pick 39a2bef Implement part of feature XYZ fixup 4bc987e Oops, forgot to add this file pick f9282bc Implement the remainder of feature XYZ fixup 2c5dd33 Fix typo fixup a524b5c Fix a bug when you foo the bar
I’ve just changed “
pick” to “
fixup” for all the mistake commits I made. This will roll them in with the commits above them so that, when we close the editor, git will re-write your history so it looks like this:
Mistakes? What mistakes? :)
As I said, I use this almost daily to prepare a patch set for review. After I rebase, I’d prepare patch emails with
git format-patch -2 --attach, then send them with
git send-email 000* --firstname.lastname@example.org.
Hope that helps you out. Rewriting history like this is a key feature of git that I haven’t seen in other source control systems, and it goes a long way towards making your project history look professional.