Git Rebase for Dummies

In the following post I will go over how and why to use git rebase instead of git merge, even if you don’t completely understand how and what rebasing does.

We will try to explain in layman’s terms (e.g., without relying on the term ‘HEAD’) what’s happening, and most importantly, why you should drop your fear of rebase and learn to love it. If your Git-fu is strong and you’re a Git-ninja, cherry-picking all over the place, you won’t need this. However, if you’re a smart developer but learning Git has been a trip down the rabbit hole, read on.

Specifically we will cover the most common use-case, where you are working (alone) on a feature branch and have finished your feature, and you wish to now push your code to master. Perhaps you might ‘merge’ from master (as many naive guides suggest), but you’ve heard people say you should be rebasing. How? What? Why?

We will cover the following:

  1. Base workflow when rebasing in git
  2. In-depth explanation of what rebase does, in easy terms
  3. Conflicts – and why you shouldn’t fear them
  4. Summary

1. Git rebase workflow cheatsheet:

  • git checkout master
  • git pull
  • git checkout branch
  • git rebase master (if you have conflicts, see below.)
  • git log (see your branch commits on top)
  • git diff master
  • git push –force (unless someone else has pulled this branch. This will mess them up.)

(if ready to deploy:)

  • git checkout master
  • git merge branch
  • git push

2. git rebase, step by step:

  • git checkout master
  • git pull

As you may have heard before, *pull* is actually *fetch+merge*. Anyway, in our case master is now up-to-date.

  • git checkout branch
  • git rebase master

The crucial step, of course. What rebase does is it puts the branch commits on top of master’s commits., instead of merging them together.

Let’s explore the differences between merge and rebase. Suppose master has commits A-B-C-D, and your branch includes your additions, commits E-F. After merging, we will have all the commits together. Hooray? No, wait – the order in which the commits appear will depend on at which point we branched off. Our commit log might look something like A-B-E-F-C-D, despite the last commits de-facto being E-F. The end result (the code) will be the same, but the commit log is deceiving. (In fact, in the case of merging there will also be a redundant ‘merge commit’, but let’s ignore that for now.)

When merging, if we had branched off from A, the end result after merging would be A-E-F-B-C-D. If we had branched off of B, if would be A-B-E-F-C-D. If we had branched off of C, it would be A-B-C-E-F-D. If we had branched off of D, it would be A-B-C-D-E-F. And this is what we want, of course — after ‘adding’ our branch to master (and pushing), we would want the commit log to reflect our changes as being added ‘on top’ of everything else, since logically that’s what happened for master.

Enter rebase. What rebase does is ignore the point at which you branched off. It grabs the current ‘last commit’ of master, and puts all of your commits on top of it. So in effect, it simulates as if you had just now branched off master, done all of your commits, and then merged back. In the above scenario, it will ensure our commit log will be A-B-C-D-E-F. Awesomeness!

Bottom line is if you merge, the post-merge commit log would be something like A-B-E-F-C-D, where B is the commit where you branched off, E-F are your commits, and C-D are any commits pushed to master between the time you branched off and the time you merged.

But if you rebase, the post-merge commit log will *in any case* be A-B-C-D-E-F, where *your commits* E-F are *on top*. Why is this important? For you as a developer, it usually isn’t. I did my commits, merged & deployed, thank the Lord. But think of your coworker: He sees you’ve pushed code to master and goes to your github repo to view the commit log to see what’s changed. Bah humbug! If you’ve ‘merged’ the top commits he sees are C-D, which aren’t the new commits – they were already there. How can he even know what’s changed? It’s very difficult, up to impossible. However, if you rebase, a quick look at the git log will show the newest commits on top. Excellent and shiny.

Now we can know exactly what’s changed, revert if necessary, etc. This is also relevant in the case of Pull Requests, and any other situation in which you inspect the commit log. To review, you should now be able to understand the excellent documentation and visualization at http://git-scm.com/docs/git-rebase and http://git-scm.com/docs/git-merge.

  • git log Yes! Our commits are on top. We can easily see exactly what we’ve changed, by commits. To stress the point, when you ‘merge’, the top commits in the commit log will be the last commits pushed to master by *anyone*, not necessarily yours – very confusing.
  • git push –force (unless someone else has pulled this branch. This will mess them up.)

If we rebase over master and then push to our branch, we might have to override a previous push to the branch, since we’ve rewritten history (moving our commits to the ‘top’). The easiest way to overcome this is by –force’ing our code into the repo. Obviously this might create issues for anyone sharing our branch, which is why this method is advocated only if you are not sharing this branch with others.

3) Conflicts

You might have conflicts during the rebase. If this happens, stay calm and follow git’s instructions. Git is here to help you (and if we freak out and lose our marbles, we can always git rebase –abort and go back to square 1.)

As always, Git is a little (too?) verbose. But it helpfully CAPSLOCKS the important part: And at the end, it will (vaguely) what you need to do: OK, what’s going on? The issue to understand is that when ‘rebasing’, Git first ‘grabs’ the master branch (or whatever branch you’re rebasing on) and then ‘applies’ all of your commits, one-by-one, *on top* of those commits. (As we said, this is main difference from ‘merging’, which integrates (well, merges) your commits in-between the commits on master.). Unfortunately, sometimes we have conflicts, but we can solve them.

Git has already told us, but to be sure a git status will show us the files being changed in *this* commit, including the conflicted ones. (Recall, we are rebasing all of the commits in our branch, one-by-one. Each commit might entail several files.)

You might conflicts in one or more files. Go into those files and fix the conflict[s], the standard way . Now back in the shell, we can proceed, recalling git’s instructions: git rebase –continue.

Note, you might have more than one conflicting commit – we are ‘rebasing’ all of your commits, so each one might contain a conflict you might have to solve.

4) Summary

Hopefully by now you have both understood what rebase does (specifically, differently form merging) and why it is important. Hopefully you have also lost your fear of rebase conflicts.

Remember that even if you don’t need it for yourself, the team as a whole can much better observe each other’s work if everybody rebases.

Be a team player – rebase.

Advertisements

One thought on “Git Rebase for Dummies

Comments are closed.