Stackness
All moves

Commit message types become machine-readable release notes

by Elif Yilmaz

DevOps & Infrastructure

Before I adopted conventional commits, my git log was a graveyard of "fix stuff", "updates", and "wip". When it came time to cut a release, I'd manually sift through months of commits trying to figure out what actually changed for users. Worse, when I needed to bisect a regression, reading commit messages from six months ago felt like archaeological work because nobody had bothered to say whether a commit was a breaking change, a bug fix, or just a refactor.

I started structuring every commit as type(scope): subject where type is one of feat, fix, refactor, docs, chore, or perf. The scope is optional but specific: auth, api, cli. This took maybe two weeks to internalize as muscle memory. Now when I'm in the middle of a bisect and land on a commit, I can immediately tell whether it was a behavioral change or a code cleanup without reading the body.

The real payoff arrives when GitHub Actions runs after a merge to main. A simple script parses commit types, groups them, and generates release notes automatically. I've set up a workflow that counts feat commits for minor versions, fix commits for patches, and any breaking change in the commit footer for major versions. No more sitting in a release meeting trying to remember what we shipped.

The caveat is that this only works if your team actually follows the convention, and if you're rebasing frequently in a chaotic codebase, you'll spend time cleaning up commit messages anyway. Squash merging can also obscure individual commits, so you lose the benefit during bisect. It's less powerful than a proper changelog file, but it beats starting from nothing.

$ git log --oneline -4 9cfc5db fix(auth): reject expired refresh tokens 4c43ff2 feat(feed): cursor paginate the home feed 7fa7e00 chore(deps): bump ent to 0.14 b3bc5e2 docs(readme): document the staging runbook

Tools

Commit message types become machine-readable release notes | Stackness