How to Use GitHub CLI (gh) on Linux: The Complete Guide (2026)

Tested on: GitHub CLI 2.96 — Last updated: July 2026
GitHub CLI (gh) brings issues, pull requests, releases, Actions runs, and the GitHub API into your terminal — no browser tab-switching required. It replaced hub, the older unofficial GitHub tool, which GitHub itself now points users away from. This guide covers installation on every major Linux distro, authentication, the full day-to-day command set, scripting with gh api, and the newest addition to the tool: gh skill, for installing AI agent skills straight from a repository.
- What Is GitHub CLI and Why Use It Over the Web UI
- Step 1 — Install GitHub CLI
- Step 2 — Authenticate
- Step 3 — Configure gh
- Working With Repositories
- Issues
- Pull Requests: The Full Review Workflow
- Gists and Releases
- GitHub Actions From the Terminal
- Scripting With gh api
- Aliases and Extensions
- gh skill: Installing AI Agent Skills From the CLI (Preview)
- Newer Command Groups Worth Knowing
- Troubleshooting
- Frequently Asked Questions
What Is GitHub CLI and Why Use It Over the Web UI
gh is GitHub's official command-line tool, maintained by GitHub itself (not a third-party wrapper). It talks to the same REST and GraphQL APIs the website uses, so anything you can do on github.com, you can script or automate from a terminal.
| Task | Web UI | gh CLI |
|---|---|---|
| Review a PR | Click through tabs, switch branches manually | gh pr checkout 42 && gh pr diff |
| Create an issue from a script | Not possible without the API directly | gh issue create --title "..." --body "..." |
| Check CI status | Refresh the page | gh pr checks --watch |
| Bulk operations | One at a time, manually | Pipe gh output through jq and loop |
| Stay in the terminal | No | Yes — no context switching |
If you're still finding tutorials that reference hub — GitHub's earlier CLI tool — skip them. hub is unmaintained and GitHub has directed users to gh since 2020.
Step 1 — Install GitHub CLI
Debian and Ubuntu
Don't run a plain apt install gh — Debian's own gh package is an unrelated tool (GNU Hello alternative), not GitHub CLI. Add the official repository instead:
(type -p wget >/dev/null || (sudo apt update && sudo apt-get install wget -y)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
&& cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& sudo mkdir -p -m 755 /etc/apt/sources.list.d \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages/deb stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -yFedora (DNF5)
sudo dnf install dnf5-plugins
sudo dnf config-manager addrepo --from-repofile=https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install gh --repo gh-cliRHEL, CentOS Stream, Rocky, AlmaLinux (DNF4/YUM)
sudo dnf install 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install gh --repo gh-cli
# On systems still using yum instead of dnf:
sudo yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo yum install gh --repo gh-cliArch Linux
sudo pacman -S github-cliNote the package name is github-cli, not gh — searching pacman -Ss gh alone won't find it.
Cross-distro: Conda
conda install gh --channel conda-forgeAvoid the Snap package. It's available, but GitHub's own maintainers discourage it — Snap's confinement model causes issues with SSH key access and credential storage that the native packages don't have.
Step 2 — Authenticate
gh auth loginThis starts an interactive flow:
- Choose GitHub.com or a GitHub Enterprise hostname
- Choose your preferred protocol for git operations: HTTPS or SSH
- Choose an authentication method: browser-based login (recommended — opens a one-time device code in your browser) or paste an existing personal access token
- If you picked SSH and don't have a key yet,
ghoffers to generate and upload one for you
For scripted or CI environments, skip the interactive flow entirely:
# Read a token from stdin — no prompts
echo "$GH_TOKEN" | gh auth login --with-token
# Or authenticate with the browser directly
gh auth login --web
# Verify who you're authenticated as and which scopes you have
gh auth statusMinimum token scopes for full functionality: repo, read:org, gist. Add -s workflow to gh auth login if you need to push changes to GitHub Actions workflow files.
Step 3 — Configure gh
Settings live in ~/.config/gh/config.yml. Edit them directly or use the command:
# Set your default editor for commit messages, issue bodies, etc.
gh config set editor "vim"
# Set the default git protocol
gh config set git_protocol ssh
# Disable the interactive prompt in scripts (useful for automation)
gh config set prompt disabled
# See all current settings
gh config listWorking With Repositories
# Clone a repo — no need to type the full URL
gh repo clone owner/repo
# Create a new repo from the current directory
gh repo create my-project --public --source=. --push
# Fork a repo and clone your fork in one step
gh repo fork owner/repo --clone
# View a repo in the terminal (or --web to open it in the browser)
gh repo view owner/repoIssues
# List open issues assigned to you
gh issue list --assignee @me
# Create an issue
gh issue create --title "Bug: login fails on Safari" --body "Steps to reproduce..."
# View an issue with comments
gh issue view 123 --comments
# Close an issue with a comment
gh issue close 123 --comment "Fixed in v2.1"Pull Requests: The Full Review Workflow
This is where gh earns its place over the web UI — reviewing a PR end-to-end without leaving the terminal:
# Create a PR from your current branch
gh pr create --title "Add rate limiting" --body "Closes #45" --base main
# Check out someone else's PR locally to test it
gh pr checkout 42
# Review the diff right in the terminal
gh pr diff 42
# Watch CI checks until they finish
gh pr checks 42 --watch
# Approve, request changes, or leave a comment-only review
gh pr review 42 --approve --body "LGTM"
gh pr review 42 --request-changes --body "Needs tests for the edge case"
# Merge once checks pass — squash, merge, or rebase
gh pr merge 42 --squash --delete-branchGists and Releases
# Create a gist from a file
gh gist create script.sh --public
# Create a release with a changelog and attached binaries
gh release create v1.2.0 ./dist/*.tar.gz --title "v1.2.0" --notes "See CHANGELOG.md"
# List releases
gh release listGitHub Actions From the Terminal
# List workflows in the repo
gh workflow list
# Trigger a workflow manually (must have workflow_dispatch configured)
gh workflow run deploy.yml
# List recent runs
gh run list --workflow=ci.yml
# Watch a run live, streaming logs as it executes
gh run watch
# View only the logs from a failed step — skips scrolling through the whole run
gh run view --log-failed
# Re-run a failed workflow, or just the failed jobs
gh run rerun 123456789
gh run rerun 123456789 --failedScripting With gh api
Every GitHub REST and GraphQL endpoint is reachable through gh api with your authenticated session already attached — no manual token handling in scripts:
# Raw REST call
gh api repos/owner/repo/issues
# GraphQL query
gh api graphql -f query='
query($owner:String!, $repo:String!) {
repository(owner:$owner, name:$repo) {
stargazerCount
}
}' -f owner=owner -f repo=repo
# POST a new issue via the API directly
gh api repos/owner/repo/issues -f title="API-created issue" -f body="Body text"Combine --json and --jq on the higher-level commands to extract exactly the fields you need — this is the difference between a one-off lookup and a real automation script:
# Get just PR numbers and titles as clean output
gh pr list --json number,title,author --jq '.[] | "\(.number): \(.title) by \(.author.login)"'
# Find every open issue with the "bug" label, output as a table
gh issue list --label bug --json number,title,url --jq '.[] | [.number, .title, .url] | @tsv'
# Use --template for Go-template formatting instead of jq
gh pr list --json title,url --template '{{range .}}{{.title}}: {{.url}}{{"\n"}}{{end}}'Aliases and Extensions
Aliases turn long commands into short ones you'll actually remember:
# Alias a full command, including flags
gh alias set prs 'pr list --assignee @me'
gh alias set co 'pr checkout'
# Now just run:
gh prs
gh co 42
# List all aliases
gh alias listExtensions add entirely new subcommands, built and shared by the community:
# Search available extensions
gh extension search dash
# Install one — example: a visual dashboard of your PRs and issues
gh extension install dlvhdr/gh-dash
# List installed extensions
gh extension list
# Update all of them at once
gh extension upgrade --allgh skill: Installing AI Agent Skills From the CLI (Preview)
The newest addition to GitHub CLI has nothing to do with git operations — it manages AI agent skills, the same kind of packaged capability you'd load into Claude Code or another agentic coding tool. It's in preview and the surface may still change, but the core commands are already usable:
# Search for available skills in a repository or across GitHub
gh skill search terraform
# Preview a skill's contents before installing it
gh skill preview owner/repo/skill-name
# Install a skill
gh skill install owner/repo/skill-name
# List what's currently installed
gh skill list
# Update everything at once
gh skill update --all
# Package your own skill for publishing
gh skill publish --dry-runThe short alias gh skills works the same way. If you're already using agent skills with Claude Code on Linux, this is the fastest way to pull one straight from a GitHub repo without manually cloning and copying files.
Newer Command Groups Worth Knowing
# Codespaces — create, list, connect via SSH, stop
gh codespace create
gh codespace list
gh codespace ssh
# Projects (the GitHub Projects board, v2)
gh project list
gh project item-add 1 --url https://github.com/owner/repo/issues/5
# Search across all of GitHub from the terminal
gh search repos "language:go stars:>1000"
gh search issues "is:open label:bug" --repo owner/repoTroubleshooting
gh auth status shows the wrong account or scopes
You may be authenticated to multiple accounts or hosts at once. List and switch explicitly:
gh auth status --active
gh auth switch --hostname github.com --user your-usernameScripts fail with a permissions or scope error
Your token is missing a required scope. Re-authenticate with the scope added rather than trying to patch it:
gh auth login --scopes "repo,read:org,workflow"GH_TOKEN vs GITHUB_TOKEN — which one gh actually uses
gh reads GH_TOKEN first; if that's unset, it falls back to GITHUB_TOKEN. Inside GitHub Actions runners, GITHUB_TOKEN is set automatically — but if you've also exported a personal GH_TOKEN in your shell profile, it silently takes priority over the Actions-provided token, which is a common source of "wrong permissions" confusion in custom scripts run inside workflows.
SSO-protected organizations reject API calls despite being logged in
Organizations with SAML SSO enforcement require you to separately authorize your token for that specific org, even after a successful gh auth login:
gh api orgs/your-org/... # fails with a 403 mentioning SSO
# Authorize your token for the org from: https://github.com/settings/tokens
# then re-run the commandFrequently Asked Questions
Is GitHub CLI the same as hub?
No. hub was an earlier, unofficial wrapper around git. GitHub CLI is the official replacement, built and maintained by GitHub directly, with a much larger command surface (Actions, API access, Codespaces, Projects) that hub never had.
Does GitHub CLI work with GitHub Enterprise Server?
Yes — pass --hostname your-enterprise-host to gh auth login, and most commands work identically against a GHE instance.
Can I use gh without git installed?
Some commands (issues, PR viewing, API calls, Actions) work without a local git repo. Cloning and PR checkout obviously require git itself.
Is gh api rate-limited the same as the REST API?
Yes, it uses your authenticated token and is subject to the same GitHub API rate limits. Check your remaining quota with gh api rate_limit.
