← Back to DevBytes

GitHub CLI (gh): Complete Workflow Guide

What is GitHub CLI (gh)?

GitHub CLI, commonly invoked as gh, is an official command-line tool developed by GitHub that brings the entire GitHub experience directly into your terminal. It allows developers to interact with GitHub repositories, issues, pull requests, releases, workflows, and more—without ever leaving the command line. Written in Go, it is fast, cross-platform, and deeply integrated with GitHub's GraphQL and REST APIs.

Unlike traditional Git commands which only handle version control operations, gh bridges the gap between local development and GitHub's collaborative platform. You can create repositories, triage issues, review pull requests, trigger Actions workflows, manage releases, and even configure repository settings—all through a consistent, intuitive CLI interface.

Why gh Matters for Developers

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

For developers who spend most of their time in the terminal, switching context to a browser breaks flow and slows productivity. gh solves this by keeping GitHub interactions within the same environment where code is written and tested. Here are the key benefits:

Installation and Setup

Installing gh on Various Platforms

GitHub CLI is available through all major package managers. Choose the method appropriate for your operating system:

# macOS (Homebrew)
brew install gh

# macOS (MacPorts)
sudo port install gh

# Windows (winget)
winget install --id GitHub.cli

# Windows (scoop)
scoop install gh

# Linux (Debian/Ubuntu via official repository)
type -p curl >/dev/null || sudo apt install curl -y
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install gh -y

# Linux (Fedora)
sudo dnf install 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh.repo
sudo dnf install gh -y

# Linux (Arch)
sudo pacman -S github-cli

# Verify installation
gh --version

Authentication

Before using gh, you need to authenticate with your GitHub account. The tool supports multiple authentication methods including OAuth device flow, personal access tokens, and GitHub Enterprise Server login.

# Standard OAuth login (interactive browser flow)
gh auth login

# Login with specific scopes and protocol
gh auth login --scopes repo,workflow,admin:public_key --web

# Login via SSH (generates and uploads SSH key automatically)
gh auth login --scopes repo --ssh

# Login to GitHub Enterprise Server
gh auth login --hostname github.mycompany.com --web

# Login using a personal access token (non-interactive)
gh auth login --with-token < my-token-file.txt

# Check current authentication status
gh auth status

# Logout and remove credentials
gh auth logout

Once authenticated, credentials are stored securely in your system's credential store. You can verify your identity at any time with gh auth status, which displays the logged-in user, token scopes, and active GitHub host.

Core Workflow: Repositories

Creating and Cloning Repositories

Creating a new repository from the terminal is a single command. You can initialize it with a README, .gitignore, and license all at once, then clone it locally in one smooth motion.

# Create a new public repository on GitHub and clone it
gh repo create my-project --public --clone

# Create a private repository with a README and .gitignore
gh repo create my-private-app --private --add-readme --gitignore Node

# Create from an existing local directory
cd my-existing-project
git init
gh repo create my-existing-project --public --source=. --remote=origin --push

# Fork an existing repository
gh repo fork octocat/hello-world --clone

# List all your repositories
gh repo list

# List repositories for a specific organization
gh repo list my-org --limit 50

Managing Repository Settings

Beyond creation, gh lets you view and modify repository metadata, topics, visibility, and more without opening the browser.

# View repository details
gh repo view owner/repo --web

# Display repository info in terminal (description, stars, forks, etc.)
gh repo view owner/repo --json name,description,stargazerCount,forkCount

# Edit repository topics
gh repo edit owner/repo --add-topic cli,tool,devops

# Change repository visibility
gh repo edit owner/repo --visibility public

Working with Issues

Issues are the backbone of project planning on GitHub. gh provides a complete issue management workflow—from creation to closing, with labels, assignments, and milestones.

Creating and Listing Issues

# Create a new issue with title and body
gh issue create --title "Fix memory leak in parser" --body "The parser module leaks memory when processing large files."

# Create an issue with labels, assignee, and milestone
gh issue create \
  --title "Update dependencies for v2.0" \
  --body "All npm packages need to be updated to latest versions." \
  --label "enhancement,dependencies" \
  --assignee "@me" \
  --milestone "v2.0"

# List open issues in current repository
gh issue list

# List issues filtered by label and assignee
gh issue list --label bug --assignee "@me"

# List issues with custom limit and state
gh issue list --state all --limit 100

# Search issues across repositories
gh search issues "memory leak" --repo owner/repo --state open

# View issue details in terminal
gh issue view 42

# Open issue in browser
gh issue view 42 --web

Managing Issue Lifecycle

# Edit an existing issue (interactive editor)
gh issue edit 42 --title "Updated title" --body "Updated description"

# Add or remove labels
gh issue edit 42 --add-label priority-high --remove-label low-priority

# Assign users
gh issue edit 42 --add-assignee username1,username2

# Set milestone
gh issue edit 42 --milestone "Sprint 5"

# Lock an issue to prevent further comments
gh issue lock 42 --reason "resolved"

# Unlock an issue
gh issue unlock 42

# Close an issue with a comment
gh issue close 42 --comment "Fixed in PR #128"

# Reopen a closed issue
gh issue reopen 42 --comment "Reopening due to regression"

Bulk Operations with Issues

# Close multiple issues by label
gh issue list --label obsolete --state open --json number | jq -r '.[].number' | while read num; do
  gh issue close "$num" --comment "Closing obsolete issues"
done

# Bulk assign issues to a team member
for issue in $(gh issue list --label triage --state open --json number -q '.[].number'); do
  gh issue edit "$issue" --add-assignee developer-name
done

Pull Request Workflow

The pull request workflow is where gh truly shines. You can create, review, merge, and manage PRs entirely from the command line, streamlining the code review process significantly.

Creating Pull Requests

# Create a PR from current branch (auto-detects base branch)
gh pr create --title "Add user authentication module"

# Create PR with detailed body and draft status
gh pr create \
  --title "Implement OAuth2 flow" \
  --body "This PR adds the OAuth2 authentication flow with support for Google and GitHub providers. Includes unit tests and documentation." \
  --base main \
  --head feature/oauth2 \
  --draft

# Create PR and assign reviewers
gh pr create \
  --title "Refactor database layer" \
  --reviewer alice,bob \
  --assignee "@me" \
  --label refactor,needs-review

# Create PR with specific milestone and project
gh pr create \
  --title "Performance improvements" \
  --milestone "v1.5" \
  --label performance

# Create PR from a template (if .github/PULL_REQUEST_TEMPLATE.md exists)
gh pr create --template

# Fill PR body from a file
gh pr create --title "API documentation update" --body-file docs/pr-description.md

Reviewing and Checking Pull Requests

# List open PRs in current repository
gh pr list

# List PRs with specific state and author
gh pr list --state open --author "@me"

# List PRs awaiting your review
gh pr list --search "review-requested:@me"

# View PR details (description, checks, reviews)
gh pr view 128

# Check PR status including CI checks
gh pr checks 128

# View PR in browser
gh pr view 128 --web

# Check out a PR locally for review
gh pr checkout 128

# Show diff of a PR
gh pr diff 128

Reviewing and Approving PRs

# Approve a pull request
gh pr review 128 --approve --body "Looks great! Ready to merge."

# Request changes
gh pr review 128 --request-changes --body "Please add error handling for the edge case discussed."

# Leave a general comment
gh pr review 128 --comment --body "I left some inline comments, overall looks good."

# Add inline comments on specific files (requires interactive mode)
gh pr review 128 --comment

# Submit a review and auto-close related issues
gh pr review 128 --approve --body "Fixes #42 and #43"

Merging and Managing PRs

# Merge a PR using squash merge
gh pr merge 128 --squash

# Merge with rebase strategy
gh pr merge 128 --rebase

# Merge with standard merge commit
gh pr merge 128 --merge

# Merge and delete the branch automatically
gh pr merge 128 --squash --delete-branch

# Merge with custom commit body
gh pr merge 128 --squash --body "Squashing all commits for release v1.5"

# Close a PR without merging
gh pr close 128 --comment "Superseded by PR #150"

# Reopen a closed PR
gh pr reopen 128

# Edit PR title and body
gh pr edit 128 --title "Updated PR title" --body "Updated description"

# Change base branch of a PR
gh pr edit 128 --base develop

Managing Releases

Creating releases is essential for shipping software. gh simplifies release creation with changelog generation, asset uploads, and release notes management.

# Create a new release with auto-generated release notes
gh release create v1.2.0 --generate-notes

# Create release with custom notes
gh release create v1.2.0 --title "Version 1.2.0 - Stability Update" --notes "Fixed critical bugs and improved performance."

# Create release with notes from a file
gh release create v1.2.0 --notes-file CHANGELOG.md

# Create a prerelease
gh release create v2.0.0-beta.1 --prerelease --generate-notes

# Upload binary assets to a release
gh release create v1.2.0 \
  --generate-notes \
  ./build/app-linux-x64.tar.gz \
  ./build/app-macos-x64.dmg \
  ./build/app-windows-x64.exe

# List all releases
gh release list

# List releases with limit
gh release list --limit 10

# View specific release details
gh release view v1.2.0

# Download release assets
gh release download v1.2.0 --pattern '*.tar.gz'

# Delete a release
gh release delete v1.0.0-deprecated

# Edit an existing release
gh release edit v1.2.0 --title "Updated title" --notes "Updated notes"

GitHub Actions and Workflows

gh provides direct access to GitHub Actions, allowing you to trigger workflows, view run logs, and monitor CI/CD pipelines without leaving the terminal.

# List all workflow files in the repository
gh workflow list

# View details of a specific workflow
gh workflow view "CI Pipeline"

# Trigger a workflow run manually
gh workflow run "CI Pipeline" --ref main

# Trigger workflow with custom inputs
gh workflow run "Deploy" --ref main -f environment=production -f version=v1.2.0

# List recent workflow runs
gh run list

# List runs for a specific workflow
gh run list --workflow "CI Pipeline"

# List runs filtered by status
gh run list --status failure --limit 5

# View details of a specific run
gh run view 12345

# View run logs in terminal
gh run view 12345 --log

# View logs for a specific job
gh run view 12345 --job build --log

# Download run logs as a zip file
gh run view 12345 --log --output logs.zip

# Cancel a running workflow
gh run cancel 12345

# Re-run a failed workflow
gh run rerun 12345

# Delete a workflow run
gh run delete 12345

# Watch a workflow run in real-time
gh run watch 12345

Gists and Code Sharing

Gists are lightweight code snippets that can be created, shared, and managed entirely through gh.

# Create a public gist from a file
gh gist create script.sh

# Create a private gist with description
gh gist create config.yaml --desc "Server configuration template" --private

# Create a gist from multiple files
gh gist create file1.py file2.py --desc "Utility scripts"

# Create a gist from stdin
echo "print('Hello World')" | gh gist create -d "Simple Python hello world"

# List your gists
gh gist list

# List gists with limit
gh gist list --limit 20

# List public gists for a user
gh gist list --public username

# View a gist
gh gist view abc123def456

# View gist in browser
gh gist view abc123def456 --web

# Edit a gist (add or update files)
gh gist edit abc123def456 --add newfile.txt --rename oldfile.txt newname.txt

# Delete a gist
gh gist delete abc123def456

Working with Projects (GitHub Projects Beta)

For teams using GitHub Projects for project management, gh offers commands to interact with project boards, items, and fields.

# List projects in an organization
gh project list --org my-org

# List projects for a user
gh project list --user username

# View project details
gh project view 123

# List items in a project
gh project item-list 123 --org my-org

# Add an issue to a project
gh project item-add 123 --org my-org --url https://github.com/my-org/repo/issues/42

# Add a draft item
gh project item-add 123 --org my-org --title "Research new framework"

# Edit item fields
gh project item-edit  --field-name Status --field-value "In Progress"

# Archive a project item
gh project item-archive 

# View item details
gh project item-view 

Secret and Variable Management

Managing repository and organization secrets for GitHub Actions is straightforward with gh.

# List repository secrets
gh secret list

# List organization secrets
gh secret list --org my-org

# Set a repository secret
gh secret set DEPLOY_KEY --body "secret-value-here"

# Set a secret from a file
gh secret set AWS_CREDENTIALS < credentials.json

# Set an organization secret
gh secret set SHARED_TOKEN --org my-org --body "token-value"

# Set a secret with visibility to specific repos
gh secret set SHARED_KEY --org my-org --body "key-value" --visibility selected --repos repo1,repo2

# Remove a secret
gh secret delete DEPLOY_KEY

# Remove an organization secret
gh secret delete SHARED_TOKEN --org my-org

# List repository variables
gh variable list

# Set a variable
gh variable set ENVIRONMENT --body "production"

# Set an organization variable
gh variable set DEFAULT_REGION --org my-org --body "us-east-1"

# Delete a variable
gh variable delete ENVIRONMENT

Aliases and Extensions

gh supports custom aliases for frequently used commands and a rich extension system for adding functionality beyond the built-in commands.

Creating Command Aliases

# Create an alias for listing issues assigned to you
gh alias set mine 'issue list --assignee @me --state open'

# Create an alias with arguments
gh alias set review 'pr list --search "review-requested:@me" --state open'

# Create an alias that chains commands
gh alias set ship '!gh pr merge $(gh pr list --author @me --state open --json number -q ".[0].number") --squash --delete-branch'

# List all defined aliases
gh alias list

# Delete an alias
gh alias delete mine

Using and Creating Extensions

# List installed extensions
gh extension list

# Install an extension from a repository
gh extension install meiji163/gh-emoji

# Install from a local directory during development
gh extension install ./my-extension

# Search for extensions in the official catalog
gh extension search workflow

# Upgrade all extensions
gh extension upgrade --all

# Upgrade a specific extension
gh extension upgrade owner/extension-name

# Remove an extension
gh extension remove owner/extension-name

# Create your own extension (any executable prefixed with gh-)
# Example: gh-mycommand is invoked as 'gh mycommand'
# Write it in any language, place it on PATH, and gh discovers it automatically

Advanced JSON Output and Scripting

One of the most powerful features of gh is its structured JSON output combined with --jq or --template filtering, enabling sophisticated shell scripting and automation.

# Get repository stats as JSON
gh repo view --json name,description,stargazerCount,forkCount,watchers

# Filter JSON output with built-in jq expressions
gh issue list --state open --json number,title,labels \
  --jq '.[] | select(.labels[].name == "bug") | {number, title}'

# Use template syntax for custom output formatting
gh pr list --state open --json number,title,author \
  --template '{{range .}}{{tablerow (printf "#%v" .number | autocolor) .title .author.login}}{{end}}'

# Extract specific fields for scripting
PR_COUNT=$(gh pr list --state open --json number -q 'length')
echo "There are $PR_COUNT open pull requests"

# Bulk close stale issues (30+ days with no activity)
gh issue list --state open --label stale --json number,updatedAt \
  --jq '.[] | select(.updatedAt | fromdateiso8601 < now - 30*24*3600) | .number' \
  | while read num; do
    gh issue close "$num" --comment "Closing stale issue due to inactivity"
  done

# Get all failed workflow runs and their URLs
gh run list --status failure --limit 10 --json databaseId,url,displayTitle \
  --jq '.[] | "\(.displayTitle): \(.url)"'

Configuration and Customization

gh stores its configuration in ~/.config/gh/config.yml (or the equivalent on Windows). You can customize various settings to tailor the experience to your workflow.

# View current configuration
gh config list

# Set default editor for gh commands
gh config set editor "vim"

# Set default browser
gh config set browser "firefox"

# Configure git protocol preference
gh config set git_protocol ssh

# Enable/disable prompts (useful for CI)
gh config set prompt disabled

# Set default repository for commands
gh config set current-repo owner/repo

# Reset a configuration value
gh config reset editor

Example config.yml structure:

# ~/.config/gh/config.yml
git_protocol: ssh
editor: vim
prompt: enabled
browser: firefox
aliases:
  mine: issue list --assignee @me --state open
  review: pr list --search "review-requested:@me"
version: "1"

GitHub Enterprise Server

For organizations using GitHub Enterprise Server (GHES), gh provides first-class support with multiple host configurations and enterprise-specific features.

# Authenticate to an enterprise instance
gh auth login --hostname github.mycompany.com --web

# Authenticate with a token for enterprise
gh auth login --hostname github.mycompany.com --with-token < enterprise-token.txt

# List configured hosts
gh auth status --show-token

# Specify host when running commands
gh repo list --host github.mycompany.com

# Create repo on enterprise instance
gh repo create new-project --host github.mycompany.com --private

# Switch between multiple GitHub hosts
gh auth switch

# Set default host
gh config set default-host github.mycompany.com

CI/CD Integration Patterns

gh is designed for automation and works seamlessly in CI/CD environments. Here are common patterns for using it in pipelines:

# Authenticate in CI using a token (GitHub Actions automatically provides GITHUB_TOKEN)
# .github/workflows/example.yml
jobs:
  automate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Create release on tag push
        if: startsWith(github.ref, 'refs/tags/')
        run: |
          gh release create ${{ github.ref_name }} --generate-notes --verify-token
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Auto-label issues from triage
        run: |
          gh issue list --label triage --state open --json number \
            --jq '.[].number' | while read num; do
            gh issue edit "$num" --add-label needs-triage --remove-label triage
          done
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Script to auto-close issues mentioned in merged PR descriptions
#!/bin/bash
# Run this after PR merge to auto-close linked issues

PR_NUMBER=$1
PR_BODY=$(gh pr view "$PR_NUMBER" --json body -q '.body')

# Extract issue references (e.g., "Fixes #42" or "Closes #43")
echo "$PR_BODY" | grep -oP '(?:fixes|closes|resolves)\s+#\d+' | while read -r reference; do
  ISSUE_NUM=$(echo "$reference" | grep -oP '\d+')
  gh issue close "$ISSUE_NUM" --comment "Closed automatically by PR #$PR_NUMBER"
done

Best Practices

1. Use JSON Output for Automation

Always prefer --json with --jq or --template for scripting. Avoid parsing human-readable table output, which can change between versions.

# Good: structured and parseable
gh issue list --state open --json number,title --jq '.[].number'

# Avoid: parsing table output
gh issue list --state open | awk '{print $1}'  # Fragile and unreliable

2. Leverage GITHUB_TOKEN in Actions

In GitHub Actions workflows, gh automatically picks up the GITHUB_TOKEN environment variable. No additional authentication setup is needed. Always scope your token permissions appropriately in workflow files.

3. Use Draft PRs for Work-in-Progress

Create PRs as drafts when starting work that isn't ready for review. This signals to teammates that the code is not yet ready while still benefiting from CI checks.

gh pr create --title "WIP: Refactoring auth module" --draft

4. Combine Commands for Efficient Workflows

Chain gh commands together to build efficient, multi-step workflows. For example, create an issue, assign it, and create a branch in one script.

#!/bin/bash
# Quick bug fix workflow
ISSUE=$(gh issue create --title "Fix null pointer in parser" --body "Found during testing" --label bug --assignee "@me")
ISSUE_NUM=$(echo "$ISSUE" | grep -oP 'https://github\.com/.+/issues/\K\d+')
git checkout -b "fix/issue-$ISSUE_NUM"
echo "Created issue #$ISSUE_NUM and switched to branch fix/issue-$ISSUE_NUM"

5. Keep Aliases Organized

Define aliases for commands you use frequently, but keep them focused and well-named. Share useful aliases with your team via documentation or dotfiles.

# Recommended aliases
gh alias set ci 'run list --workflow "CI" --limit 5'
gh alias set deploy 'workflow run "Deploy" --ref main'
gh alias set todo 'issue list --assignee @me --state open --limit 10'
gh alias set unread 'pr list --search "review-requested:@me" --state open'

6. Use --verify-token in Sensitive Operations

When running gh commands that modify data in CI environments, use --verify-token to ensure the token has the required scopes before attempting operations.

gh release create v1.0.0 --generate-notes --verify-token

7. Template Your PRs and Issues

Use .github/PULL_REQUEST_TEMPLATE.md and .github/ISSUE_TEMPLATE to standardize contributions. gh automatically detects and pre-fills these templates when creating PRs and issues.

8. Automate Release Processes

Combine gh with Git tags and CI to fully automate releases. Generate release notes automatically from merged PRs and commits.

# Automated release script
git tag v$(cat VERSION)
git push --tags
gh release create "$(cat VERSION)" \
  --generate-notes \
  --verify-token \
  ./dist/*.tar.gz \
  ./dist/*.dmg

9. Use gh for Code Review Collaboration

When reviewing PRs, use gh pr checkout to test changes locally, then approve or request changes directly from the terminal. This keeps the review workflow fast and focused.

gh pr checkout 128
# Test the changes locally...
gh pr review 128 --approve --body "Tested locally, LGTM!"

10. Secure Credential Management

Never hardcode tokens in scripts. Use environment variables, CI secret stores, or gh auth login for interactive sessions. Regularly rotate personal access tokens and use fine-grained tokens with minimal scopes.

Troubleshooting Common Issues

Authentication Problems

# If gh commands fail with authentication errors
gh auth status

# Refresh authentication if token expired
gh auth refresh --scopes repo,workflow

# Re-authenticate entirely
gh auth logout
gh auth login --scopes repo,workflow,admin:public_key

Rate Limiting

# Check current rate limit status
gh api /rate_limit --jq '.rate'

# Use authenticated requests to get higher limits
gh auth status --show-token  # Verify you're authenticated

Debugging gh Commands

# Enable debug output for troubleshooting
GH_DEBUG=1 gh issue list

# Use verbose mode for detailed command output
gh issue view 42 --verbose

# Check gh version and update if needed
gh --version
gh update

Conclusion

GitHub CLI (gh) transforms how developers interact with GitHub by bringing the full power of the platform into the terminal. From repository management and issue triage to pull request reviews and CI/CD automation, gh eliminates friction and keeps you in flow. Its structured JSON output, extensible alias system, and seamless CI integration make it an indispensable tool for modern software development workflows.

By mastering the commands and patterns covered in this guide, you can dramatically accelerate your daily development tasks, reduce context switching, and build more efficient, scriptable workflows. Whether you're a solo developer managing side projects or part of a large engineering team coordinating complex releases, gh adapts to your needs. Start with the basics, build your alias collection, and gradually incorporate advanced scripting patterns—you'll quickly wonder how you ever worked without it.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles