Thu Feb 24 10:44:44 EST 2011

Gerrit, reviews and branches

For a contract job I'm using the gerrit code review system[1].  These
are some impressions and a summary of the workflow I'm using.


Gerrit is "reviewer-oriented", meaning it works best if the patch
management burden is carried on the patch submitter side.  This
requires some discipline on the patch submitter side to make it not
overly painful to use.

The basic workflow is simple:

  * Start with a clean repository = HEAD of reviewed code

  * Optionally, pull the review from gerrit if this is a rework of a
    previous review submit.

  * Make incremental changes using multiple git commits.

  * Squash all changes

  * Resubmit to gerrit

This satisfies the requirements of the reviewer:

  * The reviewer would like a single, coherent patch per conceptual
    change in order to make the review process more meaningful.

However, it is a bit crude for the developer:

  * The developer/submitter would like a chronological account of all
    the changes made to a single conceptual update identified by a
    Change-Id, including all mistakes and fixes.

A straightforward way to implement this is to use one branch per
Change-Id patch set on the developer side.  This branch can then keep
the chronological edit history, hiding it from the reviewer.

A) Creating a new review

Checkout the branch on which you want to base the current review.
This is most likely the head of the reviewed master branch.

git checkout master
git pull origin

Create a new branch that identifies the review to be submitted.
I.e. suppose we write a driver for a gadget.

git checkout -b gadget_driver

Start working in this branch, performing incremental chronological
commits without any history rewriting:

git commit -am 'initial code skeleton'
git commit -am 'test case 1'
git commit -am 'fix for foo'
git commit -am 'fix for bar'
git commit -am 'test case 1 passes'

When you are done and would like to submit, create a new branch to
contain the squashed commit:

git checkout -b gadged_driver_review

Now the intention is to create a single patch on top of the master
branch.  This can be done using an interactive rebase:

git rebase -i master

This will present you with a rebase script.  Change all the
occurrences of "pick" to "squash", except the top one.  When you save
that script, git performs the rebase and drops you into your editor to
edit the commit message of the review.  Edit the review message and
make sure the last line contains the Change-Id.

When done, push the patch to gerrit as described in the manual.

Note that it's not really necessary to keep the squashed patch in your
private repository.  It's always possible to check it out again from

B) Updating a review

You've submitted a review and you want to update it.  If you still
have the review in a branch in your private tree, simply checkout that
branch and start working.

If you don't have the patch you need to obtain it from gerrit.

Note that at this point the reviewd head might have moved compared to
the point where you submitted the patch.  It is usually a good idea to
rebase onto this new reviewd head, as it avoids merge conflicts for

git checkout master
git pull origin

Then we create our local branch, and pull in the change from gerrit.
The name is arbitrary.  Pick something so you can easily relate it
back to the Change-Id + patch-set it is based on.  I.e. here we pick
the sequence number assigned by gerrit (81) and the patch set (2).

git checkout -b 81-2
git fetch <gerrit-repo> refs/changes/81/81/2
git cherry-pick FETCH_HEAD

If the reviewed head moved too much the cherry-pick might fail so you
need to resolve conflicts.  After this step succeeds you have all you
need on the local branch to make incremental changes, just as in the
new review case.  Perform commits, rebase and push.

git commit -am ...
git commit -am ...
git commit -am ...
git commit -am ...

git rebase -i master
git push ...

Some general advice:

* Make backups.

  Until you fully understand the git workflow, please make backups of
  your repository before desctructive `rebase' or `reset' operations.

  Git is quite unforgiving.  If you ask it to throw away your work it
  will throw away your work!  Rule of thumb is to make sure your
  patches are safely tucked away on a private branch before running
  any distructive operations.

  It is sufficient to backup the .git directory only.

* Use gitk or any other graphical client to visualize the branches.
  Once you start juggling branches it helps a lot to be able to
  visualize the structure.

* Recovering a clean starting point.  

  The basic idea is to keep your local master branch in sync with the
  reviewd remote origin branch.

  When you accedentally commit on top of your master branch you can
  use the following procedure to restore to a clean master state.

  First make sure that all your changes are safe.  Assuming you are on
  the master branch, commit the changes and create a new branch that
  contains these changes.

      git commit -am <commit_message_of_local_changes>
      git branch <new_branch_msg>

  Then switch to the master branch and discard all changes that are
  not on top of the locally pulled part of the remote reviewed

      git checkout master   
      git reset --hard origin

  Optionally you can re-sync the remote origin too.

      git pull origin

[1] http://en.wikipedia.org/wiki/Gerrit_%28software%29