Overview

gh is GitHub’s official CLI. It covers the common browser round trips: opening and merging PRs, triaging issues, triggering and watching workflow runs, cutting releases, and calling the API. This page lists the commands worth memorizing and the scripting patterns around them. Shell conventions are in shell.

Authenticate once, use a token in automation

gh auth login            # interactive: browser or token
gh auth status           # which account and scopes are active
gh auth token            # print the current token

For scripts and CI, set GH_TOKEN in the environment; gh uses it before prompting. Inside Actions, gh is preinstalled on GitHub-hosted runners, so pass GH_TOKEN: ${{ github.token }} and grant the job only the permissions it needs (github-actions). Outside Actions, use a fine-grained personal access token limited to the repositories and permissions the script uses, not a classic token.

Drive the PR lifecycle with gh pr

gh pr create --fill --draft           # title and body from commits
gh pr list --state open --assignee "@me"
gh pr checkout 42
gh pr checks 42 --watch               # wait for CI
gh pr review 42 --approve --body "LGTM"
gh pr merge 42 --squash --delete-branch
gh pr merge --auto --squash           # enable auto-merge on the current PR

Title and body conventions are in github-pr-workflow. Pass --web to finish a complex body in the browser.

Manage issues with gh issue

gh issue create --title "Deploy fails on Saturday" --label bug
gh issue list --label bug --state open
gh issue close 17 --comment "Fixed in #42"

Link issues from the PR body with Closes #17 instead of closing them by hand.

Trigger and watch runs with gh workflow and gh run

gh workflow run deploy.yml --ref main
gh run list --workflow ci.yml --limit 5
gh run watch 123456789
gh run rerun 123456789 --failed       # retry only failed jobs

gh run watch confirms a deploy before you tell anyone it shipped. --failed retries flaky jobs without re-running the passing ones.

Script with --json and --jq

Most list and view commands take --json <fields> and --jq <expression>, which removes a separate jq process.

gh pr list --json number,title --jq '.[] | "\(.number): \(.title)"'
gh run list --workflow ci.yml --json databaseId,conclusion \
  --jq '.[] | select(.conclusion=="failure") | .databaseId'
gh api repos/{owner}/{repo}/commits/main --jq '.sha'

gh api fills {owner}, {repo}, and {branch} from the current repository; add --paginate for multi-page results. For heavy transformations, pipe to jq directly.

Manage repositories with gh repo

gh repo clone org/repo
gh repo fork org/repo --clone
gh repo create my-repo --public --clone
gh repo set-default org/repo     # pick the target when a checkout has several remotes

gh repo set-default removes the need for --repo on later commands in a checkout with multiple remotes.

Wrap repeated sequences in shell functions

draft-pr() { gh pr create --fill --draft --title "${1:?usage: draft-pr <title>}"; }

Keep wrappers in your shell profile so flags that vary by repo policy are typed once. Releases are covered in github-releases.