Skip to content

Github Cli

Verified

Comprehensive GitHub CLI (gh) reference. Covers repos, issues, PRs, Actions, releases, gists, search, projects v2, API, secrets/variables, labels, codespaces...

1,599 downloads
$ Add to .claude/skills/

About This Skill

# GitHub CLI (`gh`) — Comprehensive Skill

Version: gh 2.66.1+ Auth: `gh auth login` or set `GH_TOKEN` env var Always use `--repo OWNER/REPO` (or `-R`) when not inside a git repo directory.

---

Table of Contents

  1. Authentication & Config
  2. Repositories
  3. Issues
  4. Pull Requests
  5. GitHub Actions (Runs & Workflows)
  6. Releases
  7. Gists
  8. Search
  9. Labels
  10. Secrets & Variables
  11. Caches
  12. Projects V2
  13. API (REST & GraphQL)
  14. Extensions
  15. Codespaces
  16. Copilot
  17. Other Commands
  18. JSON Output & Formatting
  19. Environment Variables
  20. Advanced Patterns
  21. Tips & Gotchas

---

1. Authentication & Config

Auth

```bash # Interactive login (browser-based OAuth) gh auth login

# Login with a PAT from stdin echo "$MY_TOKEN" | gh auth login --with-token

# Login to GitHub Enterprise gh auth login --hostname enterprise.example.com

# Add extra scopes (e.g., project scope for Projects V2) gh auth refresh -s project

# Add delete_repo scope gh auth refresh -s delete_repo

# Check auth status (shows active account, scopes, token validity) gh auth status gh auth status --show-token

# Switch active account (when multiple accounts configured) gh auth switch

# Print the active token (useful for piping to other tools) gh auth token

# Logout gh auth logout ```

Required scopes by feature: | Feature | Scope needed | |---------|-------------| | Basic repo/PR/issue ops | `repo` | | Gists | `gist` | | Read org membership | `read:org` | | Projects V2 | `project` | | Delete repos | `delete_repo` | | Actions workflows | `workflow` | | Read user profile | `user` |

Config

```bash # List all config gh config list

# Get/set individual values gh config get git_protocol # https or ssh gh config set git_protocol ssh gh config set editor "code --wait" gh config set pager "less -R" gh config set prompt disabled # disable interactive prompts (good for scripts) gh config set browser "firefox"

# Clear CLI cache gh config clear-cache ```

Git credential setup

```bash # Configure git to use gh for HTTPS auth gh auth setup-git ```

---

2. Repositories

Create

```bash # Interactive gh repo create

# Public repo, clone locally gh repo create my-project --public --clone

# In an org gh repo create my-org/my-project --private

# From local directory gh repo create my-project --private --source=. --remote=upstream --push

# From template gh repo create my-project --template owner/template-repo --clone

# With options gh repo create my-project --public --description "My project" \ --license mit --gitignore Node --add-readme ```

Clone

```bash gh repo clone owner/repo gh repo clone owner/repo my-dir gh repo clone owner/repo -- --depth=1 # shallow clone

# Clone your own repo (owner defaults to you) gh repo clone my-repo ```

Fork

```bash # Fork current repo gh repo fork

# Fork and clone gh repo fork owner/repo --clone

# Fork into an org gh repo fork owner/repo --org my-org --fork-name new-name

# Fork default branch only gh repo fork owner/repo --default-branch-only ```

View

```bash # View current repo (README + description) gh repo view gh repo view owner/repo

# Open in browser gh repo view --web

# JSON output gh repo view --json name,description,stargazerCount,url gh repo view --json name,stargazerCount --jq '.stargazerCount' ```

JSON fields for repo: `archivedAt, assignableUsers, codeOfConduct, createdAt, defaultBranchRef, deleteBranchOnMerge, description, diskUsage, forkCount, hasDiscussionsEnabled, hasIssuesEnabled, hasProjectsEnabled, hasWikiEnabled, homepageUrl, id, isArchived, isEmpty, isFork, isPrivate, isTemplate, languages, latestRelease, licenseInfo, name, nameWithOwner, owner, parent, primaryLanguage, pullRequests, pushedAt, sshUrl, stargazerCount, updatedAt, url, visibility, watchers`

List

```bash # Your repos gh repo list gh repo list --limit 100

# Another user/org's repos gh repo list my-org

# Filter gh repo list --language go --visibility public gh repo list --topic cli --no-archived gh repo list --fork # only forks gh repo list --source # only non-forks

# JSON output gh repo list --json name,stargazerCount --jq '.[] | "\(.name): \(.stargazerCount) stars"' ```

Edit

```bash # Edit settings gh repo edit --description "New description" gh repo edit --homepage "https://example.com" gh repo edit --enable-issues --enable-wiki gh repo edit --enable-projects=false gh repo edit --default-branch main gh repo edit --enable-auto-merge gh repo edit --delete-branch-on-merge gh repo edit --add-topic "cli,automation" gh repo edit --remove-topic "old-topic" gh repo edit --template # make it a template repo

# Change visibility (DANGEROUS — requires acknowledgment) gh repo edit --visibility public --accept-visibility-change-consequences ```

Delete / Archive

```bash gh repo delete owner/repo --yes # requires delete_repo scope gh repo archive owner/repo --yes gh repo unarchive owner/repo --yes ```

Rename

```bash gh repo rename new-name # renames current repo gh repo rename new-name -R owner/repo ```

Set Default

```bash # Set which remote is used for gh commands in this local clone gh repo set-default owner/repo gh repo set-default --view # see current default gh repo set-default --unset ```

Sync (Fork ↔ Upstream)

```bash # Sync local repo from remote parent gh repo sync

# Sync specific branch gh repo sync --branch v1

# Sync remote fork from its parent gh repo sync owner/my-fork

# Sync from a specific source gh repo sync owner/repo --source owner2/repo2

# Force sync (hard reset) gh repo sync --force ```

---

3. Issues

Create

```bash gh issue create --title "Bug report" --body "Description here" gh issue create --title "Bug" --label "bug,urgent" --assignee "@me" gh issue create --title "Feature" --project "Roadmap" --milestone "v2.0" gh issue create --template "Bug Report" # use issue template gh issue create --body-file description.md # body from file gh issue create -R owner/repo --title "Bug" # different repo ```

List

```bash gh issue list gh issue list --state closed gh issue list --state all --limit 100 gh issue list --label "bug" --assignee "@me" gh issue list --author monalisa gh issue list --milestone "v2.0" gh issue list --search "error no:assignee sort:created-asc"

# JSON output gh issue list --json number,title,labels,state --jq '.[] | "#\(.number) \(.title)"' ```

JSON fields for issues: `assignees, author, body, closed, closedAt, comments, createdAt, id, isPinned, labels, milestone, number, projectCards, projectItems, reactionGroups, state, stateReason, title, updatedAt, url`

View

```bash gh issue view 123 gh issue view 123 --web # open in browser gh issue view 123 --comments # include comments gh issue view 123 --json title,body,labels,assignees

# View by URL gh issue view https://github.com/owner/repo/issues/123 ```

Edit

```bash gh issue edit 123 --title "New title" --body "New body" gh issue edit 123 --add-label "bug,help wanted" --remove-label "core" gh issue edit 123 --add-assignee "@me" --remove-assignee monalisa gh issue edit 123 --add-project "Roadmap" --remove-project "v1" gh issue edit 123 --milestone "v2.0" gh issue edit 123 --remove-milestone gh issue edit 123 --body-file body.md

# Bulk edit multiple issues gh issue edit 123 456 789 --add-label "help wanted" ```

Close / Reopen

```bash gh issue close 123 gh issue close 123 --comment "Fixed in PR #456" gh issue close 123 --reason "not planned" # completed | not planned gh issue reopen 123 ```

Comment

```bash gh issue comment 123 --body "Hello from CLI" gh issue comment 123 --body-file comment.md gh issue comment 123 --edit-last # edit your last comment ```

Pin / Unpin

```bash gh issue pin 123 gh issue unpin 123 ```

Transfer

```bash gh issue transfer 123 owner/other-repo ```

Lock / Unlock

```bash gh issue lock 123 gh issue unlock 123 ```

Develop (linked branches)

```bash # Create a branch linked to issue gh issue develop 123 --checkout gh issue develop 123 --name "fix-bug-123" --base develop

# List linked branches gh issue develop 123 --list ```

Delete

```bash gh issue delete 123 --yes ```

---

4. Pull Requests

Create

```bash gh pr create --title "Fix bug" --body "Description" gh pr create --fill # auto-fill title/body from commits gh pr create --fill-first # use first commit only gh pr create --fill-verbose # use commit messages + bodies gh pr create --draft # create as draft gh pr create --base develop # target branch gh pr create --head owner:feature-branch gh pr create --reviewer monalisa,hubot --reviewer myorg/team-name gh pr create --label "bug" --assignee "@me" gh pr create --project "Roadmap" gh pr create --milestone "v2.0" gh pr create --template "pull_request_template.md" gh pr create --no-maintainer-edit # prevent maintainers from pushing gh pr create --dry-run # preview without creating ```

List

```bash gh pr list gh pr list --state merged --limit 50 gh pr list --state all gh pr list --author "@me" gh pr list --assignee monalisa gh pr list --label "bug" --label "priority" gh pr list --base main gh pr list --head feature-branch gh pr list --draft # only drafts gh pr list --search "status:success review:required" gh pr list --search "<SHA>" --state merged # find PR for a commit

# JSON output gh pr list --json number,title,author,state --jq '.[].title' ```

JSON fields for PRs: `additions, assignees, author, autoMergeRequest, baseRefName, body, changedFiles, closed, closedAt, comments, commits, createdAt, deletions, files, headRefName, headRefOid, id, isDraft, labels, latestReviews, maintainerCanModify, mergeCommit, mergeStateStatus, mergeable, mergedAt, mergedBy, milestone, number, projectItems, reviewDecision, reviewRequests, reviews, state, statusCheckRollup, title, updatedAt, url`

View

```bash gh pr view 123 gh pr view 123 --web gh pr view 123 --comments gh pr view 123 --json title,body,reviews,mergeable gh pr view feature-branch # by branch name ```

Checkout

```bash gh pr checkout 123 gh pr checkout 123 --branch local-name gh pr checkout 123 --force # reset existing local branch gh pr checkout 123 --recurse-submodules gh co 123 # alias ```

Diff

```bash gh pr diff 123 gh pr diff 123 --name-only # list changed files gh pr diff 123 --patch # patch format ```

Merge

```bash gh pr merge 123 --merge # merge commit gh pr merge 123 --squash # squash merge gh pr merge 123 --rebase # rebase merge gh pr merge 123 --squash --delete-branch gh pr merge 123 --auto --squash # enable auto-merge gh pr merge 123 --disable-auto # disable auto-merge gh pr merge 123 --admin # bypass merge queue / requirements gh pr merge 123 --squash --subject "feat: new feature" --body "Details" ```

Review

```bash gh pr review 123 --approve gh pr review 123 --comment --body "LGTM" gh pr review 123 --request-changes --body "Please fix the tests" gh pr review # review current branch's PR ```

Checks (CI Status)

```bash gh pr checks 123 gh pr checks 123 --watch # live-update until done gh pr checks 123 --watch --fail-fast # stop on first failure gh pr checks 123 --required # only required checks gh pr checks 123 --json name,state,bucket gh pr checks 123 --web

# Exit codes: 0=pass, 1=fail, 8=pending ```

JSON fields for checks: `bucket, completedAt, description, event, link, name, startedAt, state, workflow`

Edit

```bash gh pr edit 123 --title "New title" --body "New body" gh pr edit 123 --add-label "bug" --remove-label "wip" gh pr edit 123 --add-reviewer monalisa --remove-reviewer hubot gh pr edit 123 --add-assignee "@me" gh pr edit 123 --add-project "Roadmap" gh pr edit 123 --base develop # change target branch gh pr edit 123 --milestone "v2.0" ```

Close / Reopen

```bash gh pr close 123 gh pr close 123 --comment "Superseded by #456" --delete-branch gh pr reopen 123 ```

Ready / Draft

```bash gh pr ready 123 # mark ready for review gh pr ready 123 --undo # convert back to draft (requires plan support) ```

Update Branch

```bash gh pr update-branch 123 # merge base into head gh pr update-branch 123 --rebase # rebase head onto base ```

Comment

```bash gh pr comment 123 --body "Comment text" gh pr comment 123 --body-file comment.md ```

Lock / Unlock

```bash gh pr lock 123 gh pr unlock 123 ```

---

5. GitHub Actions (Runs & Workflows)

Workflow Runs

```bash # List runs gh run list gh run list --limit 50 gh run list --workflow build.yml gh run list --branch main gh run list --status failure gh run list --user monalisa gh run list --event push gh run list --commit abc123 gh run list --json name,status,conclusion,url

# View a run gh run view 12345 gh run view 12345 --verbose # show job steps gh run view 12345 --log # full log output gh run view 12345 --log-failed # only failed step logs gh run view 12345 --job 456789 # specific job gh run view 12345 --job 456789 --log # specific job logs gh run view 12345 --attempt 3 # specific attempt gh run view 12345 --web

# Watch a run (live progress) gh run watch 12345 gh run watch 12345 --exit-status # exit non-zero on failure

# Rerun gh run rerun 12345 # rerun entire run gh run rerun 12345 --failed # rerun only failed jobs gh run rerun 12345 --debug # rerun with debug logging gh run rerun 12345 --job 456789 # rerun specific job

# ⚠️ GOTCHA: --job needs databaseId, NOT the number from the URL! # Get the right ID: gh run view 12345 --json jobs --jq '.jobs[] | {name, databaseId}'

# Cancel gh run cancel 12345

# Delete gh run delete 12345

# Download artifacts gh run download 12345 # all artifacts gh run download 12345 --name "build-output" gh run download 12345 --dir ./artifacts gh run download --name "coverage" --pattern "*.xml" ```

JSON fields for runs: `attempt, conclusion, createdAt, databaseId, displayTitle, event, headBranch, headSha, name, number, startedAt, status, updatedAt, url, workflowDatabaseId, workflowName`

Workflows

```bash # List workflows gh workflow list gh workflow list --all # include disabled

# View a workflow gh workflow view build.yml gh workflow view build.yml --web

# Run a workflow (workflow_dispatch) gh workflow run build.yml gh workflow run build.yml --ref my-branch gh workflow run build.yml -f name=value -f env=prod echo '{"name":"value"}' | gh workflow run build.yml --json

# Enable / disable gh workflow enable build.yml gh workflow disable build.yml ```

---

6. Releases

Create

```bash # Interactive gh release create

# With tag + notes gh release create v1.2.3 --notes "Bug fix release" gh release create v1.2.3 --generate-notes # auto-generated notes gh release create v1.2.3 --notes-from-tag # from annotated tag gh release create v1.2.3 -F CHANGELOG.md # notes from file gh release create v1.2.3 --draft # save as draft gh release create v1.2.3 --prerelease gh release create v1.2.3 --latest=false # don't mark as latest gh release create v1.2.3 --target release-branch # tag from specific branch gh release create v1.2.3 --verify-tag # abort if tag doesn't exist gh release create v1.2.3 --discussion-category "General"

# With assets gh release create v1.2.3 ./dist/*.tar.gz gh release create v1.2.3 'binary.zip#Linux Build' # with display label ```

List / View

```bash gh release list gh release list --limit 50 gh release view v1.2.3 gh release view v1.2.3 --web gh release view --json tagName,publishedAt,assets ```

Download

```bash gh release download v1.2.3 # all assets gh release download v1.2.3 --pattern '*.deb' gh release download v1.2.3 -p '*.deb' -p '*.rpm' gh release download v1.2.3 --archive zip # source code archive gh release download v1.2.3 --dir ./downloads gh release download v1.2.3 --output single-file.tar.gz gh release download --pattern '*.AppImage' # latest release (no tag arg) ```

Edit / Upload / Delete

```bash gh release edit v1.2.3 --title "New Title" --notes "Updated notes" gh release edit v1.2.3 --draft=false # publish a draft gh release edit v1.2.3 --prerelease=false gh release upload v1.2.3 ./new-asset.zip gh release upload v1.2.3 'asset.tar.gz#Display Label' gh release delete v1.2.3 --yes gh release delete-asset v1.2.3 asset-name ```

---

7. Gists

```bash # Create gh gist create file.py # secret gist gh gist create --public file.py # public gist gh gist create file.py -d "My Python snippet" gh gist create file1.py file2.js # multi-file gist echo "hello" | gh gist create - # from stdin cat data.json | gh gist create --filename data.json

# List gh gist list gh gist list --public gh gist list --secret gh gist list --limit 50

# View gh gist view GIST_ID gh gist view GIST_ID --raw # raw content gh gist view GIST_ID --filename file.py # specific file

# Edit gh gist edit GIST_ID gh gist edit GIST_ID --add newfile.txt gh gist edit GIST_ID --filename file.py # edit specific file

# Rename gh gist rename GIST_ID old-name.py new-name.py

# Clone gh gist clone GIST_ID

# Delete gh gist delete GIST_ID ```

---

8. Search

Repos

```bash gh search repos "vim plugin" gh search repos --owner=microsoft --visibility=public gh search repos --language=go --stars=">1000" gh search repos --topic=cli,automation gh search repos --good-first-issues=">=10" gh search repos --archived=false gh search repos cli shell --sort stars --limit 10 gh search repos --json fullName,stargazersCount,description ```

Issues

```bash gh search issues "memory leak" gh search issues --assignee=@me --state=open gh search issues --owner=cli --label="bug" gh search issues --comments=">100" gh search issues --repo owner/repo "error" gh search issues -- -label:bug # exclude label gh search issues --json number,title,repository,state ```

Pull Requests

```bash gh search prs "fix bug" gh search prs --repo=cli/cli --draft gh search prs --review-requested=@me --state=open gh search prs --assignee=@me --merged gh search prs --checks=success --review=approved gh search prs --json number,title,repository,state ```

Commits

```bash gh search commits "bug fix" gh search commits --author=monalisa gh search commits --committer-date="<2024-01-01" gh search commits --repo=cli/cli --hash=abc123 gh search commits --json sha,commit,repository ```

Code

```bash gh search code "TODO" --repo=owner/repo gh search code "import React" --language=typescript gh search code "api_key" --filename=".env" gh search code panic --owner=cli --extension=go gh search code --json path,repository,textMatches ```

---

9. Labels

```bash # List gh label list gh label list -R owner/repo gh label list --json name,color,description

# Create gh label create "priority:high" --color FF0000 --description "High priority"

# Edit gh label edit "bug" --name "bug 🐛" --color 00FF00 --description "Something broken"

# Delete gh label delete "old-label" --yes

# Clone labels from one repo to another gh label clone source-owner/source-repo --repo dest-owner/dest-repo ```

---

10. Secrets & Variables

Secrets (encrypted)

```bash # Set (repo-level, for Actions) gh secret set MY_SECRET --body "secret-value" gh secret set MY_SECRET < secret-file.txt echo "value" | gh secret set MY_SECRET

# Set for specific app gh secret set MY_SECRET --app dependabot --body "value" gh secret set MY_SECRET --app codespaces --body "value"

# Set environment secret gh secret set MY_SECRET --env production --body "value"

# Set org-level secret gh secret set MY_SECRET --org my-org --visibility all --body "value" gh secret set MY_SECRET --org my-org --visibility selected --repos repo1,repo2

# Set user secret (for Codespaces) gh secret set MY_SECRET --user --body "value"

# Bulk set from .env file gh secret set -f .env

# List gh secret list gh secret list --env production gh secret list --org my-org

# Delete gh secret delete MY_SECRET gh secret delete MY_SECRET --env production gh secret delete MY_SECRET --org my-org ```

Variables (plaintext)

```bash # Set gh variable set MY_VAR --body "value" gh variable set MY_VAR --env staging --body "value" gh variable set MY_VAR --org my-org --visibility all --body "value"

# Bulk set from .env file gh variable set -f .env

# Get gh variable get MY_VAR

# List gh variable list gh variable list --env production gh variable list --org my-org

# Delete gh variable delete MY_VAR gh variable delete MY_VAR --env production ```

---

11. Caches

```bash # List Actions caches gh cache list gh cache list --limit 100 gh cache list --sort size --order desc

# Delete gh cache delete CACHE_KEY gh cache delete --all ```

---

12. Projects V2

⚠️ Requires `project` scope: `gh auth refresh -s project`

Projects V2 uses the GraphQL-based ProjectsV2 API. The CLI provides commands for most operations, but some advanced field mutations require direct GraphQL via `gh api graphql`.

List Projects

```bash gh project list # your projects gh project list --owner my-org # org projects gh project list --owner my-org --closed # include closed gh project list --format json # JSON output ```

Create

```bash gh project create --owner "@me" --title "My Roadmap" gh project create --owner my-org --title "Sprint Board" ```

View

```bash gh project view 1 # by number gh project view 1 --owner my-org gh project view 1 --web # open in browser gh project view 1 --format json ```

Edit

```bash gh project edit 1 --owner "@me" --title "New Title" gh project edit 1 --description "Updated description" gh project edit 1 --readme "Project README content" gh project edit 1 --visibility PUBLIC # PUBLIC or PRIVATE ```

Close / Reopen / Delete

```bash gh project close 1 --owner "@me" gh project close 1 --owner "@me" --undo # reopen gh project delete 1 --owner "@me" ```

Copy

```bash gh project copy 1 --source-owner monalisa --target-owner my-org --title "Copied Project" gh project copy 1 --source-owner monalisa --target-owner my-org --drafts # include drafts ```

Link / Unlink to Repository or Team

```bash gh project link 1 --owner monalisa --repo my-repo gh project link 1 --owner my-org --team my-team gh project unlink 1 --owner monalisa --repo my-repo ```

Mark as Template

```bash gh project mark-template 1 --owner my-org gh project mark-template 1 --owner my-org --undo ```

Fields

```bash # List fields (shows IDs needed for item-edit) gh project field-list 1 --owner "@me" gh project field-list 1 --owner "@me" --format json

# Create field gh project field-create 1 --owner "@me" --name "Priority" --data-type "SINGLE_SELECT" \ --single-select-options "Low,Medium,High,Critical" gh project field-create 1 --owner "@me" --name "Points" --data-type "NUMBER" gh project field-create 1 --owner "@me" --name "Notes" --data-type "TEXT" gh project field-create 1 --owner "@me" --name "Due Date" --data-type "DATE"

# Delete field gh project field-delete --id FIELD_NODE_ID ```

Field data types: `TEXT`, `SINGLE_SELECT`, `DATE`, `NUMBER` (Iteration fields must be created via the web UI or GraphQL)

Items

```bash # List items gh project item-list 1 --owner "@me" gh project item-list 1 --owner "@me" --limit 100 gh project item-list 1 --owner "@me" --format json

# Add an existing issue/PR to project gh project item-add 1 --owner "@me" --url https://github.com/owner/repo/issues/123

# Create a draft issue in project gh project item-create 1 --owner "@me" --title "Draft task" --body "Details"

# Edit a draft issue (title/body) gh project item-edit --id ITEM_NODE_ID --title "Updated title" --body "Updated body"

# Edit a field value on an item gh project item-edit --id ITEM_NODE_ID --field-id FIELD_ID --project-id PROJECT_ID \ --text "some value" gh project item-edit --id ITEM_NODE_ID --field-id FIELD_ID --project-id PROJECT_ID \ --number 5 gh project item-edit --id ITEM_NODE_ID --field-id FIELD_ID --project-id PROJECT_ID \ --date "2024-12-31" gh project item-edit --id ITEM_NODE_ID --field-id FIELD_ID --project-id PROJECT_ID \ --single-select-option-id OPTION_ID gh project item-edit --id ITEM_NODE_ID --field-id FIELD_ID --project-id PROJECT_ID \ --iteration-id ITERATION_ID

# Clear a field value gh project item-edit --id ITEM_NODE_ID --field-id FIELD_ID --project-id PROJECT_ID --clear

# Archive / unarchive item gh project item-archive 1 --owner "@me" --id ITEM_NODE_ID gh project item-archive 1 --owner "@me" --id ITEM_NODE_ID --undo

# Delete item from project gh project item-delete 1 --owner "@me" --id ITEM_NODE_ID ```

Getting Node IDs (Essential for item-edit)

The `item-edit` command requires node IDs for the item, field, project, and option. Here's how to get them:

```bash # Get project ID and item IDs gh project item-list 1 --owner "@me" --format json | jq '.'

# Get field IDs and single-select option IDs gh project field-list 1 --owner "@me" --format json | jq '.'

# Via GraphQL (more control) gh api graphql -f query=' query { user(login: "USERNAME") { projectV2(number: 1) { id fields(first: 50) { nodes { ... on ProjectV2SingleSelectField { id name options { id name } } ... on ProjectV2IterationField { id name configuration { iterations { id title startDate duration } } } ... on ProjectV2Field { id name dataType } } } } } } ' ```

Projects V2 via GraphQL (for what the CLI can't do)

Some operations require direct GraphQL:

```bash # Update a field value (equivalent to item-edit but more flexible) gh api graphql -f query=' mutation { updateProjectV2ItemFieldValue(input: { projectId: "PVT_xxxx" itemId: "PVTI_xxxx" fieldId: "PVTF_xxxx" value: { singleSelectOptionId: "option_id" } }) { projectV2Item { id } } } '

# Add issue/PR to project via GraphQL gh api graphql -f query=' mutation { addProjectV2ItemById(input: { projectId: "PVT_xxxx" contentId: "I_xxxx" }) { item { id } } } '

# Update draft issue gh api graphql -f query=' mutation { updateProjectV2DraftIssue(input: { draftIssueId: "DI_xxxx" title: "New Title" body: "New body" }) { draftIssue { id title } } } '

# Convert draft to real issue gh api graphql -f query=' mutation { convertProjectV2DraftIssueItemToIssue(input: { projectId: "PVT_xxxx" itemId: "PVTI_xxxx" repositoryId: "R_xxxx" }) { item { id content { ... on Issue { id number url } } } } } '

# Get all items with field values gh api graphql -f query=' query { user(login: "USERNAME") { projectV2(number: 1) { items(first: 100) { nodes { id content { ... on Issue { title number url } ... on PullRequest { title number url } ... on DraftIssue { title body } } fieldValues(first: 20) { nodes { ... on ProjectV2ItemFieldTextValue { text field { ... on ProjectV2Field { name } } } ... on ProjectV2ItemFieldNumberValue { number field { ... on ProjectV2Field { name } } } ... on ProjectV2ItemFieldDateValue { date field { ... on ProjectV2Field { name } } } ... on ProjectV2ItemFieldSingleSelectValue { name field { ... on ProjectV2SingleSelectField { name } } } ... on ProjectV2ItemFieldIterationValue { title field { ... on ProjectV2IterationField { name } } } } } } } } } } ' ```

Projects V2 Workflow (Complete Example)

```bash # 1. Create a project gh project create --owner "@me" --title "Sprint 1"

# 2. Add fields gh project field-create 1 --owner "@me" --name "Status" \ --data-type SINGLE_SELECT --single-select-options "Todo,In Progress,Done" gh project field-create 1 --owner "@me" --name "Priority" \ --data-type SINGLE_SELECT --single-select-options "Low,Medium,High" gh project field-create 1 --owner "@me" --name "Points" --data-type NUMBER

# 3. Get field IDs FIELDS=$(gh project field-list 1 --owner "@me" --format json) echo "$FIELDS" | jq '.'

# 4. Add issues to project gh project item-add 1 --owner "@me" --url https://github.com/owner/repo/issues/1 gh project item-add 1 --owner "@me" --url https://github.com/owner/repo/issues/2

# 5. Create draft issues gh project item-create 1 --owner "@me" --title "Research task" --body "Investigate X"

# 6. Set field values on items (need IDs from steps 3-5) gh project item-edit --id ITEM_ID --field-id STATUS_FIELD_ID \ --project-id PROJECT_ID --single-select-option-id TODO_OPTION_ID

# 7. Link project to repo gh project link 1 --owner "@me" --repo my-repo ```

---

13. API (REST & GraphQL)

REST API

```bash # GET request (default) gh api repos/{owner}/{repo} gh api repos/cli/cli/releases --jq '.[].tag_name'

# With query parameters gh api -X GET search/issues -f q='repo:cli/cli is:open label:bug'

# POST request gh api repos/{owner}/{repo}/issues -f title="New Issue" -f body="Description" gh api repos/{owner}/{repo}/issues/123/comments -f body='Comment text'

# PATCH / PUT / DELETE gh api -X PATCH repos/{owner}/{repo} -f description="Updated" gh api -X DELETE repos/{owner}/{repo}/issues/123/labels/bug

# With typed fields (-F for auto-type-conversion, -f for raw strings) gh api repos/{owner}/{repo}/issues -f title="Bug" -F private=true -F number:=42

# Request body from file gh api repos/{owner}/{repo}/issues --input issue.json

# Custom headers gh api -H 'Accept: application/vnd.github.v3.raw+json' repos/{owner}/{repo}/readme

# Include response headers gh api -i repos/{owner}/{repo}

# Verbose output (shows full HTTP request/response) gh api --verbose repos/{owner}/{repo}

# Silent (no output) gh api --silent repos/{owner}/{repo}/issues/123/labels -f labels[]=bug

# Caching gh api --cache 3600s repos/{owner}/{repo}/releases ```

Placeholders

The special placeholders `{owner}`, `{repo}`, and `{branch}` are auto-populated from the current git directory or `GH_REPO`.

Pagination

```bash # Auto-paginate REST results gh api --paginate repos/{owner}/{repo}/issues --jq '.[].title'

# Slurp all pages into single array gh api --paginate --slurp repos/{owner}/{repo}/issues | jq 'flatten | length' ```

GraphQL API

```bash # Basic query gh api graphql -f query='{ viewer { login } }'

# With variables gh api graphql -F owner='{owner}' -F name='{repo}' -f query=' query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { releases(last: 5) { nodes { tagName publishedAt } } } } '

# Mutation gh api graphql -f query=' mutation { addStar(input: {starrableId: "MDEwOlJlcG9zaXRvcnkxMjM="}) { starrable { stargazerCount } } } '

# Paginated GraphQL (requires $endCursor variable and pageInfo) gh api graphql --paginate -f query=' query($endCursor: String) { viewer { repositories(first: 100, after: $endCursor) { nodes { nameWithOwner } pageInfo { hasNextPage endCursor } } } } '

# GraphQL with JQ filtering gh api graphql -f query='{ viewer { repositories(first: 10) { nodes { nameWithOwner stargazerCount } } } }' \ --jq '.data.viewer.repositories.nodes[] | "\(.nameWithOwner): \(.stargazerCount) ⭐"' ```

Common GraphQL Patterns

```bash # Get repository ID (needed for many mutations) gh api graphql -f query='query { repository(owner: "OWNER", name: "REPO") { id } }' \ --jq '.data.repository.id'

# Get issue/PR node ID gh api graphql -f query=' query { repository(owner: "OWNER", name: "REPO") { issue(number: 123) { id } } } ' --jq '.data.repository.issue.id'

# Get user/org ID gh api graphql -f query='query { user(login: "USERNAME") { id } }' --jq '.data.user.id'

# Check rate limit gh api graphql -f query='{ rateLimit { limit remaining resetAt } }' gh api rate_limit --jq '.rate' ```

---

14. Extensions

```bash # Search for extensions gh extension search "copilot" gh extension search --limit 30

# Browse extensions in TUI gh extension browse

# Install gh extension install owner/gh-extension-name gh extension install https://github.com/owner/gh-extension-name

# List installed gh extension list

# Upgrade gh extension upgrade extension-name gh extension upgrade --all

# Remove gh extension remove extension-name

# Execute (useful if name conflicts with core command) gh extension exec extension-name

# Create a new extension gh extension create my-extension gh extension create my-extension --precompiled=go ```

---

15. Codespaces

```bash # List gh codespace list

# Create gh codespace create --repo owner/repo gh codespace create --repo owner/repo --branch feature --machine largePremiumLinux

# SSH into codespace gh codespace ssh

# Open in VS Code gh codespace code

# Copy files gh codespace cp local-file.txt remote:~/path/ gh codespace cp remote:~/path/file.txt ./local/

# View details gh codespace view

# Port forwarding gh codespace ports

# Rebuild gh codespace rebuild

# Stop / Delete gh codespace stop gh codespace delete ```

---

16. Copilot

(Requires `gh-copilot` extension)

```bash # Suggest a command gh copilot suggest "find large files in current directory"

# Explain a command gh copilot explain "find . -type f -size +100M -exec ls -lh {} +"

# Configure gh copilot config ```

---

17. Other Commands

Browse (open in browser)

```bash gh browse # repo home gh browse 123 # issue or PR #123 gh browse src/main.go # specific file gh browse src/main.go:42 # file at line gh browse --settings # repo settings gh browse --projects # repo projects gh browse --releases # repo releases gh browse --branch feature src/ # specific branch gh browse --commit abc123 # specific commit gh browse -n # print URL instead of opening ```

Status (cross-repo overview)

```bash gh status # assigned issues, PRs, review requests, mentions gh status --org my-org # limit to org gh status -e owner/repo # exclude repo ```

Aliases

```bash gh alias set pv 'pr view' gh alias set bugs 'issue list --label=bug' gh alias set --shell igrep 'gh issue list --label="$1" | grep "$2"' gh alias list gh alias delete pv gh alias import aliases.yml ```

SSH Keys / GPG Keys

```bash gh ssh-key list gh ssh-key add ~/.ssh/id_ed25519.pub --title "My Laptop" gh ssh-key delete KEY_ID

gh gpg-key list gh gpg-key add pubkey.gpg gh gpg-key delete KEY_ID ```

Rulesets

```bash gh ruleset list gh ruleset view RULESET_ID gh ruleset check branch-name # what rules apply to this branch ```

Attestations

```bash gh attestation verify artifact.tar.gz --owner owner gh attestation download --owner owner artifact.tar.gz ```

Org

```bash gh org list ```

---

18. JSON Output & Formatting

Most listing/view commands support `--json`, `--jq`, and `--template` flags.

Basic JSON

```bash # Discover available fields (pass --json with no value) gh pr list --json

# Select specific fields gh pr list --json number,title,author

# JQ filtering gh pr list --json number,title,author --jq '.[].author.login' gh issue list --json number,title,labels --jq ' map(select(.labels | length > 0)) | map(.labels = (.labels | map(.name))) | .[:5] ' ```

Go Template Formatting

```bash # Table output gh pr list --json number,title,headRefName,updatedAt --template \ '{{range .}}{{tablerow (printf "#%v" .number | autocolor "green") .title .headRefName (timeago .updatedAt)}}{{end}}'

# Hyperlinks gh issue list --json title,url --template \ '{{range .}}{{hyperlink .url .title}}{{"\n"}}{{end}}'

# Color gh pr list --json title,state --template \ '{{range .}}{{.title}} ({{.state | color "green"}}){{"\n"}}{{end}}' ```

Template Functions

| Function | Description | |----------|-------------| | `autocolor <style> <input>` | Color (terminal-aware) | | `color <style> <input>` | Force color | | `join <sep> <list>` | Join list values | | `pluck <field> <list>` | Extract field from list items | | `tablerow <fields>...` | Aligned table columns | | `tablerender` | Render accumulated tablerows | | `timeago <time>` | Relative timestamp | | `timefmt <format> <time>` | Formatted timestamp | | `truncate <length> <input>` | Truncate text | | `hyperlink <url> <text>` | Terminal hyperlink |

---

19. Environment Variables

| Variable | Purpose | |----------|---------| | `GH_TOKEN` / `GITHUB_TOKEN` | Auth token for github.com (takes precedence over stored creds) | | `GH_ENTERPRISE_TOKEN` / `GITHUB_ENTERPRISE_TOKEN` | Auth token for GHES | | `GH_HOST` | Default GitHub hostname | | `GH_REPO` | Default repository in `[HOST/]OWNER/REPO` format | | `GH_EDITOR` | Editor for authoring text | | `GH_BROWSER` / `BROWSER` | Web browser for opening links | | `GH_PAGER` / `PAGER` | Terminal pager (e.g., `less`) | | `GH_DEBUG` | Enable verbose output (`1` or `api` for HTTP traffic) | | `GH_FORCE_TTY` | Force terminal output (value = column count or percentage) | | `GH_PROMPT_DISABLED` | Disable interactive prompts | | `GH_NO_UPDATE_NOTIFIER` | Disable update notifications | | `GH_CONFIG_DIR` | Custom config directory | | `NO_COLOR` | Disable colored output | | `GLAMOUR_STYLE` | Markdown rendering style |

---

20. Advanced Patterns

Scripting Best Practices

```bash # Disable prompts for non-interactive use GH_PROMPT_DISABLED=1 gh pr create --fill

# Use GH_TOKEN for CI/automation GH_TOKEN=${{ github.token }} gh pr list

# Use GH_REPO to avoid -R everywhere export GH_REPO=owner/repo gh issue list # targets owner/repo ```

Batch Operations

```bash # Close all issues with a label gh issue list --label "wontfix" --json number --jq '.[].number' | \ xargs -I{} gh issue close {} --reason "not planned"

# Add label to all open PRs gh pr list --json number --jq '.[].number' | \ xargs -I{} gh pr edit {} --add-label "needs-review"

# Download all artifacts from recent failed runs gh run list --status failure --json databaseId --jq '.[].databaseId' | \ xargs -I{} gh run download {} ```

Working with Multiple Accounts

```bash # List configured accounts gh auth status

# Switch active account gh auth switch

# Use a specific token for one command GH_TOKEN=ghp_xxx gh api user --jq '.login'

# Login to multiple hosts gh auth login --hostname github.com gh auth login --hostname github.enterprise.com ```

Rate Limiting

```bash # Check current rate limit gh api rate_limit --jq '.rate | "\(.remaining)/\(.limit) (resets \(.reset | strftime("%H:%M:%S")))"'

# GraphQL rate limit (separate pool) gh api graphql -f query='{ rateLimit { limit remaining resetAt } }'

# Use caching to reduce API calls gh api --cache 3600s repos/{owner}/{repo}/releases ```

Complex API Patterns

```bash # Nested parameters gh api gists -F 'files[myfile.txt][content][email protected]'

# Array parameters gh api -X PATCH /orgs/{org}/properties/schema \ -F 'properties[][property_name]=env' \ -F 'properties[][allowed_values][]=staging' \ -F 'properties[][allowed_values][]=production'

# Combine REST pagination with JQ gh api --paginate repos/{owner}/{repo}/issues --jq '[.[] | select(.labels | length > 0)] | length'

# GraphQL with slurp for aggregation gh api graphql --paginate --slurp -f query=' query($endCursor: String) { viewer { repositories(first: 100, after: $endCursor) { nodes { isFork stargazerCount } pageInfo { hasNextPage endCursor } } } } ' | jq '[.[].data.viewer.repositories.nodes[]] | map(.stargazerCount) | add' ```

---

21. Tips & Gotchas

Common Mistakes

  1. `--json` field names differ from API field names. For example, PR files use `files` (not `changed_files`), author uses `author.login` (not `user.login`). Always run `gh <cmd> --json` without arguments to see available fields.
  1. `gh run rerun --job` needs `databaseId`, not the URL number. Get it with:
  2. ```bash
  3. gh run view RUN_ID --json jobs --jq '.jobs[] | {name, databaseId}'
  4. ```
  1. Projects V2 require the `project` scope. If you get permission errors:
  2. ```bash
  3. gh auth refresh -s project
  4. ```
  1. `gh repo delete` requires `delete_repo` scope:
  2. ```bash
  3. gh auth refresh -s delete_repo
  4. ```
  1. Subcommand quoting in shells: PowerShell and some shells need `{owner}` escaped. Use quotes: `"{owner}"`.

When to Use `gh api` vs Specific Commands

| Use specific commands when... | Use `gh api` when... | |-------------------------------|---------------------| | The command exists and does what you need | No CLI command covers the endpoint | | You want interactive prompts | You need fine-grained control | | You want pretty-printed output | You want raw JSON response | | You're doing simple CRUD | You need GraphQL queries | | | You need to set custom headers | | | You need pagination control |

Performance Tips

  • Use `--limit` to fetch only what you need
  • Use `--json` with specific fields (fetches less data)
  • Use `--cache` with `gh api` for frequently accessed, slowly changing data
  • Use `--paginate --slurp` for aggregations across all pages
  • Set `GH_PAGER=cat` to disable paging in scripts

Exit Codes

| Code | Meaning | |------|---------| | 0 | Success | | 1 | Error / failure | | 2 | Usage error | | 4 | Command cancelled | | 8 | Checks pending (for `gh pr checks`) |

Authentication Precedence

  1. `GH_TOKEN` / `GITHUB_TOKEN` environment variable
  2. `GH_ENTERPRISE_TOKEN` (for GHES hosts)
  3. Stored credentials from `gh auth login`
  4. `.env` file in repo (only if configured)

Useful One-Liners

```bash # My open PRs across all repos gh search prs --author=@me --state=open --json repository,number,title

# Repos I starred recently gh api --paginate user/starred --jq '.[].full_name' | head -20

# Who's the top contributor to a repo gh api --paginate repos/owner/repo/contributors --jq '.[] | "\(.login): \(.contributions)"' | head -10

# Create issue from clipboard pbpaste | gh issue create --title "From clipboard" --body-file -

# Get latest release tag gh release view --json tagName --jq '.tagName'

# Watch CI and notify on completion gh run watch && notify-send "CI done!"

# Export all issues as JSON gh issue list --state all --limit 9999 --json number,title,state,labels,assignees > issues.json

# Find which PR merged a commit gh pr list --search "SHA_HERE" --state merged --json number,title,url ```

Use Cases

  • Manage GitHub repos, issues, PRs, and Actions from the command line
  • Automate GitHub workflows including releases, gists, and project boards
  • Query the GitHub API with custom JQ filters for advanced data retrieval
  • Manage repository secrets, variables, and codespace configurations
  • Search across GitHub for code, issues, and repositories using CLI filters

Pros & Cons

Pros

  • +Compatible with multiple platforms including claude-code, openclaw
  • +Well-documented with detailed usage instructions and examples
  • +Strong adoption with a large number of downloads and active users

Cons

  • -Requires API tokens or authentication setup before first use
  • -No built-in analytics or usage metrics dashboard

FAQ

What does Github Cli do?
Comprehensive GitHub CLI (gh) reference. Covers repos, issues, PRs, Actions, releases, gists, search, projects v2, API, secrets/variables, labels, codespaces...
What platforms support Github Cli?
Github Cli is available on Claude Code, OpenClaw.
What are the use cases for Github Cli?
Manage GitHub repos, issues, PRs, and Actions from the command line. Automate GitHub workflows including releases, gists, and project boards. Query the GitHub API with custom JQ filters for advanced data retrieval.

100+ free AI tools

Writing, PDF, image, and developer tools — all in your browser.

Next Step

Use the skill detail page to evaluate fit and install steps. For a direct browser workflow, move into a focused tool route instead of staying in broader support surfaces.