A rebase-based workflow 02 Apr 2010
software development git

When I first started working with Git in mid 2008 I was blissfully oblivious to the concept of a “rebase” and why somebody might ever use it. While at Slide we were crazy for merging (see diagram to the right), everything pretty much revolved around merges between branches. To add insult to injury, development revolved around a single central repository which everyone had the ability to push to. Merges compounded upon merges led to a frustratingly complex merge history.

When I first arrived at Apture, we were still using Subversion, similar to Slide when I arrived (I have a Git-effect on companies). In order to work effectively, I had to use git-svn(1) in order to commit changes that weren’t quite finished on a day-to-day basis. Rebasing is fundamental to the git-svn(1) workflow, as Subversion requires a linear revision history; I would typically work in the master branch and execute git svn rebase prior to git svn dcommit to ensure that my changes could be properly committed at the head of trunk.

When we finally switched from Subversion to Git we adopted an “integration-manager workflow” which is far more conducive to rebase being useful than the purely centralized repository workflow I had previously used at Slide.

From the [Pro Git]( site

In addition to the publicly readable repositories for each developer, we use Gerrit religiously which I’ll cover in a later post.

We use rebase heavily in this workflow to accomplish three main goals:

  • Linear revision history
  • Concise commits covering a logical change
  • Reduction of merge conflicts

Creating a solid linear revision history, while not immediately important, is nicer in the longer term allowing developers (or new hires) to walk the history of a particular file or module and see a clear progression of changes.

Creating concise commits is probably the most important reason to use rebase, when working in a topic branch I will typically commit every 20-40 minutes. In order to not break my flow, the commit messages will typically be brief and cover only a few lines of changes, atomic commits are great when writing code but they’re lousy at informing other developers about the changes. To do this, an “interactive rebase” can be used, for example, collapsing the commits in a topic branch ticket-1234 would look like:

  • git checkout ticket-1234
  • git rebase -i master

This will bring up an editor with a list of commits, where you can “squash” commits together and re-write the final commit message to be more informative.

The Workflow

For the purposes of the example, let’s use the topic branch from above (ticket-1234) which we’ll assume has 3 commits unique to it.

  1. Fetch the latest changes from the upstream “master” branch
    • git fetch origin
  2. Rebase the topic branch, effectively piling the 3 commits on top of the latest tip of the upstream “master” branch
    • git rebase origin/master
  3. Collapse the 3 commits in the topic branch down into one commit
    • git rebase -i origin/master
  4. (Later) Bringing those commits down into the “master” branch
    • git checkout master && git rebase ticket-1234

With an interactive rebase, you can chop commits up, re-order them, squash them, etc, with the non-interactive rebase you can pile your commits on top of an upstream head making your changes apply cleanly to the latest code in the upstream repository.

git ready has a few nice articles on the subject as well, such as an intro to rebase and an article on squashing commits with rebase