Demystify git rebase with animations

January 18, 2019

There are lots of commands in git and we can often achieve our goal in several different ways. I usually manage to get my stuff done with just few commands like rebase, reset, cherry-pick. But sometimes I felt I was doing it ineffectively. Like for example squashing all commits into a single one so that it is easier to rebase. Even though I heard that rebasing with the onto option could be useful, I never took the time to man it… until recently. So what are some use cases?

  • we want to cherry-pick multiples commits
  • we have created a branch from the wrong one
  • we want to delete a range of commits

Basically it all comes down to this: apply a range of commits elsewhere

Rebase

Let’s begin with a little reminder about how rebase works in its simplest form. The man gives us:

git rebase upstream [branch]

To illustrate this, let’s take an example. topic has forked master from B but in the meantime a new commit—C—has arrived on master. To bring topic up to date with master we can run:

git rebase master topic

Here is what happens:

  1. Git performs a checkout topic
  2. The index and working tree are reset to master (reset --hard master) Commits in topic but not in master—namely X, Y, Z—are put aside for later use
  3. Those commits are applied one by one on master. This is like “cherry-picking” them.

Note If we already are on the topic branch (HEADtopic) then we can omit the branch arg and just type git rebase master (step 0 is skipped) This is a common short-hand.

The --onto option

git rebase --onto newbase upstream [branch]

The only difference is in step 1. Git hard resets to newbase instead of upstream. Step 2 remains the same, commits upstream..branch are applied.

This is particularly useful when we want to change the base branch.

Example

We have created a branch topicB from topicA but it was a “mistake”. The work on topicB is totally unrelated to topicA and thus doesn’t depend on it. To fix this unfortunate mistake and make topicB fork from master, we can run:

git rebase --onto master topicA topicB

Step 1 is hard resetting to master, step 2 is applying commits topicA..topicB .

Removing some commits

I told you in the intro that we could also remove a range of commits by using this option. Well, lets say we have a branch like the one below and want to get rid of commits F and G.

Step 1 is a hard reset to E and step 2 is picking G..I (as a reminder G is excluded: this is how .. works in git) F and G are removed.

Let’s play with the past

The -i option lets us interact with any commits. We can move, squash, delete, rename, edit… It’s on of the most powerful git command that allows us to do pretty much anything with the git history.