gh-ish (./gh): Gerrit with GitHub CLI Ergonomics
SkillDev toolsLets your agent manage Gerrit code reviews, CI checks, and push changes using familiar GitHub CLI-style commands.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the gh-ish (./gh): Gerrit with GitHub CLI Ergonomics skill
About this capability
Use the ./gh CLI (gh-ish) for Gerrit code reviews, CI checks, and pushing changes using GitHub CLI syntax.
What this skill tells your AI
The instructions your AI receives, as published by pigweed-project/pigweed in .agents/skills/ghish/SKILL.md and read by ahel’s review.
Pigweed provides ./gh (a zero-overhead cached repository wrapper around
//pw_ghish:gh-ish), exposing Gerrit code reviews and LUCI Buildbucket checks
through standard GitHub CLI (gh pr) syntax.
This skill is the single source of truth for Gerrit workflows in Pigweed,
completely replacing legacy raw git push, manual curl commands, and
.gitcookies scripts.
Quick Command Reference
All commands run via ./gh pr <subcommand> (or standalone
gh-ish pr <subcommand>):
1. Change Targeting & Inspection
Subcommands accepting [<id>] support:
- Omitted argument: Automatically resolves the active change on the current Git branch.
- Change number:
472267or with patchset472267/3. - Gerrit URL:
https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/472267(or/+/472267/3). - Shortlink:
pwrev/472267,pwrev.dev/472267,pwrev.dev/i/472267(internal review),fxrev/472267,fxrev.dev/i/472267,crrev.com/c/472267. - Branch name:
my-feature,cl/472267,change-472267(resolves via branch commitChange-Idorbranch.<name>.gerrit-change-idconfig).
Commands:
./gh pr view [<id>]: View change metadata (patchset, owner, reviewers, attention set, status, labels). Defaults to active change on current branch.-c, --comments: Display all file and inline comment threads indented by file and line number.--json <fields>: Output structured JSON (e.g.number,title,state,author,files,reviewers). Unknown fields are strictly rejected.--json bug,bugs: Read back the linked bugs — the Gerrit counterpart to GitHub'sclosingIssuesReferences.bugis a flat"b/123456, b/789"string;bugsis[{"id": "b/123456", "closes": true}], whereclosesdistinguishes aFixed:trailer (closes the bug on submit) from aBug:trailer (links only). Use this to verify a./gh pr edit --bugactually took, and to check whether a bug is already linked before adding one. Asking for these when Gerrit returned no commit message is an error, not an empty answer, so an emptybugalways means "genuinely nothing linked".
./gh pr diff [<id>[/<patchset>]]: View unified patch diff. Defaults to active change on current branch../gh pr checkout [<id>[/<patchset>]]: Fetch and check out change branch or specific patchset locally atFETCH_HEAD. Defaults to active change on current branch.
2. Push & Edit
./gh pr create: Push local commit(s) to Gerrit as a new change.- Safety Guard: Fails with a clear error and URL if the change already
exists (use
pr pushto update existing changes). - Stack Guard: Halts if pushing multiple commits unless
--stackis specified. -r, --reviewer <email>: Add reviewer to change.-c, --cc <email>: Add CC to change.--auto: Set auto-submit label (+1) (e.g.Pigweed-Auto-Submit+1orAuto-Submit+1depending on host; auto-submits when reviews & checks pass).--cq [1|2]: Set Commit-Queue vote (--cqdefaults to dry run /+1; specify2to submit).-d, --draft: Mark change as Work-In-Progress (WIP).-B, --base <branch>: Target branch (e.g.sandbox/experiment, defaults to upstream tracking branch or repository default).--stack: Allow pushing multiple commits as a stack of Gerrit changes.--publish: Publish draft comments upon pushing.-o, --push-option <opt>: Pass raw Gerrit push options (e.g.-o topic=my-topic).--no-verify: Bypass pre-push git hooks.
- Safety Guard: Fails with a clear error and URL if the change already
exists (use
./gh pr push(aliases:./gh push,./gh pr upload): Push local commit(s) to Gerrit to upload a new patchset on an existing change.- Branch Memory: Automatically queries Gerrit by
Change-Idto discover the CL's target branch (e.g. sandbox branch), guaranteeing updates land on the right branch. - Stack Guard: Requires
--stackif pushing multiple commits ahead of origin. - Supports all rich push options (
--reviewer,--cc,--auto,--cq,--draft,--ready,--publish,--stack,-o,--no-verify). - Smart Fallback: If pushed with
--cqor metadata on an already up-to-date commit,pr pushautomatically applies updates via the Gerrit API instead of failing. --ready: Remove WIP status and mark change as ready for review.
- Branch Memory: Automatically queries Gerrit by
./gh pr edit [<id>]: Edit an existing change (defaults to active change if omitted):- Trigger CQ dry run:
./gh pr edit --cq(or--cq 2to submit,--cq 0to remove vote; also supports--add-label <Name>=<Score>) - Update message/reviewers:
./gh pr edit --message "new message" --add-reviewer user@google.com - Rewrite only the prose, keeping trailers:
./gh pr edit --body "new description" - Link a bug:
./gh pr edit --bug b/123456(or--fixed b/123456to also close it on submit; both accept123456,b/123456, or an issue URL, and--bug none) - Data Safety:
--bodyand--titlealways preserve every Git trailer (Change-Id:,Bug:,Fixed:,Co-authored-by:,Cq-Include-Trybots:, cherry-pick provenance, ...).--messagereplaces the entire message, so it fails with an error listing any trailers your new text leaves out; either carry them forward or pass--drop-trailersto confirm.Change-Id:is always restored regardless.
- Trigger CQ dry run:
3. Review & Comment
./gh pr comment [<id>] --path <file> --line <line> -m <msg>: Post an inline comment (defaults to active change if omitted).- Auto-threading: Automatically detects and appends a reply to the active thread on that file and line.
--resolved: Mark thread as resolved (requires both--pathand--line).--draft: Save comment as a private unpublished draft visible only to you in Gerrit.
./gh pr comment [<id>] -m <msg>: Post a change-level comment (-F <file>reads from file)../gh pr review [<id>]: Submit change review (defaults to active change on current branch if omitted):--cq [1|2]: Vote Commit-Queue (--cqdefaults to dry run /+1;--cq 2= submit).--approve -m <msg>: VoteCode-Review+2(approve).--approve --cq: Approve and trigger CQ dry run in a single step.--request-changes -m <msg>: VoteCode-Review-1(request changes).
4. Monitor & Rerun CI / Buildbucket Checks
Pigweed organizes CI into two complementary command tiers matching the GitHub CLI:
High-Level Check Table (gh pr checks):
./gh pr checks [<id>[/<patchset>]]: Query remote LUCI Buildbucket checks for a change or patchset (defaults to active change if omitted).- Displays status icons (
✓,✕,*,?), builder names, durations, and direct log URLs. -w, --watch: Continuously monitor checks until all blocking checks finish.--fail-fast: Exit immediately upon the first failure among blocking checks (implies--watch).-i, --interval <duration>: Polling interval when watching (default:15s).--log-failed: Automatically display failure reports and LogDog snippets for failed checks on exit (default:true).-e, --experimental: Include non-blocking experimental checks in output.--web: Open checks overview in Milo web browser.- Exit codes (same contract as the real GitHub CLI, on every invocation,
regardless of
--watch/--json/--template):0= all blocking checks passed,8= nothing failed but checks are still running,1= a blocking check failed, no checks were reported, or the command errored. Branch on the exit code; never scrape the table../gh pr checks --watch && ./gh pr merge --cqis a safe gate. - Fails closed: a change with no reported checks exits
1. Experimental builders never influence the exit code, even with-e; that flag only changes what is displayed. - Canceled checks also exit
1(a canceled build did not pass), but are reported as canceled, not failed. This is normal when querying an older patchset: uploading a new patchset cancels the runs still in flight on the previous one. Re-query without the/<patchset>suffix to see current state. - Rebase Note: If you are on a patchset of type
TRIVIAL_REBASE,TRIVIAL_REBASE_WITH_MESSAGE_UPDATE,NO_CODE_CHANGE, orNO_CHANGE, builds from the prior patchset are generally still applicable. - Distinction:
./gh pr checksqueries remote cloud CI builders;./pw presubmitruns local host validation.
- Displays status icons (
Deep Run & Job Management (gh run):
./gh run list [<id>]: List all checks/runs for a change with duration, ID, status, and URL (--json,--limit,--experimental)../gh run view [<id>]: Structured run summary overview matching GitHub CLI.-j, --job <builder>: View hierarchical step execution tree for a specific builder (or direct build ID like867...). Collapses internal recipe plumbing and highlights failures with 1-line extracted diagnostics (formatting diffs, compiler errors).--log-failed: Fetch and display failure summaries and LogDog error snippets directly in the terminal without opening a browser.--log: Dump full log stream instead of tail snippet.-v, --verbose: Show all unfiltered recipe micro-steps.-w, --web: Open build directly in Milo web browser.--json: Output machine-parseable failure reports or step details.
./gh run rerun [<id>]: Rerun specific or failed CI builders without manual URL bashing.--failed: Rerun all failed checks on the change (e.g../gh run rerun --failed).-j, --job <builder>: Rerun a specific builder (e.g../gh run rerun -j pigweed-lintformat).--dry-run: Print the underlyingbb addcommand without executing it.
./gh run watch [<id>]: Watch runs until all blocking checks finish.
5. Listing, Merging & Navigation
./gh pr list: List repository changes (--limit 30,--state open|merged|closed|all,--json <fields>). List repository changes../gh pr merge [<id>] [--auto] [--cq]: Submit change to target branch (defaults to active change if omitted). In Pigweed/LUCI, use--auto(auto-submit upon approval) or--cq(vote Commit-Queue+2) for automated submission; barepr mergerequires all gates already satisfied../gh pr status [--all]: Show focused review status dashboard:- Current branch: Displays active change ID, title, target branch, patchset, submittability, labels/flags, live tryjob check status, and comments overview (unresolved threads, unpublished drafts, and inline previews with hysteresis).
- Created by you & Requesting a code review from you: Scoped to the last 30 days by default for fast rendering and token efficiency.
--all(-A): Show all open changes across your account without 30-day filter.
6. Root-Level Ergonomic Aliases
Direct shortcuts matching common developer muscle memory:
./gh checks->./gh pr checks./gh view->./gh pr view./gh diff->./gh pr diff./gh status->./gh pr status./gh push->./gh pr push
7. Where gh Habits Break
No gh shorthand is re-used here to mean a different flag. Where a spelling
would collide it is left unbound, so the mistake fails with an unknown-flag
error instead of quietly doing the wrong thing — trust that error rather than
working around it. Run ./gh --help for the authoritative list; this table is
maintained by hand alongside it.
Use the long form for these, because gh gives the shorthand another meaning:
--auto (gh -a is --assignee), --publish (-p is --project), --force
(-f is --fill), --cq (-q is --jq), and --message on pr edit and
pr merge (-m is --milestone and --merge).
What still differs is the meaning underneath a flag that is spelled the same:
| You type | Real gh | Here |
|---|---|---|
pr list -a | assignee | queries Gerrit reviewer: — Gerrit dropped assignees in 3.8. |
pr list -l | issue label | a Gerrit vote predicate, e.g. Code-Review+2. |
run list/view --json | a field list | a boolean; it takes no fields. pr view --json does take fields. |
--json state | OPEN/CLOSED/MERGED | Gerrit's NEW/MERGED/ABANDONED. |
pr review --request-changes | blocks the PR | votes Code-Review-1, which is advisory. Code-Review-2 is the veto. |
pr comment --draft | (n/a) | an unpublished draft comment nobody else can see — not a WIP change. |
Workflow 1: Addressing Review Feedback
When tasked with addressing review comments on a change:
- Fetch & review comments:
./gh pr view <id> --comments - Apply code fixes locally: Edit files and verify with the local
presubmit gate:
./pw presubmit --mode auto --base origin/main - Upload updated patchset:
git commit -a --amend --no-edit ./gh pr push - Reply to threads and mark resolved:
./gh pr comment <id> --path <file> --line <line> -m "Fixed, using pw::Status." --resolved
Workflow 2: Performing a Code Review
When tasked with reviewing a colleague's change or local commit:
- Inspect metadata & diff:
./gh pr view <id> ./gh pr diff <id> - Evaluate against Core Principles:
- Testing: Are there sufficient unit tests covering edge cases?
- Functionality: Does the change behave correctly without regressions?
- Security: Any buffer overflows, integer issues, or resource leaks?
- Style: Adheres to Pigweed C++17 style (
pw::types, no dynamic allocation,#pragma once). - Commit Message: Conforms to Pigweed style (
module: Imperative message under 72 chars,Bug: b/...orFixed: b/...).
- Submit review feedback:
- Post inline comments for specific lines:
./gh pr comment <id> --path <file> --line <line> -m "nit: consider std::string_view" [--draft] - Submit overall review:
./gh pr review <id> --approve -m "LGTM! Verified tests pass." # or ./gh pr review <id> --request-changes -m "Please address comments on error handling."
Workflow 3: CI Triage & Targeted Retry (gh run / pr checks)
-
Check builder statuses or watch until done:
./gh pr checks <id> # quick status snapshot (blocking checks) ./gh pr checks <id> --watch --fail-fast # watch until complete; fail fast on error and dump failure logs ./gh pr checks <id> --experimental # include non-blocking experimental checksAgent Tip: When asked to monitor or wait for CI checks, launch
./gh pr checks --watch --fail-fastas a background command and STOP calling tools. DO NOT poll in a loop with manual./gh pr checkscalls or recurring schedule timers. The tool itself polls Buildbucket and the environment will automatically wake you when the process finishes or when a failure occurs. -
Inspect failure logs without browser context switching:
./gh run view <id> --log-failed # summarize all failed blocking builders, failure steps & snippets ./gh run view <id> -j <builder> # inspect step tree with extracted diagnostics (diffs, compilation errors) ./gh run view <id> -j <builder> --log-failed# inspect failure logs for specific builder ./gh run view <id> -j <builder> --log # dump full log stream ./gh run view <id> --log-failed --json # parseable diagnostics for agent analysis -
Targeted Verification (
gh run rerun): If only specific builders failed (e.g.pigweed-lintformat), trigger only those builders without URL bashing:./gh run rerun <id> -j <builder> # or rerun all failed checks: ./gh run rerun <id> --failed(Note: Under the hood,
./ghinvokesbb addusing the active project's try bucket. Ifbbis not logged in, the user must runbb auth-loginin an interactive terminal). -
Full Validation: Once targeted fixes succeed, trigger a full CQ dry run:
./gh pr edit <id> --cq
Critical Rules for AI Agents
- NEVER use raw
git push: Always use./gh pr push(or./gh push) to update existing changes with new patchsets, and./gh pr createto create new changes. - Use
--draftfor Private Notes: Intermediate or preparatory review comments should use--draftso they remain private to you until ready. - Resolve Threads Explicitly: When fixing an issue raised by a reviewer,
always reply with
--resolved --path <file> --line <line>. - Authentication is Automatic: No manual
curl -sb ~/.gitcookiesor auth tokens needed;./ghautomatically routes through workstation credentials (gob-curlon Google corp workstations, or~/.gitcookies/ githttp.cookiefile/~/.netrcfor external contributors). - Never Ignore Command Failures or Exit Codes:
./ghguarantees that invalid inputs (unknown--jsonfields, invalid--profile, missing--path/--linefor--resolved, etc.) fail fast with non-zero exit codes. Always inspect stderr and address the reported error rather than assuming success. - Preserve Commit Trailers: Prefer
./gh pr edit --body/--titlewhen reworking a description; they keep every trailer (Change-Id:,Bug:,Fixed:,Reviewed-on:,Co-authored-by:, cherry-pick provenance) automatically.--messagereplaces the whole message and will refuse if that would delete trailers. Treat that error as a stop sign: carry the listed trailers into your new message rather than reaching for--drop-trailers. - Link Bugs With Trailers, Never
Fixes #N: GitHub'sFixes #456does nothing on Gerrit — the bug is silently never linked or closed. Use aBug: b/456orFixed: b/456trailer, or let the tool write it:./gh pr edit <id> --fixed b/456../ghrejects GitHub issue syntax rather than guessing, because a GitHub issue number and a Buganizer ID are different number spaces andb/456would be an unrelated bug. Look the real Buganizer ID up; do not invent one. Verify the link took with./gh pr view <id> --json bug,bugsrather than assuming. - Submit Changes, Not Patchsets: Use
./gh pr merge <id>without patchset suffixes, as Gerrit submits whole changes. - Submit via Commit-Queue: In Gerrit projects with a
Commit-Queuelabel or LUCI gates, direct submission via bare./gh pr mergeattempts an immediate submit, which fails if CI gates (e.g.Presubmit-Verified) or review approvals are not yet satisfied. Use./gh pr merge --autoto enable automatic submission once requirements pass,./gh pr merge --cqto delegate the build-and-submit cycle directly to the Commit-Queue, or wait for checks with./gh pr checks --watchbefore merging. - NEVER Poll CI in an Agent Loop: When monitoring tryjobs or driving
changes to ground, run
./gh pr checks --watch --fail-fastas a background command and let it run. DO NOT set polling timers or execute repeated manual./gh pr checkscalls. The background process will notify you automatically when checks finish or when a failure is detected, avoiding wasteful turn and token consumption.
Signals
- GitHub stars
- 538
- Forks
- 127
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
ghish- Source
- github.com/pigweed-project/pigweed