---
title: "GitHub CLI"
slug: "github-cli"
category: "tooling"
tags: ["tooling", "github", "cli", "automation", "shell", "scripting", "gh"]
status: "stable"
last_updated: 2026-05-14
summary: "Core gh commands for PRs, issues, repos, and workflows; auth setup; --jq for JSON piping; and scripting patterns that replace the GitHub web UI."
related: ["[[tooling/github]]", "[[tooling/github-pr-workflow]]", "[[tooling/github-actions]]", "[[tooling/github-releases]]", "[[tooling/github-branch-protection]]", "[[coding/git]]", "[[coding/shell]]"]
---

## Overview

`gh` is the official GitHub CLI. It removes the context switch to the browser for the most common operations: opening PRs, triaging issues, triggering workflows, and cutting releases. The rules below cover authentication, the command groups worth learning, `--jq` for scriptable output, and one-liners that save repeated clicks. Read [[coding/shell]] for the shell scripting patterns that pair with `gh`.

## Authenticate once; use tokens for non-interactive environments

```bash
gh auth login          # interactive: browser or PAT
gh auth status         # verify which account and scopes are active
gh auth token          # print the current token for piping
```

For CI and automation, set `GH_TOKEN` in the environment or in [[tooling/github-secrets]]. The CLI picks up `GH_TOKEN` before prompting for interactive auth. Use a fine-grained PAT scoped to the repositories and permissions the script needs. Avoid classic PATs with broad scopes.

## `gh pr` covers the full PR lifecycle

```bash
gh pr create --title "feat(tooling): add CLI page" --body "$(cat body.md)" --draft
gh pr list --state open --assignee "@me"
gh pr view 42
gh pr checkout 42        # switches to the branch locally
gh pr merge 42 --squash --delete-branch
gh pr review 42 --approve --body "LGTM"
gh pr merge --auto --squash   # enable auto-merge on the current branch's PR
```

`gh pr create` without arguments infers the title from the last commit and opens an editor for the body. Pass `--web` to open the creation form in the browser when the body is complex. See [[tooling/github-pr-workflow]] for the title and body conventions these commands must follow.

## `gh issue` replaces the issues tab

```bash
gh issue create --title "Bug: deploy fails on Saturday" --label "bug"
gh issue list --label "bug" --state open
gh issue view 17
gh issue close 17 --comment "Fixed in #42"
gh issue edit 17 --add-label "priority:high"
```

Link issues to PRs in the PR body with `Closes #17`; do not close issues manually when a PR will do it at merge.

## `gh workflow` triggers and monitors Actions runs

```bash
gh workflow list
gh workflow run deploy.yml --ref main
gh run list --workflow ci.yml --limit 5
gh run view 123456789
gh run watch 123456789      # stream logs in real time
gh run rerun 123456789 --failed   # retry only failed jobs
```

`gh run watch` is useful for deploy workflows where you want to confirm success before notifying a stakeholder. `gh run rerun --failed` retries flaky checks without re-running jobs that already passed. See [[tooling/github-actions]] for the workflow files these commands operate on.

## Use `--jq` for scriptable JSON output

Most `gh` commands accept `--json` to emit structured output and `--jq` to filter it with a jq expression in one step.

```bash
# List open PR numbers and titles
gh pr list --json number,title --jq '.[] | "\(.number): \(.title)"'

# Get the SHA of the last commit on main
gh api repos/:owner/:repo/commits/main --jq '.sha'

# Find all issues labeled "bug" opened in the last 7 days
gh issue list --label bug --json number,createdAt,title \
  --jq '[.[] | select(.createdAt > (now - 604800 | todate))]'

# Print the run IDs of all failed CI runs
gh run list --workflow ci.yml --json databaseId,conclusion \
  --jq '.[] | select(.conclusion=="failure") | .databaseId'
```

`--jq` eliminates a separate `jq` invocation and keeps the pipeline readable. For complex transformations, pipe to `jq` directly.

## `gh repo` manages repository-level operations

```bash
gh repo clone org/repo
gh repo fork org/repo --clone
gh repo view --web                    # open in browser
gh repo create my-new-repo --public --clone
gh repo set-default org/repo         # set default for ambiguous commands in a monorepo checkout
```

`gh repo set-default` is useful in a checkout that contains multiple remotes. After setting the default, commands like `gh pr list` target the right repository without a `--repo` flag.

## Script common multi-step operations as shell functions

```bash
# Open a draft PR for the current branch
draft-pr() {
  local title="${1:?usage: draft-pr <title>}"
  gh pr create --title "$title" --body "" --draft
}

# Approve and auto-merge a PR by number
ship() {
  local num="${1:?usage: ship <pr-number>}"
  gh pr review "$num" --approve
  gh pr merge "$num" --auto --squash --delete-branch
}
```

Store these in `~/.zshrc` or `~/.bashrc`. They turn a four-command sequence into a single call and reduce typos in the flags that vary by repo policy. See [[coding/shell]] for shell function conventions.

## Related

- [[tooling/github]]
- [[tooling/github-pr-workflow]]
- [[tooling/github-actions]]
- [[tooling/github-releases]]
- [[tooling/github-branch-protection]]
- [[tooling/github-secrets]]
- [[coding/git]]
- [[coding/shell]]
