Simple Git Rebases


Learning to make appropriate use of git rebase can help you ensure your git commit log makes sense and is easy to follow. It is also important if you want to use commands like git bisect.

I recently had to make 47 commits in order to debug an issue. I could only test my changes inside a Heroku private space due to IP whitelisting. So commit after commit was pushed to Heroku, but I never pushed any of those commits to GitHub. Forcing a push to Heroku is necessary from time to time, but it is rarely permissible to do the same to GitHub or wherever your repository is stored.

Today I was able to go in and do an interactive rebase to take those 47 commits and combine them into a single commit with a nice log message and push that up to GitHub. One small thing I did that was very helpful was to consistently start the commit message for every one of those debugging commits with [DEBUG]. When I was rebasing I was able to clearly see where my debugging work started and didn’t have to worry about how I named my commits. Below I’ll take you through a simple example showing how I rebased things.

Let us suppose you had a situation like mine and were debugging issues on Heroku and had to keep pushing commits. You had better luck with your debugging and only made 10 commits, but you don’t really need everyone to see each step you went through in debugging.

To start with our commit log looks like this:

> git log --oneline
b481c12 (HEAD -> feature-cool-stuff, heroku/master) [DEBUG] Remove debugging code
b47a33f [DEBUG] Lock package2 version
fdf7e4f [DEBUG] Downgrade package2, Upgrade package1
c8a3a97 [DEBUG] Downgrade package1
ccdcda3 [DEBUG] Tweak even more
723e090 [DEBUG] Tweak complex function
23f4f6e [DEBUG] Moar logging!
39c00f8 [DEBUG] console.log not console.olg
749df59 [DEBUG] Add even more log output
2a16981 [DEBUG] Add console debugging statements
e2399fe (origin/feature-cool-stuff) Upgrade packages

Next we will run git rebase -i to begin an interactive rebase on our current branch. That will display this in an editor:

pick e2399fe Upgrade packages
pick 2a16981 [DEBUG] Add console debugging statements
pick 749df59 [DEBUG] Add even more log output
pick 39c00f8 [DEBUG] console.log not console.olg
pick 23f4f6e [DEBUG] Moar logging!
pick 723e090 [DEBUG] Tweak complex function
pick ccdcda3 [DEBUG] Tweak even more
pick c8a3a97 [DEBUG] Downgrade package1
pick fdf7e4f [DEBUG] Downgrade package2, Upgrade package1
pick b47a33f [DEBUG] Lock package2 version
pick b481c12 [DEBUG] Remove debugging code

# Rebase e2399fe.. b481c12 onto e2399fe (11 commands)
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
# These lines can be re-ordered; they are executed from top to bottom.
# If you remove a line here THAT COMMIT WILL BE LOST.
#   However, if you remove everything, the rebase will be aborted.
# Note that empty commits are commented out

The command for the first debug commit should be reword. All the rest should be changed to have the fixup command. This combines all the debug commits into one, ignoring their original commit messages, and allow me to set the end message.

pick e2399fe Upgrade packages
reword 2a16981 [DEBUG] Add console debugging statements
fixup 749df59 [DEBUG] Add even more log output
fixup 39c00f8 [DEBUG] console.log not console.olg
fixup 23f4f6e [DEBUG] Moar logging!
fixup 723e090 [DEBUG] Tweak complex function
fixup ccdcda3 [DEBUG] Tweak even more
fixup c8a3a97 [DEBUG] Downgrade package1
fixup fdf7e4f [DEBUG] Downgrade package2, Upgrade package1
fixup b47a33f [DEBUG] Lock package2 version
fixup b481c12 [DEBUG] Remove debugging code

After saving and exiting the editor I was presented with a commit message that I changed to reflect what the resulting commit actually contained. After saving and exiting that the rebase continued to execute until I was left with a much simpler commit log.

> git log --oneline
b4fac12 (HEAD -> feature-cool-stuff) Fix bugs caused by package upgrade
e2399fe (origin/feature-cool-stuff) Upgrade packages

Rebasing can be a dangerous task if you are careless or don’t understand what you are doing, but with a bit of time and knowledge, you can make use of this powerful feature.