rebase like a boss

Everyone who loves Git hopefully loves branching. However, there’s a problem with branching: merging your work back in. Surprisingly enough, Git’s inflexibility makes this action quite simple. It’s my opinion that Git users should be branching frequently, and rebasing them back into the mainline when ready.

Merges should be used only to denote when long lived branches (read: several weeks, months) are brought into the mainline, or for some reason you want to specifically denote when two histories were joined together. Rebasing as often as possible means you keep the history graph as simple as possible. For example, you may be seeing a lot of these if you’re only doing merges:

There’s a way around this: use git rebase! The action of rebasing is conceptually simple: you’re playing a set of changes on top of another branch. I like Travis Swicegood’s metaphor the best: rebase is like a meat cleaver. Given the right amount of skill, you can slice and dice your commits the way you want. Here’s an example of a feature branch we just had for Hoptoad:

So, as you can see, there’s been a fair amount of work in this branch across several days and contributors. There’s also commits going on in other branches as well, most notably our master branch (the far left one). Now, if I had done a merge, we would have seen this:

$ git checkout master
$ git merge lighthouse_config

Our merge commit specifically denotes when we brought our work into master. This is a perfectly acceptable way of bringing in our changes, but now we have these two paths of history when we don’t necessarily need them. Especially for long lived feature branches, this can start to become a mess in your history if you have multiple features being developed in parallel.

Another issue is when you want to bring in the latest upstream changes to your feature branch: you’ll get a lot of little merge commits. Rebasing blows away those tiny merge commits that we used for when we wanted to sync up with the master branch. So, this means that all you’re left with is the clean history of what happened. The commits have been moved to on TOP of the master branch after a git rebase master:

$ git checkout lighthouse_config
$ git rebase master

We could get even cleaner by squashing our commits, but I didn’t squash in this situation since multiple people had worked on the feature. In general, this is a great way to use Git as shown by Josh Susser’s fantastic agile story branch post. If I had squashed the branch, it would end up like this:

$ git checkout lighthouse_config
$ git rebase -i master

So the lesson here is to rebase whenever possible. It keeps the history clean, and it’s just easier in general to understand when you’re looking at the log. Use git pull --rebase when pulling down your latest changes, or just use git fetch and git rebase as you see fit. Just remember the golden rule of rebasing and you’ll be fine: NEVER rebase existing, pushed commits!