CHANGELOG.md
20 Aug 2025I’ve seen some teams and projects having really nice CHANGELOG.md and release notes but knowing from experience, writing release notes by hand is a pain. Scrolling through git log
, guessing which commits count as features or fixes, and hoping you don’t forget something important isn’t exactly fun.
In DevOps we often talk about removing toil and automating the boring things and I wanted to see if tbdflow
could help with that. Since the tool already encourages Conventional Commits, we’ve got a clean, structured Git history ready to be turned into a CHANGELOG. So, I added a new command: changelog
.
Generating a CHANGELOG in one command
The changelog
command turns the commit history into a clear, readable, and nice-looking CHANGELOG automatically. I took inspiration of the formatting by release-please
, and because I have used tbdflow
to commit changes to tbdflow
I had the advantage of having a pretty clean commit history.
I categorised the allowed types in sections:
/// Returns the section header based on the commit type.
fn get_section_header(commit_type: &str) -> &'static str {
match commit_type {
"feat" => "### ✨ Features",
"fix" => "### 🐛 Bug Fixes",
"perf" => "### 🚀 Performance Improvements",
"refactor" => "### 🔨 Code Refactoring",
"build" | "chore" | "ci" | "docs" | "style" | "test" => "### ⚙️ Maintenance",
_ => "### Miscellaneous",
}
}
Then I looped thru my git log, adding a header and links and printing it to stdout
.
The changelog command
Let’s take a look at the two options we can use. The first one is looking at last release up until HEAD:
tbdflow changelog --unreleased
This will generate a nice CHANGELOG of unreleased changes which could be good to have as tbdflow sync
only prints git log --graph --oneline -n 15
(you can see all Git commands tbdflow
is using by adding --verbose
before any other command, like tbdflow --verbose sync
)
After a release we can run the changelog
command with a range, to show all commits that happened within that span.
tbdflow changelog --from v0.13.0 --to v0.14.0
It groups commits by category and outputs something like this:
# [0.13.0](https://github.com/cladam/tbdflow/releases/tag/v0.13.0) (2025-08-20)
### 🔨 Code Refactoring
- **(commit):** moved commit handler to seperate file to keep main clean-er [`8975588`](https://github.com/cladam/tbdflow/commit/89755887be8322a6cd0739772731432278098a47)
- updated init command to handle populated remote repo [`87e9e5e`](https://github.com/cladam/tbdflow/commit/87e9e5ee25798f677f552506dfcef4cfa25247df)
### ⚙️ Maintenance
- **(release):** bump version and publish to GH Releases and crates.io [`428628c`](https://github.com/cladam/tbdflow/commit/428628c394cce08017e6e2a434799f900e8d198a)
Updating CHANGELOG.md
Most projects keep the latest release at the top of the changelog. Prepending text manually can be tricky as >> append
is the default, but here’s the one-liner I use in tbdflow
itself:
{ tbdflow changelog --from v0.12.0 --to v0.13.0; echo; cat CHANGELOG.md; } > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
It generates the new section, adds a blank line, and then appends the old content; all in one step.
Wrapping Up
The new changelog
command is another step in tbdflow
’s mission to be a “friendly assistant” for your TBD workflow.
It takes one more repetitive task off your plate, so you can spend more time writing code.
Take a look at tbdflow
’s CHANGELOG, generated by the changelog
command 🙂