Skip to main content

Command Palette

Search for a command to run...

GitHub CLI (gh) Deep Dive: PRs, Issues, API, and Scripting

Published
7 min read
D
Practical guides for developers: TypeScript, developer tools, CI/CD, and modern web development. We cover the tools that make devs more productive.

GitHub CLI (gh) Deep Dive: PRs, Issues, API, and Scripting

The GitHub CLI (gh) replaces most trips to github.com with terminal commands. Once you build it into your workflow, going back to the web UI feels slow. This guide covers everyday PR workflows, issue management, the powerful gh api command, and how to script GitHub operations.

GitHub CLI logo

Installation and Setup

# macOS
brew install gh

# Fedora
sudo dnf install gh

# Ubuntu/Debian
sudo apt install gh

# Authenticate
gh auth login

gh auth login walks you through OAuth authentication. Choose HTTPS for most use cases. Your token is stored securely in the system keychain.

# Verify authentication
gh auth status

# Switch between accounts
gh auth switch

Pull Request Workflows

Creating PRs

# Create PR from current branch (interactive)
gh pr create

# Create with title and body
gh pr create --title "Add user authentication" --body "Implements JWT-based auth"

# Create as draft
gh pr create --draft --title "WIP: Database migration"

# Create and fill from commit messages
gh pr create --fill

# Create targeting a specific base branch
gh pr create --base develop

--fill pulls the title from your first commit message and the body from subsequent commits. For single-commit PRs, this is often all you need.

Reviewing PRs

# List open PRs
gh pr list

# View a specific PR
gh pr view 42

# View in browser
gh pr view 42 --web

# Check out a PR locally
gh pr checkout 42

# View the diff
gh pr diff 42

# Review a PR
gh pr review 42 --approve
gh pr review 42 --request-changes --body "Need to handle the error case"
gh pr review 42 --comment --body "Looks good, minor suggestion inline"

gh pr checkout is one of the most useful commands. It creates a local branch from the PR, sets up tracking, and fetches the latest changes. No more manually adding remotes for external contributors.

Merging PRs

# Merge (default strategy from repo settings)
gh pr merge 42

# Squash merge
gh pr merge 42 --squash

# Rebase merge
gh pr merge 42 --rebase

# Merge and delete branch
gh pr merge 42 --squash --delete-branch

# Auto-merge when checks pass
gh pr merge 42 --auto --squash

--auto is excellent for PRs waiting on CI. It merges automatically once all required checks pass and reviews are approved.

PR Status and Checks

# See status of your PRs
gh pr status

# View CI checks for a PR
gh pr checks 42

# Watch checks in real-time
gh pr checks 42 --watch

gh pr status shows PRs you created, PRs requesting your review, and PRs on your current branch. It's the first command to run at the start of your workday.

Issue Management

# Create an issue
gh issue create --title "Bug: login fails on mobile" --label bug

# Create with body from file
gh issue create --title "Feature request" --body-file .github/ISSUE_TEMPLATE.md

# List issues
gh issue list
gh issue list --assignee @me
gh issue list --label "bug" --state open

# View an issue
gh issue view 15

# Close an issue
gh issue close 15

# Reopen
gh issue reopen 15

# Add labels
gh issue edit 15 --add-label "priority:high"

# Assign
gh issue edit 15 --add-assignee username

# Transfer to another repo
gh issue transfer 15 owner/other-repo

Issue Templates

Create issues from templates defined in your repository:

# Interactive (lets you choose a template)
gh issue create

# Pin an issue
gh issue pin 15

# List pinned issues
gh issue list --state open --json number,title,isPinned | jq '.[] | select(.isPinned)'

gh api: The Power Tool

gh api gives you direct access to GitHub's REST and GraphQL APIs with automatic authentication. This is where gh goes from convenient to indispensable.

REST API

# Get repository info
gh api repos/owner/repo

# List workflow runs
gh api repos/owner/repo/actions/runs --jq '.workflow_runs[:5] | .[].name'

# Get PR comments
gh api repos/owner/repo/pulls/42/comments --jq '.[].body'

# Create a comment
gh api repos/owner/repo/issues/42/comments -f body="Automated comment"

# Paginate results
gh api repos/owner/repo/issues --paginate --jq '.[].title'

# Use HTTP methods
gh api repos/owner/repo/labels -f name="needs-triage" -f color="ff0000"

The --jq flag pipes the JSON response through jq, letting you extract exactly the fields you need. Combined with --paginate, you can query large datasets efficiently.

GraphQL API

# Query with GraphQL
gh api graphql -f query='
{
  repository(owner: "owner", name: "repo") {
    pullRequests(first: 5, states: OPEN) {
      nodes {
        title
        author { login }
        createdAt
      }
    }
  }
}'

# Use variables
gh api graphql -f query='
  query($owner: String!, $name: String!) {
    repository(owner: $owner, name: $name) {
      stargazerCount
    }
  }
' -f owner="owner" -f name="repo"

GraphQL is more efficient when you need specific fields from multiple related objects. Instead of making three REST requests, you can get everything in one query.

Aliases

Aliases let you create shortcuts for common commands:

# Create aliases
gh alias set prs 'pr list --author @me'
gh alias set review 'pr list --search "review-requested:@me"'
gh alias set co 'pr checkout'
gh alias set merged 'pr list --state merged --author @me --limit 10'

# Complex alias with shell commands
gh alias set 'clean-branches' '!git branch --merged | grep -v "main\|master" | xargs git branch -d'

# List aliases
gh alias list

# Use aliases
gh prs
gh review
gh co 42

The ! prefix runs a shell command instead of a gh subcommand. This lets you create aliases that combine gh with other tools.

gh alias set pv 'pr view'
gh alias set pc 'pr create --fill'
gh alias set pm 'pr merge --squash --delete-branch'
gh alias set il 'issue list --assignee @me'
gh alias set ic 'issue create'
gh alias set runs 'run list --limit 5'

Extensions

Extensions add entirely new commands to gh. They're community-built and installed from GitHub repositories.

# Browse available extensions
gh extension browse

# Install an extension
gh extension install dlvhdr/gh-dash
gh extension install seachicken/gh-poi

# List installed extensions
gh extension list

# Update extensions
gh extension upgrade --all

Notable Extensions

ExtensionWhat it does
gh-dashTerminal dashboard for PRs and issues
gh-poiClean up local branches after PR merge
gh-copilotGitHub Copilot in the terminal
gh-markdown-previewPreview markdown files
gh-notifyGitHub notifications in the terminal

gh-dash deserves special mention. It provides a TUI dashboard showing all your PRs, review requests, and issues across multiple repositories. It's faster than the GitHub web UI for daily triage.

Scripting with gh

gh shines in automation scripts. Here are practical examples.

Close Stale Issues

#!/bin/bash
# Close issues with no activity in 90 days
gh issue list --state open --json number,updatedAt --jq \
  '.[] | select(.updatedAt < (now - 7776000 | todate)) | .number' |
while read -r issue; do
  gh issue close "$issue" --comment "Closing due to inactivity. Reopen if still relevant."
done

Create Release Notes

#!/bin/bash
# Generate release notes from merged PRs since last tag
LAST_TAG=$(git describe --tags --abbrev=0)
gh pr list --state merged --search "merged:>$(git log -1 --format=%aI $LAST_TAG)" \
  --json title,number,author --jq \
  '.[] | "- \(.title) (#\(.number)) by @\(.author.login)"'

Bulk Label Issues

#!/bin/bash
# Add label to all issues matching a search
gh issue list --search "is:open label:bug" --json number --jq '.[].number' |
while read -r issue; do
  gh issue edit "$issue" --add-label "priority:high"
done

CI Status Check

#!/bin/bash
# Wait for CI to pass on current branch, then merge
gh pr checks --watch && gh pr merge --squash --delete-branch

This is a great one-liner for your workflow: submit a PR, run this command, and walk away. It watches CI and merges automatically when everything passes.

Tips

  • Use gh pr status every morning to see what needs your attention
  • Set GH_REPO=owner/repo to run gh commands outside a git repository
  • Pipe gh output through jq for structured data processing
  • Use --json flag with most list commands to get machine-readable output
  • Combine gh api --paginate with --jq for querying large datasets
  • Set GH_PAGER=cat to disable paging in scripts

Recommendations

  • Install gh and authenticate immediately on any new development machine
  • Set up 5-10 aliases for your most common operations
  • Install gh-dash for a daily PR/issue dashboard
  • Use gh pr create --fill for most PRs and edit the body in the interactive editor
  • Use gh api with --jq instead of writing custom API clients for one-off queries
  • Script repetitive GitHub operations -- if you do it more than three times, automate it

Enjoyed this guide? Subscribe to DevTools Guide — a free weekly newsletter covering developer tools, workflows, and best practices.

More from this blog

DevTools Guide

183 posts