Git+Gerrit workflow for modern projects

Here, you'll find some tips on how to add (review and merge) a change to Gerrit. And a list of common pitfalls. Article is focused on detailed flow of described process with a short version (checklist) of it provided at the very end of this long text.

If below table of contents scares you then jump directly to summary checklist.

Preparation (once)

This document assumes, that you already have a local repository created.

Clone the repository

  • use port and project name (git clone ssh://[USERNAME]@[SERVER]:29418/[PROJECT]) in clone command,
  • pull code (git pull origin master) after cloning a Gerrit repo,
  • set tracking branch (git branch --set-upstream-to=origin/master master).

If any of above fails, read through Setting up new project in Gerrit for details on what could be wrong.

Create or install a commit-msg hook

Each your commit must have an unique Change-ID. You have to add it manually to each of your commit message or install a commit-msg hook, that will automate this step for you.

1. To install this hook, execute scp -p -P 29418 [USERNAME]@[SERVER]:hooks/commit-msg .git/hooks/ in repo's root or (if this fails) download it directly from your Gerrit server via: http://[SERVER]/codereview/tools/hooks/commit-msg.

2. Place it in .githooks folder of your repo or copy it to C:\Program Files\Git\share\git-core\templates\hooks (correct path, if necessary) to have this hook always added to .githooks folder of each new repository.

Configure refs

You have to push with proper refs (git push origin HEAD:refs/for/master). You can automate this. The fastest way is to execute (once) git config remote.origin.push HEAD:refs/for/master command.

Now, you can do just git push (without need to specify refs) and end up without problems.

Longer and detailed version (each push)

Create a local branch

Name it like you want, for example:

git checkout -b xx-branch-name

Note: Always use issue number, that corresponds to proper issue and a descriptive name.

You should always use local branches, even for doing changes as small as few bytes of code or fixing typo. And even, if you're using Gerrit for your own purpose, and you're both commiter, reviewer and project manager. This forces Gerrit to treat each change as really separate and saves you from a lot of troubles (hellish Gerrit dependencies), when you decide to abandon some change. See this SO question for more details.

Code!

Do your magic: code, test, review, fix, code again etc.

Verify changes

Verify and add all newly created files and commit all changes:

git status
git add --all
git commit -am "Commit message"

Note: Your commit need to have proper (unique) Change-ID! See above for more details.

Push changes to Gerrit

Never forget about refs, when pushing (unless you changed your config file properly, see above)! For example:

git push origin HEAD:refs/for/master

If you omit this, but haven't passed Preparation stage, then you have troubles, sir! Gerrit won't object, but it will not be able to do anything with a commit, ending up with a total mess.

Wait for the review (or review yourself)

If everything goes OK, Gerrit will reply with URL to newly created change. Open it in your browser or login to Gerrit UI and go to My > Changes section and picking your change. Verify, that everything is fine with it. Wait for someone to review your change or do this yourself, by clicking Review button, then +2 Looks good to me, approved option (write some comment, if you wish) and push Publish & Submit button.

If, again, everything goes well, your change should change Status to Merged and be moved to Recently closed on My > Changes list. If there are any problems (dependencies?), be sure, that your worst nightmare has just begun.

Pull back reviewed change

Switch to master branch (only, if working on local branches of course) and pull reviewed changes:

git checkout master
git pull

If you were lucky enough, your change should be merged by Git to master branch, so executing git merge xx-branch-name should end with Already up-to-date. Now, you can delete your branch:

git branch -d xx-branch-name

That would be all.

How to handle Please rebase the change locally error?

If other developer made some changes in the files, that you have also changed and push it to Gerrit, and your repository is configured to accept only fast-forward changes, you'll see a message saying Please rebase the change locally and upload again for review, when you try to review your change. In this case, you have to rebase it.

All you have to do is pull current state of repository, rebase your change on top of it and push changes again:

git pull
git rebase origin/master
git push

Git will do all the hard work for you. After push, Gerrit will mark your change as having one or more Patch Sets and should now allow you to review and merge your change. If someone else is reviewing your changes, he or she will probably have the same problem in such scenarion, so you may be notified, that a rebase and new patch set submission is required.

Quick review (checklist)

Preparation (once)

  1. Clone: git clone ssh://[USERNAME]@[SERVER]:29418/[PROJECT] + git pull origin master.
  2. Hook: scp -p -P 29418 [USERNAME]@[SERVER]:hooks/commit-msg .git/hooks/.
  3. Config: git config remote.origin.push HEAD:refs/for/master.
  4. Track: git branch --set-upstream-to=origin/master master.

Dealing with a new change in Gerrit (each change)

  1. Branch: git checkout -b xx-branch-name.
  2. Magic: code, test, review, fix, code again etc.
  3. Changes: git status + git add --all + git commit -am "Commit message".
  4. Push: git push (assuming, you did preparation phase and set proper refs in your config!).
  5. Review in Gerrit or wait for the review.
  6. Pull: git checkout master + git pull.
  7. Delete: git branch -d xx-branch-name.

Dealing with non-fast-forward change

  1. Pull: git pull or git fetch.
  2. Rebase: git rebase origin/master.
  3. Push: git push.

That's all, folks!

Leave a Reply