git shortlog between two tags is the simplest reliable way to draft release notes in a pipeline.
This pattern turns a commit range into grouped, deduplicated release notes - with the CI caveats that trip teams up.
What it does
Run against a tag-to-HEAD range, git shortlog groups commit subjects by author so a release job can emit a contributor-attributed changelog without external tooling.
Common usage
Terminal
# notes since the previous tag:
PREV=$(git describe --tags --abbrev=0 HEAD^)
git shortlog --no-merges "$PREV"..HEAD
# just the contributor list:
git shortlog -sne "$PREV"..HEAD
Common errors in CI
git shortlog without a range or piped input can block waiting on stdin in non-interactive CI - always pass an explicit range. fatal: No names found / a bad PREV happens when no earlier tag exists or tags were not fetched; guard the describe call and set fetch-depth: 0.
Using 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.
.github/workflows/ci.yml
- uses:actions/checkout@v4with:fetch-depth:0 # history, tags, and git describe all need this- run:|git rev-parse --is-shallow-repository # expect falsegit rev-parse --abbrev-ref HEAD # prints HEAD when detached
Frequently asked questions
git shortlog for Release Notes: Usage & CI Errors?
This pattern turns a commit range into grouped, deduplicated release notes - with the CI caveats that trip teams up.
What it does?
Run against a tag-to-HEAD range, git shortlog groups commit subjects by author so a release job can emit a contributor-attributed changelog without external tooling.
Common errors in CI?
git shortlog without a range or piped input can block waiting on stdin in non-interactive CI - always pass an explicit range. fatal: No names found / a bad PREV happens when no earlier tag exists or tags were not fetched; guard the describe call and set fetch-depth: 0.