| name | gerrit-workflow |
| description | This skill should be used when the user asks to "submit a change to Gerrit", "push for review", "upload a patch", "update a change in Gerrit", "add a patch set", "work with Gerrit", "push to refs/for", "fix a missing Change-Id", "amend a Gerrit change", or any task involving git operations in a repository hosted on Gerrit Code Review. Also use when the user encounters Gerrit push errors such as "missing Change-Id in commit message footer" or "prohibited by Gerrit". |
| allowed-tools | Bash, Read |
Gerrit Workflow
Gerrit is a code review system that sits in front of a git repository. The key
difference from GitHub/GitLab: changes go through a review queue before
landing in the branch. This changes several git workflows in important ways.
Core Concepts
Changes and Patch Sets
A Change is the unit of review in Gerrit — it corresponds to one logical
commit. Each change has:
- A numeric Change number (e.g.,
12345)
- A Change-Id trailer in the commit message (e.g.,
Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b)
When a commit is revised and re-uploaded, the new version becomes a new patch
set on the same change. Gerrit associates them via the Change-Id trailer —
this is what makes the Change-Id essential.
The Magic refs/for/<branch> Ref
Gerrit intercepts pushes to refs/for/<branch>. These pushes never actually
create that ref; instead Gerrit creates or updates a Change for review. To land
code in master:
# NOT this (bypasses review):
git push origin HEAD:refs/heads/master
# This — submits for review:
git push origin HEAD:refs/for/master
The commit-msg Hook
Gerrit provides a commit-msg hook that auto-inserts Change-Id trailers.
Without it, the Change-Id must be added manually. To install:
curl -Lo .git/hooks/commit-msg <gerrit-url>/tools/hooks/commit-msg
chmod u+x .git/hooks/commit-msg
scp -p -P 29418 <user>@<gerrit-host>:hooks/commit-msg .git/hooks/
chmod u+x .git/hooks/commit-msg
Check if it is already installed:
ls -la .git/hooks/commit-msg
Common Workflows
1. Create a New Change
git add <files>
git commit -m "Fix the foo widget"
git log -1
git push origin HEAD:refs/for/master
The server prints the URL of the new change.
2. Update an Existing Change (New Patch Set)
After receiving review feedback, amend the commit. Do not modify or remove the
Change-Id line — Gerrit uses it to associate the new commit with the
existing change.
git add <files>
git commit --amend
git push origin HEAD:refs/for/master
3. Work on Multiple Independent Changes
Each change should be its own commit on its own local branch:
git checkout -b fix-foo origin/master
git checkout -b fix-bar origin/master
Do not stack unrelated changes on a single branch unless they are intentionally
dependent (see below).
4. Dependent / Stacked Changes
Gerrit supports chains of dependent changes. Push multiple commits in one push;
Gerrit creates one change per commit, linked in a relation chain:
git checkout -b feature origin/master
git commit -m "Step 1: add plumbing"
git commit -m "Step 2: wire up the UI"
git push origin HEAD:refs/for/master
Each change can be reviewed and submitted independently, but Gerrit shows the
dependency chain.
5. Rebase and Re-push
When the target branch has moved on, rebase and re-push. Keep Change-Ids intact:
git fetch origin
git rebase origin/master
git push origin HEAD:refs/for/master
6. Squashing Commits Before Push
When squashing several commits, keep exactly one Change-Id — prefer the
one already known to Gerrit (i.e., the one that was previously pushed, if any).
Remove the others:
git rebase -i origin/master
git push origin HEAD:refs/for/master
7. Cherry-pick to Another Branch
To propose the same fix on a maintenance branch, cherry-pick and generate a
new Change-Id (delete the old one so the hook creates a fresh one):
git checkout -b backport-3.10 origin/stable-3.10
git cherry-pick <commit-sha>
git commit --amend
git push origin HEAD:refs/for/stable-3.10
Or, keep the original Change-Id to have Gerrit treat it as a replacement for the
same change on that branch.
Push Options
Additional metadata can be sent with the push via % options or -o:
git push origin HEAD:refs/for/master%topic=my-feature
git push origin HEAD:refs/for/master%r=alice@example.com,cc=bob@example.com
git push origin HEAD:refs/for/master%wip
git push origin HEAD:refs/for/master%ready
git push origin HEAD:refs/for/master%l=Verified+1
git push origin HEAD:refs/for/master%notify=NONE
git push origin HEAD:refs/for/master%topic=my-feature,r=alice@example.com
Fetching Changes
To check out an existing change locally (e.g., to test it):
git fetch origin refs/changes/45/12345/3 && git checkout FETCH_HEAD
Common Errors and Fixes
missing Change-Id in commit message footer
The commit has no Change-Id. Fix:
git commit --amend --no-edit
git commit --amend
! [remote rejected] ... (prohibited by Gerrit)
Direct push to refs/heads/* was rejected. Push to refs/for/<branch> instead.
Change xxx: patch set already exists
The commit hash hasn't changed since the last push (no new patch set was made).
Amend the commit to create a distinct object, then push again.
! [remote rejected] ... (no new changes)
All commits being pushed are already known to Gerrit. This often means the
branch is already up to date with the target.
Critical Rules
- Never push directly to
refs/heads/* unless intentionally bypassing
review (requires special permissions).
- Never change or remove the
Change-Id trailer when amending a commit that
is already under review — doing so creates a second, orphaned change.
- One logical change = one commit. Gerrit reviews commits, not branches.
- Always verify
Change-Id is present with git log -1 before pushing.
- Keep Change-Ids when rebasing — git preserves them through rebase
automatically.
Additional Resources
references/gerrit-vs-github.md — Side-by-side comparison of Gerrit and
GitHub/GitLab workflows for common tasks
references/change-id-details.md — Deep dive on Change-Id: creation,
squashing, cherry-picks, and edge cases