gh — GitHub CLI
What is gh?
gh is the official GitHub command-line tool that brings the full power of GitHub into your terminal. Instead of switching between your editor, the command line, and a browser tab, gh lets you manage pull requests, issues, releases, GitHub Actions workflows, and more — all without leaving your terminal session.
Whether you are a solo developer wanting a faster PR workflow or a team lead automating code review pipelines, gh is an indispensable part of the modern developer toolkit.
Why Use gh?
Most developers already use git for version control, but git only covers the local side of the story. The moment you need to open a pull request, triage issues, or trigger a CI run, the traditional workflow forces you to open a browser. gh eliminates that context switch entirely.
- Speed — Create, review, and merge PRs in seconds without leaving the terminal.
- Scriptability — Combine
ghwith shell scripts,jq, andfzfto build powerful automation. - Consistent JSON output — Every command supports
--jsonflags for machine-readable output. - GitHub Actions integration — Trigger, list, and inspect workflow runs from your terminal.
- Cross-platform — Available on macOS, Linux, and Windows.
- Extensible — Install community extensions with
gh extension install.
Installation
# macOS (Homebrew)
brew install gh
# Debian / Ubuntu
sudo apt update && sudo apt install gh
# Fedora / RHEL
sudo dnf install gh
# Arch Linux
sudo pacman -S github-cli
# Windows (Winget)
winget install GitHub.cli
# Windows (Scoop)
scoop install gh
# Verify installation
gh --version
After installing, authenticate with your GitHub account:
gh auth login
# Follow the interactive prompts — supports browser OAuth or a personal access token
Basic Usage
# Authenticate
gh auth login
# Create a new PR from the current branch (auto-fills title and body from commits)
gh pr create --fill
# List open pull requests
gh pr list
# View a specific PR in the terminal
gh pr view 123
# Open a PR in the browser
gh pr view 123 --web
# Check out a PR locally for review
gh pr checkout 456
# Merge a PR
gh pr merge 123 --squash
Working with Issues
Issues are first-class citizens in gh. You can create, filter, assign, and close them entirely from the terminal.
# Create an issue interactively
gh issue create
# Create an issue non-interactively
gh issue create \
--title "Fix login redirect" \
--body "After OAuth the redirect URL is incorrect." \
--label "bug" \
--assignee "@me"
# List open issues assigned to you
gh issue list --assignee @me
# View an issue
gh issue view 99
# Close an issue
gh issue close 99 --comment "Fixed in PR #123"
# Reopen an issue
gh issue reopen 99
Working with GitHub Actions
gh makes it trivial to trigger and inspect CI/CD workflows without leaving the terminal.
# List recent workflow runs
gh run list
# Watch a workflow run live
gh run watch
# Manually trigger a workflow
gh workflow run deploy.yml --ref main
# List available workflows
gh workflow list
# View logs for a failed run
gh run view 123456 --log-failed
# Download artifacts from a run
gh run download 123456
💡 Tips & Tricks
Tip 1: Use --json and jq for Scripting
Almost every gh subcommand accepts a --json flag followed by a comma-separated list of fields. This makes it easy to pipe output into jq or other tools.
# Get a list of PR numbers and titles as JSON
gh pr list --json number,title,author | jq '.[] | "\(.number): \(.title) by \(.author.login)"' -r
Tip 2: Create PRs with a Template
When your repository has a pull request template, gh pr create respects it automatically. You can also specify a body file:
gh pr create --title "feat: add dark mode" --body-file .github/PULL_REQUEST_TEMPLATE.md
Tip 3: Set the Default Repository
If you work in a monorepo or have multiple remotes, tell gh which repo to use:
gh repo set-default owner/repo
Tip 4: Use gh alias to Create Shortcuts
# Create a shortcut for a common query
gh alias set prs 'pr list --author @me --state open'
# Now just run:
gh prs
Tip 5: Search Across GitHub
gh can search repositories, issues, and PRs across all of GitHub, not just your current repo:
# Search for open issues mentioning "memory leak" in a specific repo
gh issue list --repo cli/cli --search "memory leak" --state open
# Search for repos
gh repo list --limit 30 --language go
Tip 6: Clone Repositories Quickly
# Clone a repository (no need to copy the URL)
gh repo clone owner/repo
# Fork and clone in one command
gh repo fork owner/repo --clone
Tip 7: Manage Releases
# List releases
gh release list
# Create a new release
gh release create v1.2.0 --title "v1.2.0" --notes "Bug fixes and performance improvements."
# Upload an asset to a release
gh release upload v1.2.0 ./dist/app-linux-amd64
# Download the latest release
gh release download --pattern "*.tar.gz"
Advanced Applications
Batch Review and Merge PRs
This script finds open PRs targeting main, checks for passing CI, and merges those that are approved:
for pr in $(gh pr list --base main --state open --json number --jq '.[].number'); do
status=$(gh pr checks $pr --json conclusion --jq '.[0].conclusion')
approvals=$(gh pr view $pr --json reviews --jq '.reviews | map(select(.state=="APPROVED")) | length')
if [ "$status" = "SUCCESS" ] && [ "$approvals" -ge 1 ]; then
gh pr merge $pr --merge --admin
echo "Merged PR #$pr"
else
echo "Skipping PR #$pr (status: $status, approvals: $approvals)"
fi
done
Daily Standup Report
Generate a quick summary of your GitHub activity for a standup or daily log:
#!/bin/bash
echo "=== My Open PRs ==="
gh pr list --author @me --state open --json number,title,createdAt \
--jq '.[] | "#\(.number) \(.title) (opened \(.createdAt[:10]))"'
echo ""
echo "=== Issues Assigned to Me ==="
gh issue list --assignee @me --json number,title,labels \
--jq '.[] | "#\(.number) \(.title)"'
echo ""
echo "=== Recent Workflow Failures ==="
gh run list --status failure --limit 5 --json name,conclusion,updatedAt \
--jq '.[] | "\(.name) failed at \(.updatedAt[:16])"'
Integrating gh with fzf
Combine gh with fzf for interactive, fuzzy-searchable GitHub workflows:
# Interactively select and checkout a PR
gh pr list --json number,title,author \
--jq '.[] | "\(.number)\t\(.title)\t\(.author.login)"' | \
fzf --delimiter='\t' --preview 'gh pr view {1}' | \
awk '{print $1}' | \
xargs gh pr checkout
Extensions
The gh CLI has a rich extension ecosystem. Install community-built extensions to add new commands:
# Install an extension
gh extension install dlvhdr/gh-dash # dashboard for PRs and issues
# List installed extensions
gh extension list
# Upgrade all extensions
gh extension upgrade --all
Related Resources
Related Tools
git— local version control;ghcomplementsgitwith remote GitHub features.fzf— fuzzy finder that pairs beautifully withghfor interactive selection.jq— JSON processor for parsing and transforminggh --jsonoutput.
Real-world Use Cases
- Code review workflows — check out, review, approve, and merge PRs entirely from the terminal.
- Release automation — create tagged releases and upload compiled assets as part of a CI script.
- Issue triage — bulk-label, assign, and close issues using
ghin a shell loop. - CI monitoring — watch GitHub Actions workflow runs live and download failure logs automatically.
- Onboarding scripts — fork and clone repositories, set up issue templates, and configure branch protection rules programmatically.
When Not To Use gh
- Pure
gitoperations — cloning, committing, rebasing, and pushing are best handled bygitdirectly. - Complex GitHub administration — managing organization settings, billing, or audit logs is easier in the GitHub web UI.
- Offline work —
ghrequires an internet connection and GitHub authentication for all operations. - Non-GitHub remotes —
ghonly works with GitHub; use GitLab CLI (glab) or similar for other platforms.
Practical Examples: Automate Your GitHub Workflow with gh
# 1. Interactively pick a PR, check it out, and open it in the browser
gh pr list --json number,title,author \
--jq '.[] | "\(.number)\t\(.title)\t\(.author.login)"' | \
fzf --delimiter='\t' --preview 'gh pr view {1}' | \
awk '{print $1}' | xargs -I{} sh -c 'gh pr checkout {} && gh pr view {} --web'
# 2. Create a release and upload build artifacts in one pipeline
VERSION=$(git describe --tags --abbrev=0)
npm run build
gh release create "$VERSION" \
--title "Release $VERSION" \
--generate-notes \
dist/app-linux-amd64 dist/app-darwin-arm64
# 3. Close all issues with a specific label
gh issue list --label "wontfix" --json number --jq '.[].number' | \
xargs -I{} gh issue close {} --comment "Closing as wontfix."