Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 1 | = Gerrit Code Review - A Quick Introduction |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 2 | |
| 3 | Gerrit is a web-based code review tool built on top of the git version |
| 4 | control system, but if you've got as far as reading this guide then |
| 5 | you probably already know that. The purpose of this introduction is to |
| 6 | allow you to answer the question, is Gerrit the right tool for me? |
| 7 | Will it fit in my work flow and in my organization? |
| 8 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 9 | == What is Gerrit? |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 10 | |
David Pursehouse | 98fef39 | 2014-05-13 16:59:29 +0900 | [diff] [blame] | 11 | It is assumed that if you're reading this then you're already convinced |
| 12 | of the benefits of code review in general but want some technical support |
| 13 | to make it easy. |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 14 | |
David Pursehouse | 98fef39 | 2014-05-13 16:59:29 +0900 | [diff] [blame] | 15 | Code reviews mean different things to different people. To some it's a |
| 16 | formal meeting with a projector and an entire team going through the code |
| 17 | line by line. To others it's getting someone to glance over the code before |
| 18 | it is committed. |
| 19 | |
| 20 | Gerrit is intended to provide a lightweight framework for reviewing |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 21 | every commit before it is accepted into the code base. Changes are |
| 22 | uploaded to Gerrit but don't actually become a part of the project |
| 23 | until they've been reviewed and accepted. In many ways this is simply |
| 24 | tooling to support the standard open source process of submitting |
| 25 | patches which are then reviewed by the project members before being |
| 26 | applied to the code base. However Gerrit goes a step further making it |
| 27 | simple for all committers on a project to ensure that changes are |
| 28 | checked over before they're actually applied. Because of this Gerrit |
| 29 | is equally useful where all users are trusted committers such as may |
David Pursehouse | 221d4f6 | 2012-06-08 17:38:08 +0900 | [diff] [blame] | 30 | be the case with closed-source commercial development. Either way it's |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 31 | still desirable to have code reviewed to improve the quality and |
| 32 | maintainability of the code. After all, if only one person has seen |
| 33 | the code it may be a little difficult to maintain when that person |
| 34 | leaves. |
| 35 | |
| 36 | Gerrit is firstly a staging area where changes can be checked over |
| 37 | before becoming a part of the code base. It is also an enabler for |
| 38 | this review process, capturing notes and comments about the changes to |
| 39 | enable discussion of the change. This is particularly useful with |
| 40 | distributed teams where this conversation can't happen face to face. |
| 41 | Even with a co-located team having a review tool as an option is |
| 42 | beneficial because reviews can be done at a time that is convenient |
| 43 | for the reviewer. This allows the developer to create the review and |
| 44 | explain the change while it is fresh in their mind. Without such a |
| 45 | tool they either need to interrupt someone to review the code or |
| 46 | switch context to explain the change when they've already moved on to |
| 47 | the next task. |
| 48 | |
| 49 | This also creates a lasting record of the conversation which can be |
| 50 | useful for answering the inevitable "I know we changed this for a |
| 51 | reason" questions. |
| 52 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 53 | == Where does Gerrit fit in? |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 54 | |
| 55 | Any team with more than one member has a central source repository of |
| 56 | some kind (or they should). Git can theoretically work without such a |
| 57 | central location but in practice there is usually a central |
| 58 | repository. This serves as the authoritative copy of what is actually in |
| 59 | the project. This is what everyone fetches from and pushes to and is |
| 60 | generally where build servers and other such tools get the source |
| 61 | from. |
| 62 | |
| 63 | .Central Source Repository |
| 64 | image::images/intro-quick-central-repo.png[Authoritative Source Repository] |
| 65 | |
| 66 | Gerrit is deployed in place of this central repository and adds an |
| 67 | additional concept, a store of pending changes. Everyone still fetches |
| 68 | from the authoritative repository but instead of pushing back to it, |
| 69 | they push to this pending changes location. A change can only be submitted |
| 70 | into the authoritative repository and become an accepted part of the project |
| 71 | once the change has been reviewed and approved. |
| 72 | |
| 73 | .Gerrit in place of Central Repository |
| 74 | image::images/intro-quick-central-gerrit.png[Gerrit in place of Central Repository] |
| 75 | |
| 76 | Like any repository hosting solution, Gerrit has a powerful |
| 77 | link:access-control.html[access control model.] |
| 78 | Users can even be granted access to push directly into the central |
| 79 | repository, bypassing code review entirely. Gerrit can even be used |
| 80 | without code review, used simply to host the repositories and |
| 81 | controlling access. But generally it's just simpler and safer to go |
| 82 | through the review process even for users who are allowed to directly |
| 83 | push. |
| 84 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 85 | == The Life and Times of a Change |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 86 | |
| 87 | The easiest way to get a feel for how Gerrit works is to follow a |
| 88 | change through its entire life cycle. For the purpose of this example |
| 89 | we'll assume that the Gerrit Server is running on a server called |
| 90 | +gerrithost+ with the HTTP interface on port +8080+ and the SSH |
| 91 | interface on port +29418+. The project we'll be working on is called |
| 92 | +RecipeBook+ and we'll be developing a change for the +master+ branch. |
| 93 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 94 | === Cloning the Repository |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 95 | |
| 96 | Obviously the first thing we need to do is get the source that we're |
| 97 | going to be modifying. As with any git project you do this by cloning |
| 98 | the central repository that Gerrit is hosting. e.g. |
| 99 | |
| 100 | ---- |
| 101 | $ git clone ssh://gerrithost:29418/RecipeBook.git RecipeBook |
| 102 | Cloning into RecipeBook... |
| 103 | ---- |
| 104 | |
| 105 | Then we need to make our actual change and commit it locally. Gerrit |
| 106 | doesn't really change anything here, this is just the standard editing |
| 107 | and git. While not strictly required, it's best to include a Change-Id |
| 108 | in your commit message so that Gerrit can link together different |
| 109 | versions of the same change being reviewed. Gerrit contains a standard |
| 110 | link:user-changeid.html[Change-Id commit-msg hook] |
| 111 | that will generate a unique Change-Id when you commit. If you don't do |
| 112 | this then Gerrit will generate a Change-Id when you push your change |
| 113 | for review. But because you don't have the Change-Id in your commit |
| 114 | message you'll need to manually copy it in if you need to upload |
| 115 | another version of your change. Because of this it's best to just |
| 116 | install the hook and forget about it. |
| 117 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 118 | === Creating the Review |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 119 | |
| 120 | Once you've made your change and committed it locally it's time to |
| 121 | push it to Gerrit so that it can be reviewed. This is done with a git |
| 122 | push to the Gerrit server. Since we cloned our local repository |
| 123 | directly from Gerrit it is the origin so we don't have to redefine the |
| 124 | remote. |
| 125 | |
| 126 | ---- |
| 127 | $ <work> |
| 128 | $ git commit |
| 129 | [master 9651f22] Change to a proper, yeast based pizza dough. |
| 130 | 1 files changed, 3 insertions(+), 2 deletions(-) |
| 131 | $ git push origin HEAD:refs/for/master |
| 132 | Counting objects: 5, done. |
| 133 | Delta compression using up to 8 threads. |
| 134 | Compressing objects: 100% (2/2), done. |
| 135 | Writing objects: 100% (3/3), 542 bytes, done. |
| 136 | Total 3 (delta 0), reused 0 (delta 0) |
Robin Rosenberg | 524a303 | 2012-10-14 14:24:36 +0200 | [diff] [blame] | 137 | remote: |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 138 | remote: New Changes: |
| 139 | remote: http://gerrithost:8080/68 |
Robin Rosenberg | 524a303 | 2012-10-14 14:24:36 +0200 | [diff] [blame] | 140 | remote: |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 141 | To ssh://gerrithost:29418/RecipeBook.git |
| 142 | * [new branch] HEAD -> refs/for/master |
| 143 | ---- |
| 144 | |
| 145 | The only different thing about this is the +refs/for/master+ branch. |
| 146 | This is a magic branch that creates reviews that target the master |
| 147 | branch. For every branch Gerrit tracks there is a magic |
| 148 | +refs/for/<branch_name>+ that you push to to create reviews. |
| 149 | |
| 150 | In the output of this command you'll notice that there is a link to |
| 151 | the HTTP interface of the Gerrit server we just pushed to. This is the |
| 152 | web interface where we will review this commit. Let's follow that link |
| 153 | and see what we get. |
| 154 | |
| 155 | .Gerrit Code Review Screen |
| 156 | image::images/intro-quick-new-review.jpg[Gerrit Review Screen] |
| 157 | |
| 158 | This is the Gerrit code review screen where someone will come to |
| 159 | review the change. There isn't too much to see here yet, you can look |
| 160 | at the diff of your change, add some comments explaining what you did |
| 161 | and why, you may even add a list of people that should review the change. |
| 162 | |
| 163 | Reviewers can find changes that they want to review in any number of |
David Pursehouse | 98fef39 | 2014-05-13 16:59:29 +0900 | [diff] [blame] | 164 | ways. Gerrit has a capable link:user-search.html[search] |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 165 | that allows project leaders (or anyone else) to find changes that need |
| 166 | to be reviewed. Users can also setup watches on Gerrit projects with a |
| 167 | search expression, this causes Gerrit to notify them of matching |
| 168 | changes. So adding a reviewer when creating a review is just a |
| 169 | recommendation. |
| 170 | |
| 171 | At this point the change is available for review and we need to switch |
| 172 | roles to continue following the change. Now let's pretend we're the |
| 173 | reviewer. |
| 174 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 175 | === Reviewing the Change |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 176 | |
| 177 | The reviewer's life starts at the code review screen shown above. He |
| 178 | can get here in a number of ways, but for some reason they've decided |
| 179 | to review this change. Of particular note on this screen are the two |
| 180 | "Need" lines: |
| 181 | |
| 182 | ---- |
| 183 | * Need Verified |
| 184 | * Need Code-Review |
| 185 | ---- |
| 186 | |
| 187 | Gerrit's default work-flow requires two checks before a change is |
| 188 | accepted. Code-Review is someone looking at the code, ensuring it |
| 189 | meets the project guidelines, intent etc. Verifying is checking that |
| 190 | the code actually compiles, unit tests pass etc. Verification is |
| 191 | usually done by an automated build server rather than a person. There |
| 192 | is even a |
| 193 | link:https://wiki.jenkins-ci.org/display/JENKINS/Gerrit+Trigger[Gerrit Trigger Jenkins Plugin] |
| 194 | that will automatically build each uploaded change and update the |
| 195 | verified score accordingly. |
| 196 | |
| 197 | It is important to note that Code-Review and Verification are |
| 198 | different permissions in Gerrit, allowing these tasks to be separated. |
| 199 | For example, an automated process would have rights to verify but not |
| 200 | to code-review. |
| 201 | |
| 202 | Since we are the code reviewer, we're going to review the code. To do |
| 203 | this we can view it within the Gerrit web interface as either a |
| 204 | unified or side-by-side diff by selecting the appropriate option. In |
| 205 | the example below we've selected the side-by-side view. In either of |
Bruce Zu | 6b0fd76 | 2012-10-25 16:52:00 +0800 | [diff] [blame] | 206 | these views you can add inline comments by double clicking on the line |
| 207 | (or single click the line number) that you want to comment on. Also you |
| 208 | can add file comment by double clicking anywhere (not just on the |
| 209 | "Patch Set" words) in the table header or single clicking on the icon |
| 210 | in the line-number column header. Once published these comments are |
| 211 | viewable to all, allowing discussion of the change to take place. |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 212 | |
| 213 | .Side By Side Patch View |
| 214 | image::images/intro-quick-review-line-comment.jpg[Adding a Comment] |
| 215 | |
| 216 | Code reviewers end up spending a lot of time navigating these screens, |
| 217 | looking at and commenting on these changes. To make this as efficient |
| 218 | as possible Gerrit has keyboard shortcuts for most operations (and |
| 219 | even some operations that are only accessible via the hot-keys). At |
| 220 | any time you can hit the +?+ key to see the keyboard shortcuts. |
| 221 | |
| 222 | .Gerrit Hot Key Help |
| 223 | image::images/intro-quick-hot-key-help.jpg[Hot Key Help] |
| 224 | |
| 225 | Once we've looked over the changes we need to complete reviewing the |
| 226 | submission. To do this we click the _Review_ button on the change |
| 227 | screen where we started. This allows us to enter a Code Review label |
| 228 | and message. |
| 229 | |
| 230 | .Reviewing the Change |
| 231 | image::images/intro-quick-reviewing-the-change.jpg[Reviewing the Change] |
| 232 | |
| 233 | The label that the reviewer selects determines what can happen next. |
| 234 | The +1 and -1 level are just an opinion where as the +2 and -2 levels |
| 235 | are allowing or blocking the change. In order for a change to be |
| 236 | accepted it must have at least one +2 and no -2 votes. |
| 237 | Although these are numeric values, they in no way accumulate; |
| 238 | two +1s do not equate to a +2. |
| 239 | |
| 240 | Regardless of what label is selected, once the _Publish Comments_ |
| 241 | button has been clicked, the cover message and any comments on the |
| 242 | files become visible to all users. |
| 243 | |
| 244 | In this case the change was not accepted so the creator needs to |
| 245 | rework it. So let's switch roles back to the creator where we |
| 246 | started. |
| 247 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 248 | === Reworking the Change |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 249 | |
| 250 | As long as we set up the |
| 251 | link:user-changeid.html[Change-Id commit-msg hook] |
| 252 | before we uploaded the change, re-working it is easy. All we need |
| 253 | to do to upload a re-worked change is to push another commit that has |
David Pursehouse | 2c6f638 | 2014-09-04 13:06:19 +0900 | [diff] [blame] | 254 | the same Change-Id in the message. Since the hook added a Change-Id in |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 255 | our initial commit we can simply checkout and then amend that commit. |
| 256 | Then push it to Gerrit in the same way as we did to create the review. E.g. |
| 257 | |
| 258 | ---- |
| 259 | $ <checkout first commit> |
| 260 | $ <rework> |
| 261 | $ git commit --amend |
| 262 | $ git push origin HEAD:refs/for/master |
| 263 | Counting objects: 5, done. |
| 264 | Delta compression using up to 8 threads. |
| 265 | Compressing objects: 100% (2/2), done. |
| 266 | Writing objects: 100% (3/3), 546 bytes, done. |
| 267 | Total 3 (delta 0), reused 0 (delta 0) |
Edwin Kempin | ef12658 | 2014-05-13 12:31:38 +0200 | [diff] [blame] | 268 | remote: Processing changes: updated: 1, done |
| 269 | remote: |
| 270 | remote: Updated Changes: |
| 271 | remote: http://gerrithost:8080/68 |
| 272 | remote: |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 273 | To ssh://gerrithost:29418/RecipeBook.git |
| 274 | * [new branch] HEAD -> refs/for/master |
| 275 | ---- |
| 276 | |
Edwin Kempin | ef12658 | 2014-05-13 12:31:38 +0200 | [diff] [blame] | 277 | Note that the output is slightly different this time around. Since |
| 278 | we're adding to an existing review it tells us that the change was |
| 279 | updated. |
| 280 | |
| 281 | Having uploaded the reworked commit we can go back into the Gerrit web |
| 282 | interface and look at our change. |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 283 | |
| 284 | .Reviewing the Rework |
| 285 | image::images/intro-quick-review-2-patches.jpg[Reviewing the Rework] |
| 286 | |
| 287 | If you look closely you'll notice that there are now two patch sets |
| 288 | associated with this change, the initial submission and the rework. |
| 289 | Rather than repeating ourselves lets assume that this time around the |
| 290 | patch is given a +2 score by the code reviewer. |
| 291 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 292 | === Trying out the Change |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 293 | |
| 294 | With Gerrit's default work-flow there are two sign-offs, code review |
| 295 | and verify. Verifying means checking that the change actually works. |
| 296 | This would typically be checking that the code compiles, unit tests |
| 297 | pass and similar checks. Really a project can decide how much or |
| 298 | little they want to do here. It's also worth noting that this is only |
| 299 | Gerrit's default work-flow, the verify check can actually be removed |
| 300 | or others added. |
| 301 | |
| 302 | As mentioned in the code review section, verification is typically an |
| 303 | automated process using the |
| 304 | link:https://wiki.jenkins-ci.org/display/JENKINS/Gerrit+Trigger[Gerrit Trigger Jenkins Plugin] |
| 305 | or similar. But there are times when the code needs to be manually |
| 306 | verified, or the reviewer needs to check that something actually works |
| 307 | or how it works. Sometimes it's just nice to work through the code in a |
| 308 | development environment rather than the web interface. All of these |
| 309 | involve someone needing to get the change into their development |
| 310 | environment. Gerrit makes this process easy by exposing each change as |
| 311 | a git branch. So all the reviewers need to do is fetch and checkout that |
| 312 | branch from Gerrit and they will have the change. |
| 313 | |
| 314 | We don't even need to think about it that hard, if you look at the |
David Pursehouse | 98fef39 | 2014-05-13 16:59:29 +0900 | [diff] [blame] | 315 | earlier screenshots of the Gerrit Code Review Screen you'll notice a |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 316 | _download_ command. All we need to do to get the change is copy |
| 317 | paste this command and run it in our Gerrit checkout. |
| 318 | |
| 319 | ---- |
| 320 | $ git fetch http://gerrithost:8080/p/RecipeBook refs/changes/68/68/2 |
| 321 | From http://gerrithost:8080/p/RecipeBook |
| 322 | * branch refs/changes/68/68/2 -> FETCH_HEAD |
| 323 | $ git checkout FETCH_HEAD |
| 324 | Note: checking out 'FETCH_HEAD'. |
| 325 | |
| 326 | You are in 'detached HEAD' state. You can look around, make experimental |
| 327 | changes and commit them, and you can discard any commits you make in this |
| 328 | state without impacting any branches by performing another checkout. |
| 329 | |
| 330 | If you want to create a new branch to retain commits you create, you may |
| 331 | do so (now or later) by using -b with the checkout command again. Example: |
| 332 | |
| 333 | git checkout -b new_branch_name |
| 334 | |
| 335 | HEAD is now at d5dacdb... Change to a proper, yeast based pizza dough. |
| 336 | ---- |
| 337 | |
| 338 | Easy as that, we now have the change in our working copy to play with. |
| 339 | You might be interested in what the numbers of the refspec mean. |
| 340 | |
David Pursehouse | 221d4f6 | 2012-06-08 17:38:08 +0900 | [diff] [blame] | 341 | * The first *68* is the id of the change +mod 100+. The only reason |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 342 | for this initial number is to reduce the number of files in any given |
| 343 | directory within the git repository. |
| 344 | * The second *68* is the full id of the change. You'll notice this in |
| 345 | the URL of the Gerrit review screen. |
| 346 | * The *2* is the patch-set within the change. In this example we |
| 347 | uploaded some fixes so we want the second patch set rather than the |
| 348 | initial one which the reviewer rejected. |
| 349 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 350 | === Manually Verifying the Change |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 351 | |
| 352 | For simplicity we're just going to manually verify the change. |
| 353 | The Verifier may be the same person as the code reviewer or a |
| 354 | different person entirely. It really depends on the size of the |
| 355 | project and what works. If you have Verify permission then when you |
| 356 | click the _Review_ button in the Gerrit web interface you'll be |
| 357 | presented with a verify score. |
| 358 | |
| 359 | .Verifying the Change |
| 360 | image::images/intro-quick-verifying.jpg[Verifying the Change] |
| 361 | |
| 362 | Unlike the code review the verify check doesn't have a +2 or -2 level, |
| 363 | it's either a pass or fail so all we need for the change to be |
| 364 | submitted is a +1 score (and no -1's). |
| 365 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 366 | === Submitting the Change |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 367 | |
| 368 | You might have noticed that in the verify screen shot there are two |
| 369 | buttons for submitting the score _Publish Comments_ and _Publish |
| 370 | and Submit_. The publish and submit button is always visible, but will |
| 371 | only work if the change meets the criteria for being submitted (I.e. |
| 372 | has been both verified and code reviewed). So it's a convenience to be |
| 373 | able to post review scores as well as submitting the change by clicking |
| 374 | a single button. If you choose just to publish comments at this point then |
| 375 | the score will be stored but the change won't yet be accepted into the code |
| 376 | base. In this case there will be a _Submit Patch Set X_ button on the |
Dave Borowitz | 01c1b1f | 2013-02-27 13:49:04 -0800 | [diff] [blame] | 377 | main screen. Just as Code-Review and Verify are different operations |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 378 | that can be done by different users, Submission is a third operation |
| 379 | that can be limited down to another group of users. |
| 380 | |
David Pursehouse | 221d4f6 | 2012-06-08 17:38:08 +0900 | [diff] [blame] | 381 | Clicking the _Publish and Submit_ or _Submit Patch Set X_ button |
Ed Costello | 7407a92 | 2011-07-23 21:38:42 +1200 | [diff] [blame] | 382 | will merge the change into the main part of the repository so that it |
| 383 | becomes an accepted part of the project. After this anyone fetching |
| 384 | the git repository will receive this change as a part of the master |
| 385 | branch. |
| 386 | |
| 387 | GERRIT |
| 388 | ------ |
| 389 | Part of link:index.html[Gerrit Code Review] |
Yuxuan 'fishy' Wang | 99cb68d | 2013-10-31 17:26:00 -0700 | [diff] [blame] | 390 | |
| 391 | SEARCHBOX |
| 392 | --------- |