This post is a follow up to this one where we explore the .git directory.
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
A second parameter
Let’s see if it is more clear in ascii:
A--B--C master \ D--E feature1 \ F--G feature2 Here we want to rebase feature2 to master beginning from feature1 | | <newbase> <upstream>
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:
And that’s the end of my first Git series.
You can read the part 2 here.
And the part 1 here (my favourite 😊).
Please tell me in the comment what the next thing you’d like to learn about Git and, if you liked this post, do not forget to subscribe to my newsletter.