Keep a Changelog, actually implemented
Olivier Lacan published Keep a Changelog in 2014 with a line that has aged better than most software writing: don’t let your friends dump git logs into changelogs. Ten years on it is the closest thing this corner of software has to a standard, which mostly means people cite it and then implement about two thirds of it.
It is worth reading the source rather than a summary of it. This is about the third that gets dropped.
What the spec actually asks for
A CHANGELOG.md at the repo root, newest first, with one section per version. Each version carries
a number and an ISO date, and groups its entries under six types:
| Type | For |
|---|---|
| Added | new features |
| Changed | changes in existing behaviour |
| Deprecated | features about to be removed |
| Removed | features removed in this release |
| Fixed | bug fixes |
| Security | vulnerabilities |
Plus an Unreleased section at the top, so there is somewhere to put an entry the moment it is
merged, and so anyone can see what is coming.
That is nearly all of it. The rest is the reasoning: entries are for humans, one entry per change, and the file is a document rather than a log.
The three parts that get dropped
Unreleased disappears first. It is the section with no deadline, so it is the one that stops
being maintained, and once it is gone entries get written at release time from commit history. That
is precisely the git-log dump the spec opens by warning about, arrived at gradually.
The six types collapse into two. Most real changelogs end up with Added and Fixed, because Changed and Deprecated require a judgement about what someone relied on. That judgement is the valuable part. Deprecated in particular is the only type that is a promise about the future, and dropping it is how a removal turns into an incident.
Security stops being separate. A security fix filed under Fixed is invisible to the one reader who was scanning for it. Keep it distinct even when the fix is trivial, and especially when you would rather not draw attention to it.
What the spec deliberately does not answer
It is a file format. It says nothing about the questions you hit immediately after adopting it:
- How does anyone find out? A file in a repo reaches contributors. It does not reach a customer who has never opened GitHub.
- What about products without versions? A continuously deployed service has no v4.2.0 to group by. Most teams substitute dates, which works, and the spec does not bless or forbid it.
- Who writes the entry? The spec assumes a human does. It does not say when.
- What about multiple audiences? One file serves developers. It does not serve the same content to a non-technical admin, and reformatting it by hand for them is where the duplication starts.
Common Changelog, a stricter fork of the idea, tightens some of this: it bans certain entry phrasings, requires a link to the change, and is opinionated about who the reader is. It is worth reading if the loose parts of Keep a Changelog are what your team keeps arguing about.
Automating it without dumping git logs
The spec’s warning is about output, not about tooling. Deriving a draft from structured commits is fine. Publishing that draft unedited is the thing it objects to.
A shape that holds up: derive candidate entries from commits automatically, put them in
Unreleased with their type prefilled, and require a human to edit the wording before a release
can be cut. The machine handles collection and formatting, which it is good at. The human handles
selection and phrasing, which it is not. Our changelog tools roundup covers
what exists for the collection half.
Where it stops being enough
Keep a Changelog is a good answer to “what should this file look like”. It is not an answer to “how do our users learn what changed”, because a Markdown file in a repo is a distribution strategy that only works if your users are contributors.
That is the gap most teams hit second: the file is fine, and nobody outside the team reads it. Solving it means the entries have to become data that can be rendered somewhere else, which is a different problem from formatting a file, and the reason changelog examples collects public changelog pages rather than repo files.
Adopt the spec anyway. It costs an afternoon, it makes the second problem tractable, and it is still the best one page written about this.
The technical claims in this article have not been independently reviewed. If something here is wrong, tell us and we will correct it.