How to generate a changelog from git commits
Your git history already knows what changed between two tags. A few `git log` commands turn it into a first draft in seconds, and dedicated tools can do it on every release. The draft still needs a human pass: commits are written for reviewers, a changelog for the people upgrading.
Updated Last checked 5 min readOpen-source libraries and packages
The short answer
git describe --tags --abbrev=0prints the most recent tag reachable from your current commit (--tagsincludes lightweight tags).git log v1.3.0..HEAD --no-merges --pretty=format:'- %s (%h)'lists every commit since that tag as a Markdown bullet.git shortlog -sn --no-merges v1.3.0..HEADcounts commits per author, for the thank-you line.gh release create v1.4.0 --generate-notesdrafts notes from merged pull requests instead of commits.- Git has no changelog command of its own. Whatever produces the list, sort it into Added, Changed, Fixed…, drop internal commits and add migration steps.
A first draft in four commands
Run these in a clone with full history and tags (git fetch --tags); CI checkouts are often shallow and miss them.
# 1. The last release tag reachable from HEAD
PREV=$(git describe --tags --abbrev=0)
# 2. Every non-merge commit since then, as Markdown bullets
git log "$PREV"..HEAD --no-merges --pretty=format:'- %s (%h)'
# 3. Only features and fixes, if you use Conventional Commits
git log "$PREV"..HEAD --no-merges --grep='^feat' --grep='^fix' --pretty=format:'- %s (%h)'
# 4. Who contributed, by number of commits
git shortlog -sn --no-merges "$PREV"..HEADWith several --grep patterns, git keeps commits matching any of them. Patterns match any line of the message, not only the first.
Free tool · no sign-up
Can a coding agent read your changelog?
Paste your repository, a GitHub release or a CHANGELOG.md link. The free converter shows every version, breaking change, migration step and deprecation it can extract, as JSON plus an llms.txt summary.
No AI and nothing stored. Or paste a CHANGELOG.md instead
01Find the range: from the last tag to now
A changelog entry covers the commits between the previous release and this one. In git, A..B means commits reachable from B but not from A, so v1.3.0..HEAD is everything since v1.3.0, and v1.3.0..v1.4.0 is exactly what went into 1.4.0.
To find the previous tag, git describe --tags --abbrev=0 “finds the most recent tag that is reachable from a commit” (HEAD by default). Without --tags it only considers annotated tags, and --abbrev=0 drops the commit-count suffix so you get just the tag name. It's the nearest tag in your history, not the highest version number, so if you release from more than one branch, pass the tag explicitly.
git tag -a v1.4.0 -m "v1.4.0"
git push origin v1.4.002Format commits as Markdown
--pretty=format: takes placeholders, so you can print each commit as a changelog line. --no-merges skips merge commits; --oneline is a quick shorthand when you just want to look.
| Placeholder | Prints |
|---|---|
%s | The subject (first line of the message) |
%h | The abbreviated commit hash |
%an | The author's name |
%as | The author date as YYYY-MM-DD |
%ad | The author date, in the format set by --date= |
- feat(parser): add parseStream() for large inputs (3f2c1ab)
- fix: handle Windows (CRLF) line endings (9d04e7c)
- refactor(parser): split the tokenizer (b81a6f0)
- chore(deps): bump test runner (2c7d9e4)If you merge pull requests with merge commits, --first-parent follows only the first parent at each merge, so you see one merge commit per pull request on your main branch instead of every commit inside it. If you squash-merge, each pull request is already one commit, and its title is the subject.
03Credit contributors with git shortlog
git shortlog groups commits by author. -s prints only the commit count per person, -n sorts by that count, and --no-merges leaves merges out. Use it for a “Thanks to…” line in the release notes; the commit history already records who did what, so keep the credit brief.
04Let GitHub draft notes from pull requests
Pull request titles are usually better raw material than individual commits. GitHub's generated release notes “include a list of merged pull requests, a list of contributors to the release, and a link to a full changelog”, grouped by the labels you set in .github/release.yml; Keep a Changelog vs GitHub Releases has a ready-made config.
gh release create v1.4.0 --generate-notescreates the release with generated notes;--notes-start-tag v1.3.0sets where they start.- The REST endpoint
POST /repos/{owner}/{repo}/releases/generate-notesreturns the text without creating anything: “The generated release notes are not saved anywhere.” Useful for pasting into CHANGELOG.md.
05Automate it with a changelog generator
If your commits follow Conventional Commits, a generator can sort them for you on every release. git-cliff writes a CHANGELOG.md from your history (git cliff -o CHANGELOG.md, or git cliff --unreleased for what's new since the last tag), and semantic-release, release-please and Changesets go further, choosing the version and creating the release. semantic-release vs release-please vs Changesets compares them. If you only want each GitHub release filled in, the free LogPulse GitHub Action sorts the commits since the last tag on every release, and uses your CHANGELOG.md section instead once you keep one. It's one workflow step, uses: kalmwerk/release-notes-action@v1 (on GitHub).
06Turn the draft into a changelog
Keep a Changelog is blunt about raw logs: “Do not use a list of commits as a changelog. It is full of noise: merge commits, unclear messages, internal changes.” Before you publish the draft:
- Sort each line into Added, Changed, Deprecated, Removed, Fixed or Security, under a
## [1.4.0] - YYYY-MM-DDheading. The CHANGELOG.md format guide has the full layout. - Delete internal changes: refactors, test and CI changes, dependency bumps nobody notices.
- Merge the five commits that built one feature into one line, and rewrite it around what users see.
- Mark breaking changes and add a migration step to each; see how to document breaking changes.
- Add the compare link for the new version at the bottom of the file.
Before and after
Too vague
- feat(parser): add parseStream() (3f2c1ab) - refactor(parser): split the tokenizer (b81a6f0) - chore(deps): bump test runner (2c7d9e4)
Specific and actionable
## [1.4.0] - 2026-10-02 · Added: parseStream() parses large files without loading them into memory. Fixed: files with Windows (CRLF) line endings now parse.
Fictional example: use your own verified names, versions and behavior.
LogPulse
Generate release notes with LogPulse
LogPulse is a hosted changelog that people and coding agents can both read. Here's exactly what it can do for the steps above, and what it can't.
Check your changelog, free
Paste a CHANGELOG.md or a GitHub releases link. A deterministic parser (no AI, nothing stored) shows the versions, breaking changes, migration steps and deprecations an agent can extract.
Draft notes from GitHub
Connect a repository: merged pull requests, commits to your default branch and published GitHub releases collect in an inbox. AI drafts a note in the tone you pick, listing breaking changes and deprecations only when the changes clearly show them. Nothing is published until you approve it. 3 AI drafts on Free; unlimited on Open source and Pro. Pro opens soon: .
Publish once, read everywhere
Approved notes go to a hosted changelog and an in-app widget, to email subscribers on Open source and Pro (Pro opens soon), and to a JSON feed and MCP server coding agents can query. CI and agents can publish with an API key.
What it doesn't do: LogPulse doesn't tag releases, bump versions, publish to npm or PyPI, or write CHANGELOG.md back to your repository; keep your release tooling for those. AI drafts can miss context, so review them like a pull request.
Before you publish
- The range starts at the previous release tag and ends at the new one
- Merge commits, refactors, test and CI changes are gone
- Lines are grouped by change type under a versioned, dated heading
- Related commits are merged into one user-facing line
- Breaking changes are marked and have migration steps
- Contributors are credited
Common questions
Can git generate a changelog automatically?
Git has no built-in changelog command. git log with a revision range and --pretty=format: gives you the raw list, and tools such as git-cliff, semantic-release or release-please turn structured commits into a formatted changelog.
How do I list the commits between two tags?
git log v1.3.0..v1.4.0 --no-merges --oneline shows commits reachable from v1.4.0 but not from v1.3.0, which is what went into the 1.4.0 release.
Should merge commits be in the changelog?
No. Use --no-merges to skip them, or --first-parent to see one merge per pull request and read the pull request titles instead. Either way the changelog line should describe the change, not the merge.
What if my commit messages are messy?
Draft from pull request titles instead (GitHub's generated notes, or squash merges that use the title), or ask contributors for a one-line summary in a change file, as Changesets does. Then edit.
Sources
Facts last checked against these sources on .
Read next
How to write release notes from commits (Conventional Commits)
Turn commits into release notes: the Conventional Commits format, how feat, fix and ! map to versions and sections, tools that automate it, what to edit.
Read the guide Open-source libraries and packagesCHANGELOG.md format, explained line by line
The CHANGELOG.md format most projects follow: version headings, YYYY-MM-DD dates, the six change types, Breaking markers, Unreleased, yanked versions and links.
Read the guide Open-source libraries and packagesKeep a Changelog vs GitHub Releases
CHANGELOG.md or GitHub Releases? See them side by side, when to use each, and how to keep both in sync with release.yml. Includes a CHANGELOG.md skeleton.
Read the guide Open-source libraries and packagessemantic-release vs release-please vs Changesets (and git-cliff)
How semantic-release, release-please, Changesets and git-cliff pick the next version, write CHANGELOG.md, create GitHub releases and publish, from their own docs.
Read the guideMore guides: open-source libraries and packages
- How to write release notes for open-source libraries
- Changelog vs release notes: what's the difference?
- Release notes templates in Markdown
- How to keep a changelog for an npm package
- How to keep a changelog for a Python package on PyPI
Tools and resources
LogPulse
Changelogs coding agents can upgrade from.
Publish versions, breaking changes, migration steps and deprecations once. People get a widget and hosted changelog; agents get a JSON feed and MCP server. Free for open source.