Mastering git rebase
Diving more into git rebase.
The elegance of pull rebase
This is the follow up of this post where I explained what really is the rebase and its golden rule. As many of you pointed it out, most of Anna’s troubles could have been avoided had she used the pull rebase. I didn’t want to talk about this back then in order to keep my post short enough, but now is the time.
Let’s say Bob is working on a branch behind the remote, his history might look like this:
And now Bob decides that it is a good time for him to pull, as you might have guessed there will be some issues here. Because Bob is behind the remote (GitHub), git will ask him to do a merge in, the result will be this:
This solution is perfectly fine, and works flawlessly however you might be please to know that you have other options to solve this problem. One of them is the pull — rebase.
When you do a pull — rebase git tries to figure out which commit are only on your branch and which are on the remote. It merges the ones on the remote with the most recent commit on your local repository also in the remote. It then rebases your “local” commits on the tip on that branch. It might sounds complicated but it really isn’t:
Step 1: Git only takes care of the commits both in your branch and the remote
You can visualize it as a basic clone of the remote (GitHub)
Step 2: Git rebase the local commits
If you remember, during a rebase git reapply the commits one by one, here this exactly what happened. Git reapply E on the top of master, then F. Note that this one example where a branch is rebased on… itself.
Hum okay, but what for?, I like merge.
Well, for me the biggest problem with the merge solution is that is often polluting the history when there is no need to do so. The pull — rebase solution is, in my opinion, more elegant. I would go further by saying that when you want to pull recent changes on your branch you should always use pull — rebase. But be careful, because during a rebase git reapplies each commit one by one, if you rebase 20 commits, you might have to solve 20 conflicts and you would have to solve them one by one.
As a rule of thumb, I guess we could state that:
1 Big change, a long time ago changes: merge
2 Small changes, recent changes: pull — rebase
The power of rebase — onto
Imagine that your history looks like this:
Let’s say that you want to rebase the feature 2 branches, on master. If you do the normal rebase master you’ll end up with this:
It might be counterintuitive when you look at the fig1 but the commit D “belongs” to both branch feature1 and feature2. Therefore if you rebase the feature2 branch on master, the commit D will be reapplied on the top of master with F and G. So now what if we want that result instead:
Well this is where git rebase — onto enter the game. First, let’s begin by reading the doc:
If we look specifically at the — onto section:
As usual, let’s try to translate those cryptic sentences. The <newbase> param is the destination of your rebase, the commit or branch where you want to rebase your branch new branch to. In our scenario the <newbase> is master.
A second parameter <upstream> (a very bad name) can also be used, this second parameter can be seen as the first commit you want to rebase from.
Let’s see if it is more clear in ascii:
F--G feature2Here we want to rebase feature2 to master beginning from feature1
So all we have to do, bein on feature2, is a
git rebase — onto master feature1
Which would give as the result what you can see in fig 3.
Thank you for reading:
If you like the Article you can give it a clap 👏.
I write about tech in general and recently, more about my new price competitor monitoring business.
If you feel like you owe me a 🍺 after learning something valuable you can always buy me a ☕️.
Next time I’ll begin my new series about Python and Python tips. Stay tuned 😃
Other things I wrote that you might like:
Git series 1/3: Understanding git for real by exploring the .git directory
“Whoah, I’ve just read this quick tuto about git and oh my god it is cool. I feel now super comfortable using it, and…
Beware of Python dict.get()
If you think that value = my_dict.get('my_key', 'default_value') is equivalent to value = my_dict.get('my_key') or…