Before you promise a customer "that fix shipped in the last release", check it with the read-only gh release list command. It inspects releases, hides drafts and pre-releases on request, and turns the result into JSON or tab-separated data for a script. Allow about ten minutes. You need a shell, gh, network access to GitHub, and access to the repository you want to inspect.
Scope: this command only lists releases. It does not create, edit or delete one, and none of the examples needs sudo. A public repository can usually be queried without an interactive login. Private repositories require an authenticated account with suitable access.
Confirm the version and read the local command contract before putting it into a script:
$ gh --version
gh version 2.87.3 (2026-02-23)
$ gh release list --help
The command is written as gh release list. Its alias is gh release ls, but using the full form makes scripts easier to read. The default limit is 30 releases and the default order is descending, shown by the manual as desc. That means a normal invocation asks for the newest releases first, but it is still wise to state a limit in automation.
Checkpoint: If gh --version fails, stop here and repair the local installation or PATH. Do not work around a missing executable by copying an unverified binary into a system directory.
Use -R or --repo when the repository is not the current directory's target. The value is OWNER/REPO, or HOST/OWNER/REPO for another GitHub host:
$ gh release list --repo cli/cli --limit 5
TITLE TYPE TAG NAME PUBLISHED
GitHub CLI 2.101.0 Latest v2.101.0 2026-09-15
GitHub CLI 2.100.0 v2.100.0 2026-09-03
The exact rows change as the project publishes releases. Treat the displayed table as human output, not a stable interface for parsing. If you omit --repo, gh normally derives the repository from the current directory's Git remote. Check that context before trusting an unqualified command:
$ gh repo view --json nameWithOwner --jq .nameWithOwner
cli/cli
If that check reports the wrong repository, keep --repo OWNER/REPO in the release command. This is a common distraction trap when a terminal is open in a different checkout.
Draft and pre-release entries are included unless you request otherwise. Add both filters when the question is "what releases are available to ordinary users?":
$ gh release list --repo OWNER/REPO --exclude-drafts --exclude-pre-releases --limit 20
These flags affect the returned list; they do not publish a draft or change its status. If the result is empty, that may simply mean the repository has no matching releases. Do not infer that the repository has never released software until you have tried the unfiltered command.
Checkpoint: Record the filters alongside any report or script. A later reader must be able to tell whether drafts and pre-releases were intentionally omitted.
Use --json when another command needs release data. The installed help lists these fields: createdAt, isDraft, isImmutable, isLatest, isPrerelease, name, publishedAt and tagName:
$ gh release list --repo cli/cli --limit 3 \
--json tagName,name,isPrerelease,publishedAt
[{"isPrerelease":false,"name":"GitHub CLI 2.101.0","publishedAt":"2026-09-15T14:24:34Z","tagName":"v2.101.0"}]
The field order in JSON is not a useful contract, so consume field names rather than column positions. The result is an array, even when the limit is one. If you need a field that is not listed by --help, use gh release view or the GitHub API instead of guessing a field name.
The --jq option applies a jq expression to the JSON result. This is convenient for a small report without a temporary file:
$ gh release list --repo cli/cli --limit 3 \
--json tagName,publishedAt \
--jq '.[] | [.tagName, .publishedAt] | @tsv'
v2.101.0 2026-09-15T14:24:34Z
v2.100.0 2026-09-03T15:43:20Z
For a machine-to-machine interface, keep the original JSON and parse it with the consumer's JSON library. Tab-separated output is useful for a shell report, but it is not JSON and should not be fed to a JSON parser. Quote the jq expression so the shell does not interpret its punctuation.
Use --order asc for the oldest matching releases first, or leave the default explicit in a script:
$ gh release list --repo OWNER/REPO --order asc --limit 10 \
--exclude-drafts --exclude-pre-releases
Only asc and desc are documented values. A limit controls how many items the command fetches, not how many releases exist. A report that needs every release must choose a sufficiently high limit and should still check whether the returned count reached that limit. Avoid silently treating the first 30 rows as a complete history.
A missing or mistyped repository produces an error rather than an empty, trustworthy report. Check the owner and repository spelling, then retry with the fully qualified --repo value. For a private repository, check the current account:
$ gh auth status
$ gh release list --repo OWNER/PRIVATE-REPO --limit 5
Do not paste an access token into a command line or a shell script. If authentication is required, use the supported gh auth login workflow and your organisation's normal credential policy. Authentication status can reveal account and host details, so avoid putting its output into a public bug report.
There is no undo step for these examples because they only read release metadata. If a script writes its output to a file, write to a new path or use a temporary file and rename it only after the command succeeds. This prevents a failed network request from replacing a previous report with partial data.
gh version and local help.--json and named fields for anything a script must parse.--limit and --order deliberately rather than relying on defaults.