Introduction to Git & Gerrit for CrOS contributors
This guide provides a brief guide to creating Git commits and getting them reviewed on Gerrit, for those who have not used either system before. It assumes that you’ve already got a local copy of the repository you want to modify, and have set up your Gerrit credentials. For more details on the topics that this guide skims over (such as the commit queue and the review process) see the Contributing Guide.
Terms
We’ll be talking about two related but separate systems here:
Git is a version control system, in many ways similar to SVN, except that Git repositories do not need to be hosted on one central server; instead, you have a local copy which can pull from many servers, called remotes. It's strongly recommended to read this introductory presentation for more in-depth information including an explanation of the concepts and workflows.
Gerrit is a Git remote which hosts the code and makes it easier to manage code reviews. Many different projects host instances for their code, but mostly I’ll be referring to the Chromium Gerrit instance when I mention it here. For more details, see this introductory presentation that goes into more detail about the concepts and workflows.
Make and commit some changes
In your local copy of your repository, make some changes, then run git status
.
Here’s some sample output (in this example we'll be committing some files in the
chip/max32660
directory):
$ git status
On branch main
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: foo.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
chip/max32660/
no changes added to commit (use "git add" and/or "git commit -a")
This output tells us that a file that Git already tracks (foo.txt
) has been
modified, and a directory has been created that Git hasn’t seen before
(chip/max32660/
). We need to create a commit that contains these changes. To
do that, we first tell Git what we want to include in this commit:
$ git add chip/max32660/build.mk
$ git add chip/max32660/max32660.h
…
Now, when we run git status
, we see that some changes have been added. (In Git
terms, we say that they are staged.)
$ git status
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: chip/max32660/build.mk
modified: chip/max32660/max32660.h
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: foo.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
chip/max32660/foo.h
chip/max32660/foo.c
...
no changes added to commit (use "git add" and/or "git commit -a")
We’re almost ready to make a commit, but notice that we’re currently on the
branch called main
. (Older versions of Git may call this master
instead.) Most changes end up on main
eventually, but for now we want to put
them on a different local branch (often called a feature branch) while
they’re in review. So, let’s create one called max32660-basics
and switch to
it:
$ git checkout -b max32660-basics
$ git status
On branch max32660-basics
...
Now we can make the commit. When you run this command, a text editor will appear:
$ git commit
In the editor, add a message for your commit. See
the Commit messages section of the Contributing Guide
for suggestions on what to put in it. (No need to add the Change-Id
line shown
there, Gerrit will do that for you.)
When you’re done, save the file and close your editor. The commit has now been
made. (You can see it in git log
.)
Uploading your branch as a changelist
Now you’ve got a branch with a commit in it, and you want to upload it to Gerrit for review. Gerrit’s unit of code review is called a changelist (often abbreviated to CL), and you can create one from your branch. First, let’s make sure that you have Gerrit set up as a remote.
Check your repository’s remotes
If you downloaded the repository by using git clone
or repo
, you probably
already have Gerrit set up as a remote. Check with the git remote -v
command,
and note the name of the remote (cros
in this case):
$ git remote -v
cros https://chromium.googlesource.com/chromiumos/platform/ec (fetch)
cros https://chromium.googlesource.com/chromiumos/platform/ec (push)
If you don’t see a suitable remote, you can add one (replacing platform/ec
with the appropriate path for the repository you're working in):
$ git remote add cros https://chromium.googlesource.com/chromiumos/platform/ec
Uploading the code
First, check that you’re on your feature branch by running git status
and
checking the first line. (If you’re on the wrong branch, use git checkout <branch name>
to get back to the right one.)
You'll need the repo
command for this step. repo
is a tool that makes it
easier to manage multiple related Git repositories, but we'll just be using it
to upload our change and run presubmit checks. If you don't have it, you can
get it by installing depot_tools
.
First, set your branch’s upstream. This tells repo
what version of the code it
should compare your current state with. You’ll probably want the following
command (assuming that your remote is called cros
):
$ git branch --set-upstream-to=cros/main
Now you can tell repo
to upload your change:
$ repo upload . --br=max32660-basics
When asked whether to run the checks, enter yes
. If the checks find any
problems, they will tell you about them and the change will not be uploaded.
Once you've fixed them you can run the command again. Sometimes it will warn
about things that can't be fixed given the circumstances, in which case add
--ignore-hooks
to the command (though you should probably amend your commit
message to explain why).
Adding reviewers
Whichever method you use, you should see some output like this if all goes well:
Upload project src/platform/ec/ to remote branch refs/heads/main:
branch max32660-basics ( 1 commit, Wed Jun 5 12:14:47 2019 -0700):
7d244dd1 Add basic support for MAX32660
to https://chrome-internal-review.googlesource.com (y/N)? y
remote: Processing changes: refs: 1, new: 1, done
remote:
remote: SUCCESS
remote:
remote: https://chrome-internal-review.googlesource.com/c/chromeos/platform/ec/+/1234567 Add basic support for MAX32660 [NEW]
remote:
To https://chrome-internal-review.googlesource.com/chromeos/platform/ec
* [new branch] max32660-basics -> refs/for/main
Here, the URL
https://chrome-internal-review.googlesource.com/c/chromeos/platform/ec/+/1234567
is the one for your change. Open it in your browser to see the change.
Now, if you’re signed in to Gerrit, you can request that one or more other Gerrit users review the CL. Click “Reply” and add the reviewers you want to the “Reviewers” line.
Updating your changelist
Once you’ve sent your CL for review, your reviewers will probably leave comments on it, suggesting improvements. Once you’ve made the changes they asked for, you need to update the CL in Gerrit.
Modifying your commit
To do this, we need to modify the commit you created the CL from. First, let’s
check that the commit has the Change ID line that Gerrit uses to identify it.
Run git log
and look for a line beginning Change-Id:
in the message. With
that verified, let’s go ahead and modify the commit.
Amending
If you haven’t committed your recent changes yet, this is really simple. Use
git add
as before to stage the changes, but then instead of creating a new
commit, change the existing one:
$ git commit --amend
The commit message editor will appear again, prefilled with your existing
message. If you want to change the commit message, do so now (but make sure to
leave the Change-Id:
line intact). Then save and close the editor as before.
Rebasing
If you’ve already made additional commits on the branch, all is not lost. We can combine them together after the fact, using a rebase:
$ git rebase -i main
(Yes, that should be main
, even though you’re on a branch, as we’re telling
the rebase command to look at all the commits between this branch head and the
main branch.)
A text editor should appear, prepopulated with a list of commits, something like the following:
pick 7d244dd12 Add basic support for MAX32660
pick 2e0a4ea43 Fix some review comments
pick 46d8c0a28 Fix some more comments
# Rebase 29e7e6eec..46d8c0a28 onto 29e7e6eec (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
The first line will be your original commit, which we want to combine everything
in to. To do that, simply replace pick
with fixup
on all the lines below
it. Then, save and close the editor. Git will go through and do the combining.
(If you want to change the commit message too, just run git commit --amend
at
this point.)
Uploading again
Now that you’ve modified the commit, re-upload it using the same repo upload
command you used before.
Once the upload is done, open your CL in Gerrit again. You should see that it now has another patch set. A patch set is Gerrit’s name for a version of a changelist, and Gerrit allows you (and your reviewers) to see what you’ve changed between patch sets.
Respond to reviewer comments
To make it easier to see what’s going on, reply to your reviewers’ comments. This is very important to make it easier for both you and your reviewers to keep track of what's happening. If you’ve done what they asked for, click “Done” and Gerrit will mark the comment as resolved. Otherwise you can reply explaining why you think their suggestion won’t work or isn’t a good idea. Once you’re done, click the blue “Reply” button at the top of the page to send your responses.
Submitting the CL
To be submitted, your CL must have a Code-Review +2 from at least one reviewer, and Verified +1 from anybody (including yourself). Once it has those, reply to the CL adding Commit-Queue +2 to start the submission process. Assuming that the tests pass, you will get an email some time later telling you that the CL has been submitted.
Getting ready to start again
You probably want to build on the code that you just submitted in your next CL.
To do this, you’ll need to update your local copy of the main branch to include
the changes that have just been merged. Checkout main, then tell repo
to
synchronise your repositories:
$ git checkout main
$ repo sync
(If you’ve got other stuff going on in your ChromiumOS tree, you might find it helpful to split repo sync into two stages.)
Rinse and repeat
If you run git log
now, your CL should appear somewhere in the list. (It might
be quite far down depending on how busy the repository is and how long it’s been
since it was submitted.) Now you can create another feature branch and start
again, building on the changes you’ve already submitted.