ITK/Gerrit/Primer: Difference between revisions

From KitwarePublic
< ITK‎ | Gerrit
Jump to navigationJump to search
m (Corrected typo)
(Replaced content with "This page previously contained information on use of Gerrit for ITK. The old information has been removed to avoid confusion. Please get started here instead.")
Line 1: Line 1:
This primer is to aid the ITK developer community in using Gerrit.  Some of the idiosyncrasies of Gerrit take a little work to understand and appreciate, especially if one is new to using the [ git] distributed revision control system.
This page previously contained information on use of Gerrit for ITK.
The old information has been removed to avoid confusion.
==Gerrit basics==
Please [[ITK/Git|get started here]] instead.
Gerrit is designed to take a single change with a change log and make it publicly available for comments and revisions.  Once the change has been sufficiently reviewed and approved, it will be pushed into the official ITK repository.  Gerrit addresses the problem of many changes scattered about many git repositories by bringing them into a central place and allowing commenting and changes to become transparent to the rest of the community.
===Creating a Gerrit account===
In order to register you need to [ get an OpenID]. Be aware that a [ GMail] account automatically gives you an OpenID.
To register with Gerrit, first have your OpenID ready.  Then visit  Click the "Register" link in the upper left.  If you have a Google or Yahoo account, click on the "Register with a Google account".  This will create your account.  Otherwise, enter the URL of an OpenID provider.
* '''commit''' To git, a [ commit is a group of changes to a repository].  git uses a unique hash algorithm to identify a change (SHA1).
* '''Change-ID''' Gerrit uses an [ internal tracking Id to properly refer to a change].  Change-Ids let Gerrit link it's changes to a commit in the git repository.
* '''Change number''' The Gerrit change number is a small number used to identify the commit when pushing to Gerrit.
* '''repo''' An abbreviated form of git repository.  May refer to a local repository or a remote repository.
This primer requires a very basic understanding of git.  The reader should begin by understanding:
# [ Normal git workflow]
# [ Basic branching]
git should be properly setup on your system, and you should identify yourself by name and email:
git config --global "Your name goes here"
git config --global ""
This will help us track you down when things break.
If you are frequently contributing to ITK through Gerrit, please set this configuration:
git config hooks.GerritId true
This setting can be done once globally ('''--global''' flag), or on a repo by repo case (the default).  This setting automatically adds the Change-Id to any commits which greatly simplifies submission of subsequent revisions or commits.
====Helpful settings====
'''Emacs users:''' if you put this line in your .emacs file:
(setq auto-mode-alist (cons '("COMMIT_EDITMSG$" . auto-fill-mode) auto-mode-alist))
Git will automatically wrap your commit messages, which is what good git etiquette requires.
'''Bash users:''' git comes with a set of completion options that are very useful.  The location of the file varies depending on your system:
  source /opt/local/share/doc/git-core/contrib/completion/git-completion.bash  # Mac with git installed by Mac Ports
  source /usr/share/bash-completion/git      # Linux
'''Windows users:''' Mysysgit can be configured to use notepad++, especially important because vim on Windows lacks several critical features (like copy/paste).  More details can be found at [ StackOverflow].
git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
More tips and tricks can be found [[ITK/Git/TipsAndTricks|here]].
==git / Gerrit workflow==
For the sake of this primer, we'll be making a series of small documentation changes to ITK code.  The basic workflow from the developer's standpoint is:
* [[#Clone_the_ITK_official_repository| Clone the ITK official repository]]
* [[#Create_a_topic_branch|Create a topic branch]]
* [[#Edit,_test,_commit,_edit,_test,_commit,_ad_infinitum|Edit, commit, edit, commit, ad infinitum]]
* [[#Compress_your_branch_into_a_single_commit_(not_normally_necessary)|Compress your branch into a single commit]]
* [[#Push_your_changes_into_Gerrit|Push your changes into Gerrit]]
* [[#Review|Review]]
* [[#Stage_changes_into_the_ITK_official_repository|Stage changes into the ITK official repository]]
* [[#Pull_new_changes_from_ITK_repository|Pull new changes from ITK repository]]
These steps will be detailed in the next sections.
==== Clone the ITK official repository ====
The instructions for cloning the official repository are [[ITK/Git|here]].  For the minimalist:
git clone git://
cd ITK
==== Create a topic branch ====
git works well to create "micro-branches".  Frequently, branches are considered poor practice in centralized revision control systems such as CVS and Subversion.  However, in git branches are typically very easy to work with and manipulate.  They are required for working with Gerrit, so get used to them.
We'll call our branch GerritPrimer.  The branch may be created in two steps:
git branch GerritPrimer    # Create a new branch from our existing revision
git checkout GerritPrimer  # Switch our working directory into the GerritPrimer branch
or you can do this all at once:
git checkout -b GerritPrimer  # Create GerritPrimer and switch the working directory into that revision
When we are finished, our revision history looks like this:
Notice that GerritPrimer, master, origin/HEAD and origin/master branches all point to the same commit.  You can think of branches is movable labels that point to a particular commit in the revision history.  As we add code and commit our changes, we'll see GerritPrimer move.
==== Edit, test, commit, edit, test, commit, ad infinitum ====
Next, we'll edit some files and commit the changes.  In this primer, we'll make 3 changes.
Edit ITK/Code/BasicFilters/itkRecursiveGaussianImageFilter.h
add " * \see DiscreteGaussianImageFilter" on line 54
Run the tests:
When all passes, we ask git to show us what's happening with our modifications:
revelation:ITK(GerritPrimer) blezek$ git status
# On branch GerritPrimer
# Changed but not updated:
#  (use "git add <file>..." to update what will be committed)
#  (use "git checkout -- <file>..." to discard changes in working directory)
# modified:  Code/BasicFilters/itkRecursiveGaussianImageFilter.h
no changes added to commit (use "git add" and/or "git commit -a")
git has the concept of an index, or an area where changes are stored before they are committed.  In the listing above, git knows that Code/BasicFilters/itkRecursiveGaussianImageFilter.h is changed, but it has not yet staged that change into the index.  To tell git that we want to add this change into the next commit, and make the commit we can do this in two steps:
git add Code/BasicFilters/itkRecursiveGaussianImageFilter.h  # Add the modified code into the index
git commit                                                    # commit all modifications
or in one step:
git commit -a    # Auto-add all modified files into the index, then commit all modifications
'''Writing a good commit message'''
[ Well written commit messages] are a help for the entire ITK community.  It is common to build a change log from all of the commit messages between releases.  Commit messages should have a single, succinct header line, a blank line, and a body of text wrapped to 72 characters.  ITK has adopted the following conventions for the first line of a commit message.
<PREFIX>: summary of the change
The '''PREFIX''' options are:
*  BUG:    fix for runtime crash or incorrect result
*  COMP:    compiler error or warning fix
*  DOC:    documentation change
*  ENH:    new functionality
*  PERF:    performance improvement
*  STYLE:  no logic impact (indentation, comments)
*  WIP:    Work In Progress not ready for merge
* To reference Mantis issue XY, add " (#XY)" to the END of the FIRST line.
The form of a commit message should follow [ this style]:
<PREFIX>: Short (50 chars or less) summary of changes
More detailed explanatory text, if necessary.  Wrap it to about 72
characters or so.  In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body.  The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Write your commit message in the present tense: "Fix bug" and not "Fixed
bug."  This convention matches up with commit messages generated by
commands like git merge and git revert.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded by a
  single space, with blank lines in between, but conventions vary here
- Use a hanging indent
After two more commits, our repository looks like this:
From where we made the branch (master, origin/HEAD, origin/master), we have three commits.  Notice that the GerritPrimer tag has moved along with our commits.
==== Compress your branch into a single commit (not normally necessary) ====
If we were to push our branch to Gerrit, it would show up as 3 dependent commits for commenting / approvals.  This is usually exactly what we want. We would like others to review our changes in three steps, and would like these three steps to be preserved in our repository's history. ''Note: most of the time we want all of the commits to go to Gerrit.'' If we squash the commits, and then have to edit files in response to review, and upload those changes it can get very complicated keeping things in sync. If the commits should remain as single commits in history, then they should probably be single commits in Gerrit too.
There are times where we want a series of "micro-commits" to be combined into one larger body.  ''Please take some time to consider how many commits you would like in Gerrit!''  If we decide to collapse our three commits into a single commit this is easily accomplished using the [ git rebase command].  What we are going to ask git to do is create one commit from the three that we currently have.  The command is:
git rebase -i HEAD~3
The -i flag instructs rebase to do this interactively, and "HEAD~3" tells git to collapse the last three commits.  We can also use:
  git rebase -i master
because right now, master and HEAD~3 point to the same commit.  We can also use the SHA1 of that particular commit.
When we run the command we get this:
pick 1e01adb Added documentation.
pick b465a05 Documentation changes.
pick 7d7f3c1 Documentation changes.
# Rebase 43b5f37..7d7f3c1 onto 43b5f37
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
We see three lines at the top which contain the first lines from our three commits.  We need to change this commit message to tell git rebase what we want to do.  What we would like to do is '''pick''' the first commit, and '''squash''' the other two.  The end result will be a single commit.  The file looks like this when we are done:
pick 1e01adb Added documentation.
squash b465a05 Documentation changes.
squash 7d7f3c1 Documentation changes.
git processes what we've done and puts us back into editing the commit message:
# This is a combination of 3 commits.
# The first commit's message is:
Added documentation.
Added \sa tag to reference DiscreteGaussianImageFilter.
# This is the 2nd commit message:
Documentation changes.
Added \sa tag to reference RecursiveGaussianImageFilter.
# This is the 3rd commit message:
Documentation changes.
Added \sa tag to reference Recursive and Discrete GaussianImageFilters.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Not currently on any branch.
# Changes to be committed:
#  (use "git reset HEAD <file>..." to unstage)
#      modified:  Code/BasicFilters/itkBilateralImageFilter.h
#      modified:  Code/BasicFilters/itkDiscreteGaussianImageFilter.h
#      modified:  Code/BasicFilters/itkRecursiveGaussianImageFilter.h
git has compressed the three commits into one, combining the commit messages and the changes to the code.  In the original commits, we only modified one file at a time, but in this new commit, three files are modified.  Rewriting the commit message to make it look like one big commit gives:
# This is a combination of 3 commits.
# The first commit's message is:
Added documentation.
Added \sa tag in itkRecursiveGaussianImageFilter to reference
DiscreteGaussianImageFilter. Added \sa tag in itkDiscreteGaussianImageFilter.h to
reference RecursiveGaussianImageFilter. Added \sa tag to reference Recursive and
Discrete GaussianImageFilters in itkBilateralImageFilter.h.
Now we have a look at our commit history:
[[File:GerritPrimerSquashedCommit.png‎ ]]
So our three commits now look like one.  git removed the three commits through the rebase command.  Remember that these commits only exist in your local clone of the ITK repository.  Next step is to push them into Gerrit.
==== Push your changes into Gerrit ====
First, we need to tell git about the Gerrit server:
git remote add gerrit
(be sure to change '''USERNAME''' to your username on the Gerrit server)  This does nothing more than create an alias called '''gerrit''' that can be used for pushing and pulling changes.
Gerrit needs to know where we intend the code to go, so we'll push our particular commit to a particular place in Gerrit.  The '''git push''' command takes three arguments, a destination repository, a local commit and a remote location.
git push gerrit HEAD:refs/for/master/GerritPrimer
'''gerrit''' is the destination repository, '''HEAD''' is our local commit(s), and '''refs/for/master/GerritPrimer''' is the remote commit name, along with topic name '''GerritPrimer'''.  We can call the remote commit anything we like, e.g. '''refs/for/master/foo_bar_garf''', but it is sensible to make a useful name.
revelation:ITK(GerritPrimer) blezek$  git push gerrit HEAD:refs/for/master/GerritPrimer
Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 5.88 KiB, done.
Total 7 (delta 4), reused 0 (delta 0)
remote: (W) f62f37: commit message lines >70 characters; manually wrap lines
remote: New Changes:
* [new branch]      GerritPrimer -> refs/for/master/GerritPrimer
revelation:ITK(GerritPrimer) blezek$
Gerrit has told us that there is a new branch created called GerritPrimer and we can take a look at  (Looks like we should have wrapped the lines better...)
==== Review ====
What follows is a simplified overview of the review process.  More in-depth information [[ITK/Gerrit/ReviewPrimer|can be found here]].  Our change is now available on the Gerrit site:
Clicking on the link takes us to the page describing the change (  Here we can invite reviewers to look through the code, comment on the changes, etc...
Our basic workflow would be to invite a few reviewers through the Gerrit site.  They will be notified via email and asked to comment on the code.  Reviewers can pull your changes locally, build and test.  For a change to be pushed into the official repository, it must be reviewed and verified.  The original author is not allowed to vote on commit.
The review screen looks like this (on a different commit from our primer example):
In this case, I have reviewed the changes, and marked them as Verified (+1), and Approved (+2).  Generally, developers with write access can grant a +2 in the review, while others can only mark +1.  A commit takes a score of 2 or more to be approved in the code review box.
==== Making Changes in Uploaded Patches ====
The original page is available [[ITK/Gerrit#Making_Changes_in_Uploaded_Patches|here]].
If your change requires revision before it is accepted, you will first need to correct the commit in the topic branch, find the change-id in Gerrit to upload the revised patch (if it was not automatically inserted into your commit by the Gerrit hook). The change-id can be automatically added to your commits (this is preferred), or you can manually add it after the fact.
Assume that you are working on gerrit issue #98, and you've made two local commits.  The change ID is a SHA1 hash of your changes from the first commit, and uniquely identifies a commit even when it is changed in response to feedback/rebasing.  To push a new commit for a given change number, you will need to reference the change-id.  NB: the gerrit hooks should help ease this.
$ git rebase -i HEAD~2
Two commits should appear with the word 'pick'. You actually need to remove the word pick and replace with 'edit', which can simply be 'e':
pick 641cd36 Add space
e aq98139 Remove space
'''NB:''' If 'edit' fails with a 'squash commits' error, you may need to use 'squash' in place of 'edit'/'e'.
Click 'save' from your favorite editor. This will allow you to edit the chosen patch, and create a new hash for the newly created patchset.  The output should then read something like:
[my_branch_name 1f58239] Remove space
  1 files changed, 0 insertions(+), 1 deletions(-)
Then simply push this edited topic branch to Gerrit. If each commit has the Change-Id line as its final line Gerrit will automatically replace the commits in its database.
git push gerrit HEAD:refs/for/master/GerritPrimer
Gerrit will resolve the Change-Id in the last line of the commit message to the Change-Id already in its database. These steps assumed you were working on a topic branch. And you had your [[ITK/Gerrit/Primer#Prerequisites|gerrit hook setup]].
==== Stage changes into the ITK official repository ====
Once the code has been reviewed, it is now time to migrate the changes into the ITK repository.  This topic is [[ITK/Git#Topic_Stage|covered in detail elsewhere]].  Only a developer with commit access to ITK can perform this step.
The steps required to stage and push into ITK include pushing your local changes into the ITK staging area.  Then issuing a command over SSH to instruct the ITK robot to merge the changes.  Assuming you have your remote ITK git checkout [[ITK/Git#Topic_Stage|configured correctly]]:
git push stage HEAD              # Push your current work into the staging area for ITK
ssh stage ITK print  # Print the list of staged changes
ssh stage ITK merge topic-name  # Merge your topic into the ITK main.
==== Pull new changes from ITK repository ====
Once changes have been pushed to the official repository, you must pull them back into your local clone:
git pull
== Conclusion ==
Hopefully this primer has been useful to distill some experiences using Gerrit and git into a central location.  Gerrit and git are a potent combination, but require a little knowledge and know-how to be used effectively.

Latest revision as of 17:30, 3 June 2011

This page previously contained information on use of Gerrit for ITK. The old information has been removed to avoid confusion. Please get started here instead.