GitHub CLI Cheatsheet
Reviews and Merging
Use this GitHub CLI reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Submitting a Review
gh pr review submits a whole review, not a line comment. One of the three verdict flags is required non-interactively.
gh pr review 123 --approve gh pr review 123 --approve --body "ship it" gh pr review 123 --request-changes -b "needs a test for the empty case" gh pr review 123 --comment -b "one nit, otherwise fine" gh pr review 123 --request-changes --body-file review.md gh pr review 123 --comment --body-file - < notes.txt gh pr review # interactive, current branch
| Flag | Verdict |
|---|---|
-a, --approve | Approve |
-r, --request-changes | Request changes, body is required |
-c, --comment | Comment only, no verdict, body is required |
-b, --body | Review body text |
-F, --body-file | Read the body from a file, - for stdin |
With no flags it opens a prompt, then your editor for the body. Per-line review comments are not exposed here, use --web on gh pr view or the gh api pulls review-comments endpoint.
Watching Checks
gh pr checks # current branch's PR gh pr checks 123 gh pr checks 123 --watch # refresh until every check finishes gh pr checks 123 --watch --interval 5 gh pr checks 123 --watch --fail-fast # bail on the first failure gh pr checks 123 --required # only required checks gh pr checks 123 --json name,state,link gh pr checks 123 --json state --jq '[.[] | select(.state=="FAILURE")] | length' gh pr checks 123 --web
--watch blocks and redraws until the run set completes, then exits non-zero if anything failed. That makes it usable as a gate:
gh pr checks --watch --fail-fast && gh pr merge --squash --delete-branch
Exit codes matter here: 0 every check passed, 8 checks are still pending, 1 a check failed, 2 cancelled, 4 not authenticated. Do not treat every non-zero code as "a check failed".
Merging
gh pr merge 123 --squash gh pr merge 123 --merge gh pr merge 123 --rebase gh pr merge 123 --squash --delete-branch gh pr merge 123 --squash -t "feat: add login" -b "closes #42" gh pr merge 123 --merge --body-file merge-notes.md gh pr merge 123 --auto --squash # merge once requirements pass gh pr merge 123 --disable-auto gh pr merge 123 --admin --squash # bypass branch protection gh pr merge 123 --squash --match-head-commit 9a3f21c gh pr merge # interactive, current branch
| Flag | Effect |
|---|---|
-s, --squash | One squashed commit onto the base |
-m, --merge | A merge commit |
-r, --rebase | Replay the commits onto the base |
--auto | Enable auto-merge, GitHub merges when checks and reviews pass |
--disable-auto | Turn auto-merge back off |
-d, --delete-branch | Delete the remote branch, and the local one if checked out |
--admin | Merge with admin privileges even if requirements are unmet |
-t, --subject, -b, --body | Commit subject and body |
-F, --body-file | Commit body from a file |
-A, --author-email | Author email for the merge commit |
--match-head-commit <SHA> | Refuse the merge unless the head is still that SHA |
--match-head-commit is the safety belt for automation. Between reading a PR and merging it someone can push another commit, and this flag turns that race into a clean failure instead of merging code you never reviewed.
A merge method the repo has disabled is rejected, so check gh repo view --json squashMergeAllowed,mergeCommitAllowed,rebaseMergeAllowed if a flag errors out.
Auto-Merge
--auto queues the merge instead of performing it. GitHub waits until required checks pass and required reviews land.
gh pr merge 123 --auto --squash --delete-branch gh pr merge 123 --disable-auto gh pr view 123 --json autoMergeRequest
Auto-merge must be enabled on the repository first (gh repo edit --enable-auto-merge), and the branch needs at least one required status check, otherwise the API rejects the request.
Review Workflow
A realistic pass over someone else's PR, all read-only until the last line.
gh pr status # what is waiting on me gh pr list --search "review-requested:@me" gh pr view 123 --comments # read the discussion gh pr diff 123 --exclude "*.lock" # read the change gh pr checkout 123 # run it locally gh pr checks 123 # CI state gh pr review 123 --approve -b "lgtm"
And the author's side once approved:
gh pr checks --watch --fail-fast gh pr merge --squash --delete-branch git checkout main && git pull
Inspecting Review State
Reviews and approvals are fields on the PR, so --json answers "who approved" without opening a browser.
gh pr view 123 --json reviews \ --jq '.reviews[] | "\(.author.login) \(.state)"' gh pr view 123 --json reviewDecision --jq .reviewDecision gh pr view 123 --json mergeable,mergeStateStatus gh pr list --json number,title,reviewDecision \ --jq '.[] | select(.reviewDecision=="APPROVED") | .number' gh pr view 123 --json latestReviews \ --template '{{range .latestReviews}}{{.author.login}} {{.state}}{{"\n"}}{{end}}'
reviewDecision is the rolled-up verdict (APPROVED, CHANGES_REQUESTED, REVIEW_REQUIRED), and latestReviews collapses each reviewer to their most recent verdict. reviews is the full history, which double counts anyone who reviewed twice.