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 will be easier to rebase afterward.
Even though I heard that rebasing with the
onto option could be useful, I never took the time to man it… until recently. I guess now is a good time to write something about it.
Here are some use-cases:
Basically it all comes down to this: apply a range of commits somewhere else
Let’s begin with a little reminder about how rebase works in its simplest form. From the man (unix) we get:
git rebase upstream [branch]
I am gonna give some examples and intentionally avoid any short-hand way at first.
When we run the command
git rebase master topic then:
git reset --hard masterexcept that commits X, Y, Z are put aside for later use. Basically all commits that are in topic but not in master (
Step 2 may fail applying the commits. Don’t worry, be happy, we can either resolve the conflict by running
git rebase --continue or get back to the state we left before the rebase with
git rebase --abort
Note If we already are on the topic branch (HEAD → topic) then we can omit the branch arg and just type
git rebase master (step 0 is skipped) This is a common short-hand.
The man tells us:
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.
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.
So naturally, we need to fix this unfortunate mistake to make topicB fork from master. To do so we can run:
git rebase --onto master topicA topicB
As seen previously, step 1 is hard resetting to master, step 2 is applying 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.
We can run:
git rebase --onto E G I
Step 1 is a hard reset to E and step 2 is picking
(as a reminder G is excluded: this is how
.. works in git)
F and G are removed.
-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.