The gh CLI, GitHub’s official command-line interface, is surprisingly more than just a shortcut for web actions; it’s a powerful tool that reshapes how you interact with GitHub by bringing its rich API directly to your shell.
Let’s see it in action. Imagine you’ve just pushed a new feature branch and want to open a pull request. Instead of navigating to the GitHub website, clicking "New pull request," selecting your branch, filling out the title and description, and then clicking "Create pull request," you can do this:
gh pr create --base main --head feature/my-new-feature --title "Implement awesome new thing" --body "This PR adds the core logic for the new feature. See #123 for related issue."
This single command achieves the same outcome. The gh CLI interacts with the GitHub API behind the scenes, translating your shell commands into HTTP requests.
The core problem gh solves is bridging the gap between the command line and the vast functionality of GitHub. Developers often live in their terminals for coding, building, and testing. Managing GitHub resources—pull requests, issues, releases, repository settings—traditionally required context switching to a web browser. gh eliminates this friction, allowing for a more fluid and efficient workflow. It enables automation of GitHub tasks, integration into CI/CD pipelines, and a deeper understanding of repository state without leaving the terminal.
Internally, gh authenticates using your GitHub credentials (either via a web login flow or a personal access token) and then makes direct calls to the GitHub REST and GraphQL APIs. This means you have access to nearly everything you can do on the GitHub website, and often more, directly from your command line.
The primary levers you control are the various subcommands and their flags. For instance, managing pull requests:
gh pr list: See open pull requests.gh pr view <pr-number>: Get detailed information about a specific PR.gh pr checkout <pr-number>: Download and checkout a PR’s branch locally.gh pr merge <pr-number>: Merge a pull request.gh pr close <pr-number>: Close a pull request.
Similarly, for issues:
gh issue list: List issues.gh issue view <issue-number>: View an issue.gh issue create --title "Bug in login" --body "Users are unable to log in after recent update.": Create a new issue.gh issue close <issue-number>: Close an issue.
You can also manage repositories, Gists, releases, and even interact with GitHub Actions workflows. The gh repo subcommand offers options like clone, fork, and edit, while gh release allows for creating, uploading assets to, and deploying releases.
The real power, however, emerges when you start scripting. Imagine needing to update the labels on all open pull requests in a large project. You could combine gh pr list with gh pr edit in a loop:
gh pr list --state open --json number | jq -r '.[].number' | while read -r pr_number; do
gh pr edit "$pr_number" --add-label "needs-review"
done
This script fetches the numbers of all open PRs, pipes them to jq to extract just the numbers, and then iterates through each number, adding the "needs-review" label. This level of automation is a significant productivity boost for maintainers and contributors alike.
When you use gh api, you’re directly interacting with the GitHub REST API. The command gh api repos/OWNER/REPO/issues?state=open will return a JSON response containing all open issues for that repository. This is incredibly useful for custom scripting and for accessing data that might not have a dedicated gh subcommand yet. The flexibility here is immense; you can query any endpoint the GitHub API exposes.
Many users are unaware that gh supports GitHub’s GraphQL API via the gh api graphql command. This allows for much more efficient data fetching by requesting only the specific fields you need, rather than the often verbose responses from REST endpoints. For example, to get the title and author of the first 10 open issues:
gh api graphql -f query='
query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
issues(first: 10, states: OPEN) {
nodes {
title
author { login }
}
}
}
}
' -f owner='your-username' -f repo='your-repo'
This approach reduces the amount of data transferred and processed, making it ideal for complex queries or performance-sensitive scripts.
The next step in mastering gh is understanding how to integrate it into your shell environment for even greater convenience and automation.