GitHub CLI (gh) Deep Dive: PRs, Issues, API, and Scripting
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.
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.
Recommended Aliases
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
| Extension | What it does |
|---|---|
gh-dash |
Terminal dashboard for PRs and issues |
gh-poi |
Clean up local branches after PR merge |
gh-copilot |
GitHub Copilot in the terminal |
gh-markdown-preview |
Preview markdown files |
gh-notify |
GitHub 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 statusevery morning to see what needs your attention - Set
GH_REPO=owner/repoto runghcommands outside a git repository - Pipe
ghoutput throughjqfor structured data processing - Use
--jsonflag with most list commands to get machine-readable output - Combine
gh api --paginatewith--jqfor querying large datasets - Set
GH_PAGER=catto disable paging in scripts
Recommendations
- Install
ghand authenticate immediately on any new development machine - Set up 5-10 aliases for your most common operations
- Install
gh-dashfor a daily PR/issue dashboard - Use
gh pr create --fillfor most PRs and edit the body in the interactive editor - Use
gh apiwith--jqinstead of writing custom API clients for one-off queries - Script repetitive GitHub operations -- if you do it more than three times, automate it