Generate a changelog from git commits (without publishing garbage)

Your git history already knows what changed. The dream is obvious: run one command, get a changelog. The tooling for this is genuinely good now β€” but teams that wire it up usually end up with a changelog nobody reads, because they skipped the one manual step that matters. This guide covers the tools and the step. (Want to try the idea in ten seconds first? Paste a git log into our free release notes generator β€” no signup, and it hands you a draft, not a changelog, for exactly the reasons below.)

Level 0: plain git log

You don't need any tooling to get a first draft out of git:

# everything since the last tag, one line each, no merge noise
git log $(git describe --tags --abbrev=0)..HEAD --oneline --no-merges

# same, formatted as markdown bullets
git log $(git describe --tags --abbrev=0)..HEAD --no-merges --pretty='- %s'

That second one-liner pasted into a release note is already better than silence. Its weakness is its input: it's only as readable as your commit subjects.

Level 1: Conventional Commits

The Conventional Commits convention prefixes every commit with a type β€” feat:, fix:, docs:, chore:, with ! or a BREAKING CHANGE: footer for breaking changes. Two real benefits:

  • Machines can sort your history. Tools can group features apart from fixes and drop chore: noise entirely.
  • Machines can pick your next version. fix β†’ patch, feat β†’ minor, breaking β†’ major (see semver in plain English).

The cost is discipline at commit time β€” enforce it with a commit-lint hook or don't bother; a half-followed convention generates half a changelog.

Level 2: the generators

  • git-cliff β€” a fast, single-binary generator with templated output. Great when you want full control of the rendered markdown.
  • conventional-changelog / standard-version β€” the original Node ecosystem tooling; writes CHANGELOG.md and bumps versions.
  • release-please β€” runs in CI, maintains a rolling release PR whose description is the pending changelog; merging it tags the release.
  • GitHub's "Generate release notes" β€” one click on a release, groups merged PRs by label. Zero setup, PR-title quality output.

All of these solve the same problem: turning commit subjects into grouped markdown. Pick whichever fits your CI; none of them solves the next problem.

The rule: generated output is a draft

A commit subject is written for your team, at the moment of the change, in implementation vocabulary. A changelog entry is written for your users, at the moment of release, in outcome vocabulary. No template closes that gap: "fix: race in session refresh" needs a human to become "you no longer get logged out mid-request." So treat generator output the way you treat a first draft: keep the grouping, rewrite the five lines users will actually care about, delete the rest. Five curated lines beat fifty accurate ones β€” that's the difference between a changelog and release notes.

Wiring it up end to end

Wakelog's CLI has this pipeline built in. wakelog post --from-git collects the commits since your last tag into a markdown draft (merges excluded, title from the tag), and --draft holds it unpublished so you can do the curation pass on the dashboard before flipping it live:

git tag v1.4.0
wakelog post --from-git --draft   # curate on the dashboard, then publish

Prefer your existing generator? Pipe anything into it: git cliff --latest | wakelog post -t "v1.4.0". Either way the result is a hosted page, RSS feed, and embeddable widget β€” not a file at the bottom of your repo.

Start a changelog β€” free   Next: how to write a changelog β†’

Related guides

Last updated 2026-07-29 Β· All guides