gh run: Inspecting and Debugging Workflows From the Terminal
The two that save the most time: gh run view --log-failed prints only the failing step output, and gh run rerun --failed retries just the failed jobs instead of the whole workflow.
Reading a failed workflow in the browser means expanding groups and scrolling. gh run gets the same information into your terminal, where it can be grepped, and makes bulk analysis across runs possible at all.
Subcommands
| Command | Does |
|---|---|
gh run list | Recent runs, filterable by workflow and branch |
gh run view <id> | Summary of a run, with per-job status |
gh run view <id> --log | Full logs |
gh run view <id> --log-failed | Only the failed steps. The one to use |
gh run watch <id> | Live progress, exits with the run status |
gh run rerun <id> | Re-run the whole workflow |
gh run rerun <id> --failed | Re-run only failed jobs |
gh run cancel <id> | Cancel |
gh run download <id> | Download artifacts |
The commands worth memorising
# the failing output only, no scrolling
gh run view --log-failed
# watch the current run and exit non-zero if it fails
gh run watch --exit-status
# re-run only what failed, with debug logging on
gh run rerun --failed --debug
# most recent failure for one workflow
gh run list --workflow=ci.yml --status=failure --limit 1 --json databaseId \
--jq '.[0].databaseId' | xargs gh run view --log-failedBulk analysis across runs
# which jobs fail most often?
gh run list --limit 100 --json databaseId --jq '.[].databaseId' |
while read -r id; do
gh api "/repos/{owner}/{repo}/actions/runs/$id/jobs" \
--jq '.jobs[] | select(.conclusion=="failure") | .name'
done | sort | uniq -c | sort -rn | head
# what share of runs are re-runs?
gh run list --limit 200 --json databaseId --jq '.[].databaseId' |
while read -r id; do gh api "/repos/{owner}/{repo}/actions/runs/$id" --jq '.run_attempt'; done |
awk '{t++; if ($1>1) r++} END {printf "re-run rate: %.1f%%\n", 100*r/t}'Filtering runs
gh run list --workflow=ci.yml
gh run list --branch=main --status=failure
gh run list --user=@me --limit 5
gh run list --event=pull_request
gh run list --json databaseId,conclusion,headBranch,createdAtUsing this in CI
CI checkouts are shallow and detached by default, which changes the answer this command gives you. Commands that read history, branch names, or tags need the checkout configured for it.
- uses: actions/checkout@v4
with:
fetch-depth: 0 # history, tags, and git describe all need this
- run: |
git rev-parse --is-shallow-repository # expect false
git rev-parse --abbrev-ref HEAD # prints HEAD when detachedFrequently asked questions
How do I see only the failed logs of a GitHub Actions run?
gh run view --log-failed prints only the output of failed steps. Without an id it uses the most recent run, which makes it the fastest way to read a failure from the terminal.Can I re-run only the failed jobs?
gh run rerun <id> --failed retries just the failed jobs rather than the whole workflow. Add --debug to enable step and runner debug logging on the retry.How do I wait for a workflow to finish from the terminal?
gh run watch --exit-status streams progress and exits non-zero if the run fails, which makes it usable inside a script or a release checklist.How do I find which jobs fail most often?
gh run list over recent runs, pull each run jobs via gh api, filter to conclusion == "failure", and count by name. That ranking usually identifies the flaky job immediately.