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?
Basically it all comes down to this: apply a range of commits elsewhere
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:
checkout topic
reset --hard master
) Commits in topic but not in master—namely X, Y, Z—are put aside for later useNote 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.
--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.
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
.
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.
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.