🎁 Get the FREE AI Skills Starter Guide β€” Subscribe β†’
BytesAgainBytesAgain
πŸ¦€ ClawHub

Github Cli

by @tag-assistant

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

Versionv1.0.0
Downloads10,396
Installs99
Stars⭐ 6
TERMINAL
clawhub install github-cli

πŸ“– About This Skill


name: github-cli description: "Comprehensive GitHub CLI (gh) reference. Covers repos, issues, PRs, Actions, releases, gists, search, projects v2, API, secrets/variables, labels, codespaces, extensions, auth, and advanced GraphQL patterns." metadata: { "openclaw": { "emoji": "πŸ™", "requires": { "bins": ["gh"] }, "install": [ { "id": "brew", "kind": "brew", "formula": "gh", "bins": ["gh"], "label": "Install GitHub CLI (brew)", }, { "id": "apt", "kind": "apt", "package": "gh", "bins": ["gh"], "label": "Install GitHub CLI (apt)", }, ], }, }

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

# 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

# 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

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


2. Repositories

Create

# 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

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

# 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

# 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

# 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

# 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

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

Rename

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

Set Default

# 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)

# 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

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

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

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

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

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

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

gh issue pin 123
gh issue unpin 123

Transfer

gh issue transfer 123 owner/other-repo

Lock / Unlock

gh issue lock 123
gh issue unlock 123

Develop (linked branches)

# 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

gh issue delete 123 --yes


4. Pull Requests

Create

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

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 "" --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

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

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

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

Merge

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

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)

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

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

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

Ready / Draft

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

Update Branch

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

Comment

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

Lock / Unlock

gh pr lock 123
gh pr unlock 123


5. GitHub Actions (Runs & Workflows)

Workflow Runs

# 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

# 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

# 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

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

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

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

# 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

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

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

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

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

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

# 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)

# 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)

# 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

# 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

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

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

View

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

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

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

Copy

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

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

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

Fields

# 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

# 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:

# 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:

# 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)

# 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

# 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

# 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

# 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

# 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

# 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

# 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)

# 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)

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)

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

Aliases

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

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

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

Attestations

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

Org

gh org list


18. JSON Output & Formatting

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

Basic JSON

# 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

# 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