GitHub CLI Cheatsheet

Repos

Use this GitHub CLI reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Creating

gh repo create runs interactively with no arguments. With a name it needs a visibility flag.

gh repo create my-app --public
gh repo create my-app --private --description "internal tool"
gh repo create org-name/my-app --internal
gh repo create my-app --public --clone            # create, then clone locally
gh repo create my-app --private --source=. --push # push the cwd's repo up
gh repo create my-app --public --source=. --remote=upstream
gh repo create my-app --template cli/gh-extension-precompile --public
gh repo create my-app --public --gitignore Go --license mit --add-readme
FlagEffect
--public / --private / --internalVisibility, one is required non-interactively
-s, --source <path>Use an existing local repo as the source
--pushPush local commits after creating, needs --source
-c, --cloneClone the new empty repo into the current directory
-p, --template <repo>Create from a template repository
--include-all-branchesWith --template, copy every branch, not just the default
-r, --remote <name>Remote name to add, defaults to origin
-d, --description, -h, --homepageMetadata
-g, --gitignore, -l, --licenseTemplate names, e.g. Node, mit
--add-readmeSeed a README so the repo is not empty
-t, --team <name>Grant an org team access
--disable-issues, --disable-wikiTurn those features off at creation

--source and --clone are mutually exclusive: one pushes an existing directory up, the other pulls a new empty repo down.

Cloning and Forking

The OWNER/REPO shorthand works everywhere a repo argument is accepted, and a bare REPO means your own.

gh repo clone cli/cli
gh repo clone cli/cli ~/src/gh-cli
gh repo clone my-repo                     # your own account
gh repo clone github.example.com/team/app # enterprise host
gh repo clone cli/cli -- --depth=1        # anything after -- goes to git
gh repo clone cli/cli -- --recurse-submodules

Cloning a fork adds an upstream remote pointing at the parent automatically:

gh repo clone my-fork --upstream-remote-name parent
gh repo clone my-fork --no-upstream       # skip the upstream remote
gh repo fork                              # fork the current repo
gh repo fork cli/cli --clone
gh repo fork cli/cli --remote             # add a git remote for the fork
gh repo fork --remote --remote-name fork  # name it 'fork', keep origin
gh repo fork cli/cli --org my-org --fork-name cli-patched
gh repo fork cli/cli --default-branch-only

--remote defaults the new remote to origin and renames the original to upstream. Pass --remote-name when you would rather keep origin pointing at the parent.

Viewing and Browsing

gh repo view                              # README plus metadata, in the terminal
gh repo view cli/cli
gh repo view cli/cli --web                # open in a browser
gh repo view cli/cli --branch trunk
gh repo view cli/cli --json name,stargazerCount,defaultBranchRef
gh repo view cli/cli --json description --jq .description

gh browse is the fast path to a URL, and -n prints instead of opening.

gh browse                                 # repo home page
gh browse 217                             # issue or PR 217
gh browse cmd/gh/main.go                  # a file at the current branch
gh browse main.go:312                     # a file at a line
gh browse main.go:312 --blame             # blame view at that line
gh browse main.go --branch bug-fix
gh browse main.go --commit=77507cd
gh browse --settings                      # -a actions, -r releases, -w wiki, -p projects
gh browse -n -R cli/cli                   # print the URL only

main.go:312 is the form worth memorizing. It is how you hand a colleague a permalink to the exact line you are looking at.

Listing

gh repo list                              # your repos, 30 by default
gh repo list cli --limit 100
gh repo list my-org --visibility private
gh repo list my-org --language go --no-archived
gh repo list my-org --topic infra --source   # non-forks only
gh repo list my-org --fork
gh repo list my-org --json name,pushedAt --jq 'sort_by(.pushedAt) | reverse'
FlagFilter
-L, --limitMax results, default 30
--visibilitypublic, private, or internal
-l, --languagePrimary language
--topicOne or more topics
--source / --forkOnly non-forks / only forks
--archived / --no-archivedOnly archived / omit archived

Editing Settings

gh repo edit changes repository settings without opening the web UI.

gh repo edit --description "a better description" --homepage https://example.com
gh repo edit --add-topic cli --add-topic golang
gh repo edit --remove-topic legacy
gh repo edit --default-branch main
gh repo edit --enable-issues=false --enable-wiki=false
gh repo edit --enable-squash-merge --enable-merge-commit=false
gh repo edit --enable-rebase-merge=false --delete-branch-on-merge
gh repo edit --enable-auto-merge
gh repo edit --squash-merge-commit-message pr-title-description
gh repo edit --template                   # mark as a template repository
gh repo edit --enable-secret-scanning
gh repo edit cli/cli --visibility private \
  --accept-visibility-change-consequences

Boolean flags take an explicit =false to turn a setting off. --visibility refuses to run without --accept-visibility-change-consequences, because making a repo private can detach forks and drop stars.

Default Repo and Syncing

In a directory with several remotes, gh asks which repo commands should target. Pin it once:

gh repo set-default cli/cli
gh repo set-default --view
gh repo set-default --unset

Without a default set, every gh pr/gh issue call in a forked clone prompts. Setting it to the upstream is usually what you want, since that is where PRs and issues live.

gh repo sync                              # pull upstream into the local default branch
gh repo sync --branch release-2.x
gh repo sync my-fork                      # sync the remote fork from its parent
gh repo sync my-fork --source cli/cli
gh repo sync --force                      # hard reset, discards divergent commits

Without --force, gh repo sync refuses when the branches have diverged rather than clobbering work. With it, the destination branch is hard reset to the source.