HOWTO: Safely use “git rebase -i”

Git is a very powerful revision control system used in software development, and at this point, is effectively the industry standard. One of the things that makes Git so powerful is that there are all sorts of low-level operations that developers can do in it. This includes everything from tagging releases, to having an insane number of branches, to painless merging of said branches, to rewriting history.

“I am serious. And don’t call my Shirley.”

If you’re new to Git, your brain probably threw an exception when reaching the end of the paragraph as you thought to yourself, “Wait WHAT? Why would you want to REWRITE HISTORY?” Good question! Normally, you don’t want to mess history in a revision control system. But sometimes you may want to or even need to. A few possible reasons for rewriting history include:

  • Feature Branch “B” is a branch of Feature Branch “A” and you want to merge B’s changes to master, but not A’s.
  • Squashing all the commits in a feature branch to a single commit, after having previously pushed those commits.
  • A developer made a commit with something that doesn’t belong in Git, such as PII or credentials.
  • You want to “clean up” the commit history a little.

Whether any of the above are fully valid reasons or not is something up to you and your dev team.

That said, rebasing is not something you want to experiment with for the first time on your production repo. It’s just a bad idea. So I built a playground/lab where anyone can experiment with git rebasing in an isolated and local environment, which can be stood up in seconds. Here’s how to get started:

git clone git@github.com:dmuth/git-rebase-i-playground.git
cd git-rebase-i-playground
./init.sh

The above will create the following repo and directories, each with about a dozen commits:

  • dev-alice – A clone of the repo made by “Alice”, with two branches:  branch1 and branch2branch1 is a branch from master while branch2 is based on branch1. That is by design (and is based on a True Story, heh).
  • dev-bob– A clone of the repo made by Alice’s co-worker “Bob”, only containing master.
  • repo.git – A “bare” clone of the repo. Note that if you cd to this directory, commands like git log --pretty=oneline will work just fine. That is useful for debugging.

The commit graph looks like this:

From there, you can play around in the repos as much as you like. To re-create everything so you can start again from Square One, just run init.sh again.

If you’re looking for some sample exercises, here’s a list:

  • Switch the order of commits 04-fourth and 05-fifth
  • Switch the order of commits 01-first-will-conflict and 02-second-will-conflict
  • Merge the changes of branch2 into master but NOT the changes of branch1
  • Squash the two commits in branch1 then push to origin
  • Switch the order of commits 04-fourth and 05-fifth, push to origin
  • Switch the order of commits 01-first-will-conflict and 02-second-will-conflict, THEN push to origin
  • Run git rebase -i and delete commit 05-fifth. Then recover it.

If you’d like to view hints or solutions to all of the above exercises, they can be found on the page for the GitHub repo itself, at: https://github.com/dmuth/git-rebase-i-playground

Enjoy!