Use GitHub CLI reliably
Prefer gh for GitHub work. Establish the authenticated account and repository before reading or changing remote state:
gh auth status
gh repo view --json nameWithOwner,url,defaultBranchRef
git status --shortPass --repo owner/name whenever the target is not unambiguous from the current working directory. Inspect an object before mutating it.
Read structured output
Prefer --json and --jq over parsing display output:
gh pr view 123 --repo owner/repo --json number,title,state,url,headRefName,baseRefName --jq '{number,title,state,url,head: .headRefName,base: .baseRefName}'
gh issue view 456 --repo owner/repo --json number,title,state,url
gh run list --repo owner/repo --limit 10 --json databaseId,status,conclusion,workflowName,urlWhen a JSON field is uncertain, inspect gh <command> --help. If help does not list fields, use a harmless invalid field to make gh print the valid set, then retry once:
gh repo view owner/repo --json _fieldsCommon corrections:
| Incorrect assumption | Use instead |
|---|---|
defaultBranch |
defaultBranchRef |
stargazersCount |
stargazerCount |
merged |
state, mergedAt, or closed |
mergedAt in search results |
closedAt, or query the PR with gh pr view |
topics in gh repo view |
gh api repos/owner/repo/topics |
gh search prs --state merged is invalid. Use --merged; search's --state accepts open or closed.
Send Markdown through temporary files
File first: For every issue, pull request, review, comment, or edit body, create a temporary .md file with the environment's file-editing tool, then invoke gh with --body-file. Create the file and run gh in separate tool calls or commands. The Markdown file is the source of truth in both PowerShell and POSIX shells, so the body stays literal and shell parsing cannot alter it.
- Create the temporary
.mdfile in the approved temp directory with the final Markdown content. The body enters the workflow through the file-editing tool; keep it out of shell variables, PowerShell here-strings, heredocs, and inline--bodyarguments. - Run
ghin a separate command using--body-file <temporary-file-path>. If the command fails and needs a retry, keep or update that file until the workflow is finished. - After the final command result has been captured, remove the temporary file.
The step is complete when gh consumed the body through --body-file and the temporary file has been removed after the last attempt.
gh pr create --repo owner/repo --base main --head branch-name --title "fix: describe the change" --body-file path/to/pr-body.md
gh issue create --repo owner/repo --title "docs: add homepage" --body-file path/to/issue-body.md
gh pr review 123 --repo owner/repo --comment --body-file path/to/review.md
gh pr comment 123 --repo owner/repo --body-file path/to/comment.mdUse the same pattern with gh pr edit, gh issue edit, and gh issue comment. Keep using --body-file for short bodies too; the file-first rule is the default for every supplied body.
Work with pull requests
Read the PR and local branch state before creating or changing a PR:
gh pr view 123 --repo owner/repo --json number,title,body,state,url,headRefName,baseRefName,author,commits,files,additions,deletions
git status --short
git branch --show-current
git log --oneline -10
git fetch origin
git log --oneline origin/main..HEADBefore gh pr create, confirm the branch has commits relative to the base and exists remotely. Push with git push -u origin HEAD when needed. For a fork, pass --head owner:branch-name.
Errors such as Head sha can't be blank, Base sha can't be blank, No commits between, and Head ref must be a branch indicate an incorrect base/head, an unpushed branch, or no commits to compare. Diagnose branch and remote state before retrying.
Useful PR reads:
gh pr list --repo owner/repo --state all --head branch-name --json number,title,state,url
gh pr diff 123 --repo owner/repo
gh pr diff 123 --repo owner/repo --name-only
gh pr checks 123 --repo owner/repogh pr diff --stat is unsupported. Use gh pr view --json additions,deletions,changedFiles.
For inline review comments, use gh api only after reading the PR files and existing comments. The API strictly validates commit_id, path, side, line, and start_line; bad positions return HTTP 422. Reply to an existing inline comment instead of creating a new top-level comment when continuing its thread.
Inspect Actions
gh pr checks 123 --repo owner/repo --watch
gh run list --repo owner/repo --branch branch-name --limit 10 --json databaseId,status,conclusion,displayTitle,workflowName,createdAt,url
gh run view RUN_ID --repo owner/repo --json status,conclusion,url,jobs
gh run view RUN_ID --repo owner/repo --log-failedgh run watch RUN_ID --exit-status can wait indefinitely. Use it only when waiting is part of the task and give the command an appropriate timeout.
If workflow dispatch returns HTTP 422 because the workflow lacks workflow_dispatch, inspect the workflow file instead of retrying.
Use gh api as the fallback
Use a dedicated gh subcommand when one exists. Otherwise use gh api:
gh api repos/owner/repo/pulls/123/files --paginate --jq '.[] | {filename,status,patch}'
gh api repos/owner/repo/contents/path/to/file -H "Accept: application/vnd.github.raw"Preserve value types:
| Value | Pattern |
|---|---|
| String | --raw-field name=value |
| Typed JSON scalar | --field count:=10 --field enabled:=true |
| Complex JSON | --input path/to/request.json |
-f enabled=true sends the string "true", not a boolean, and can cause HTTP 422.
Handle secrets and gists
List secret names with gh secret list --repo owner/repo. Pipe secret values from an environment variable or a secret manager into gh secret set; never place values in command arguments, files, issues, or PR bodies.
PowerShell:
$env:SECRET_VALUE | gh secret set SECRET_NAME --repo owner/repoPOSIX shell:
printf '%s' "$SECRET_VALUE" | gh secret set SECRET_NAME --repo owner/repoFor gists, omit --public to create a secret gist; gh gist create --private is not valid. When reading from stdin, include - and provide non-empty content.
Diagnose failures
- Read the exact error and command help.
- For an unknown field or flag, discover the valid usage and retry once.
- For PR creation errors, inspect status, branch, remotes, push state, and
origin/base..HEAD. - For HTTP 401, 403, or GraphQL permission errors, run
gh auth statusand report missing permissions. - For HTTP 422, inspect request shape, typed fields, and review-comment positions.
- For a timeout or transient network error, retry once with a narrower request or suitable timeout.
- After two equivalent failures, change the diagnosis rather than repeating the command.
Interactive authentication needs the user. Do not start gh auth refresh in an unattended workflow. Organization repository creation may require organization-level permission that no CLI flag can bypass.