I’ve been using my changelog script for years to generate release notes from git commit messages. It’s saved me countless hours and helped me maintain complete, informative changelogs across all my projects.

I wrote changelog in 2017 and mentioned it back in 2024. I’ve used it for every project I’ve worked on since then, and I’ve been improving it and making it work with more and more project types over the years.

Rust project support

The latest update adds support for Rust projects, which I’m just dipping my toes into. The script now automatically detects Rust projects in two ways:

  1. Cargo.toml detection: If your project has a Cargo.toml file, it reads the name and version fields directly from it.

  2. Rust source file scanning: For projects without a Cargo.toml (or as a fallback), it scans .rs files looking for version constants like const VERSION: &str = "1.0.0" and command names from Command::new("appname").

This means you can use the changelog script with any Rust project just by running changelog or changelog -u to update your CHANGELOG.md file, and it will automatically pull the version from your Cargo.toml or source files.

Other improvements

Along with Rust support, I’ve made a few other improvements:

  • VERSION constant: The script now includes its own VERSION constant that stays in sync with the VERSION file, making it easier to track the script’s version.

  • Code refactoring: I’ve extracted the version detection, git log parsing, and formatting logic into separate modules (VersionDetector, GitLogParser, and ChangelogFormatter) to make the codebase more maintainable.

  • Better version detection: The script now has a more robust fallback chain for detecting versions, with Rust projects taking priority when detected, followed by Ruby gems, Xcode projects, and plain VERSION files.

  • --since-version flag: You can now generate changelogs starting from a specific version tag using --since-version (or --sv for short). This is useful when you want to see changes since a particular release, and it supports partial version matching. For example, changelog --since-version 1.0 will find the most recent tag starting with “1.0” and generate a changelog from that point.

  • --select flag: If you prefer an interactive approach, use --select (or -s) to pop up an fzf menu of all your git tags. This lets you visually choose which tag to use as the starting point for your changelog generation. Perfect for when you can’t remember the exact version number but know roughly when you want to start from.

  • --only flag: Filter changelog output to show only specific change types. Use it like changelog --only new,fixed to see only new features and bug fixes, or changelog --only changed to see only breaking changes and modifications.

  • --split flag: When used with --select or --since-version, this splits the changelog output by version tag, showing what changed in each release separately. This is great for generating comprehensive release notes that span multiple versions. You can control the order with --order asc (oldest first) or --order desc (newest first, default).

How it works

The script works exactly the same way it always has — you format your commit messages with prefixes like NEW: or FIXED:, or tags like @new, @fixed, @changed, etc., and it generates a changelog from commits since your last git tag. The only difference now is that it works seamlessly with Rust projects without any additional configuration.

The script is still designed to fit my personal workflow (including some nvUltra, Marked, and Bunch-specific formatting), but it’s open for anyone to hack on and adapt to their needs. All of my project-specific paths are gated by exact directory structures and won’t affect operation by anyone else.

If you’re working with a Rust, Xcode, Ruby, or any script project and want to automate your changelog generation, give it a try. It makes it so easy to build a changelog and release notes as you develop, and have them ready to go when you hit release time.