github-cliComprehensive GitHub CLI (gh) reference. Covers repos, issues, PRs, Actions, releases, gists, search, projects v2, API, secrets/variables, labels, codespaces...
Install via ClawdBot CLI:
clawdbot install tag-assistant/github-cligh) — Comprehensive SkillVersion: 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.
# 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 |
# 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
# Configure git to use gh for HTTPS auth
gh auth setup-git
# 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
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 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 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
# 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 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
gh repo delete owner/repo --yes # requires delete_repo scope
gh repo archive owner/repo --yes
gh repo unarchive owner/repo --yes
gh repo rename new-name # renames current repo
gh repo rename new-name -R owner/repo
# 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 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
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
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
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
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"
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
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
gh issue pin 123
gh issue unpin 123
gh issue transfer 123 owner/other-repo
gh issue lock 123
gh issue unlock 123
# 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
gh issue delete 123 --yes
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
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
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
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
gh pr diff 123
gh pr diff 123 --name-only # list changed files
gh pr diff 123 --patch # patch format
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"
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
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
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"
gh pr close 123
gh pr close 123 --comment "Superseded by #456" --delete-branch
gh pr reopen 123
gh pr ready 123 # mark ready for review
gh pr ready 123 --undo # convert back to draft (requires plan support)
gh pr update-branch 123 # merge base into head
gh pr update-branch 123 --rebase # rebase head onto base
gh pr comment 123 --body "Comment text"
gh pr comment 123 --body-file comment.md
gh pr lock 123
gh pr unlock 123
# 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
# 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
# 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
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
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)
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
# 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
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
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
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
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
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
# 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
# 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
# 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
# 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
⚠️ 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.
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
gh project create --owner "@me" --title "My Roadmap"
gh project create --owner my-org --title "Sprint Board"
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
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
gh project close 1 --owner "@me"
gh project close 1 --owner "@me" --undo # reopen
gh project delete 1 --owner "@me"
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
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
gh project mark-template 1 --owner my-org
gh project mark-template 1 --owner my-org --undo
# 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)
# 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
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
}
}
}
}
}
}
'
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 } } }
}
}
}
}
}
}
}
'
# 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
# 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
The special placeholders {owner}, {repo}, and {branch} are auto-populated from the current git directory or GH_REPO.
# 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'
# 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) ⭐"'
# 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'
# 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
# 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
(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
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
gh status # assigned issues, PRs, review requests, mentions
gh status --org my-org # limit to org
gh status -e owner/repo # exclude repo
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
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
gh ruleset list
gh ruleset view RULESET_ID
gh ruleset check branch-name # what rules apply to this branch
gh attestation verify artifact.tar.gz --owner owner
gh attestation download --owner owner artifact.tar.gz
gh org list
Most listing/view commands support --json, --jq, and --template flags.
# 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]
'
# 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}}'
| Function | Description |
|----------|-------------|
| autocolor