7 years ago I wrote about a script I was using to generate changelogs for Marked. Since then I’ve continued updating the script to work with just about all of my projects, from Xcode projects to Ruby gems to scripts that just have a VERSION file in the same directory. It can output a few different formats of changelog to accommodate all of my different documentation formats. So I’m posting it again.

Since it’s unlikely anyone remembers, this script uses Git tags to determine what commits have been made since the last release. This works well with git-flow, but any setup that creates tagged releases will work. It parses commit messages for lines like - FIXED: description of fix, and it now works with a more “tag-like” syntax: @fix description of fix. It gathers all of these lines from the commit messages and outputs a Markdown-formatted changelog, ready for release notes or website posting.

It’s simple yet highly effective. Any time I make a change I want to include in the release notes, I just make sure to include a tagged line in the commit message. It works with commit subjects as well as commit notes. Then, when it’s time to release, I just run changelog and get my output for sharing. It can also update a CHANGELOG.md file by running changelog -u. It detects the format of the file and adds appropriately-formatted notes to the file, recognizing if there’s already an entry for the current version number and replacing it.

Some of the customizations are specific to the formatting I use for Bunch notes, which include syntax for custom Jekyll plugins for icons and availability. These won’t be of use to anyone else, but unless your directory structure happens to exactly match the one I use for Bunch, or you use the --format bunch flag, you’ll never see those. But if you want to edit the script to fit your specific needs, you can see how it’s done.

Eventually I’ll probably generalize this and make it work with templates and a config file with regexes for matching types and formats, but for now it’s just open to your hacking. This script has been a huge timesaver for me and has resulted in very complete release notes and changelogs I can be proud of. I hope it does the same for you.

Grab the script here.

The available tags are:

  • @change, @changed
  • @breaking, @deprecated
  • @rem, @removed
  • @fix, @fixed
  • @imp, @improved, @improvement
  • @add, @added, @new

All of these can be in the format - TAGNAME: description or @tagname description. The first letter of the description will be capitalized when the release notes are rendered.

You can also use changelog --select to pop up an fzf selection of all tags, allowing you to generate release notes added since any previous version. Use changelog --only TYPE to output only changes of a type (changed, new, improved, deprecated).

You can also use this script in combination with a tool like gh to output a changelog when creating a GitHub release. Just pass output of the changelog command to any command that accepts input on STDIN.

Usage: changelog [options] [CHANGELOG_FILE] [APP_NAME]
      Gets git log entries since last tag containing CHANGED, NEW, IMPROVED, FIXED, REMOVED
    -c, --copy                       Copy results to clipboard
    -f, --format FORMAT              Output format (def_list|bunch|markdown)
    -o, --only TYPES                 Only output changes of type (changed, new, improved, fixed, deprecated)
        --file PATH                  File to read additional commit messages from (for commit-msg hooks)
    -s, --select                     Choose "since" tag
    -u, --update [FILE]              Update changelog file
    -v, --version=VER                Force version (skips version detection)
    -n, --no_version                 Skip version check (prevents header output)
    -h, --help                       Display this screen

CHANGELOG_FILE and APP_NAME are optional, it will automatically detect a CHANGELOG.md file in the current directory, and derive the app name based on the project type (works with Ruby gems and Xcode projects currently).

Have fun, and may your changelogs be informative and complete. Again, here’s the script. That Gist will be updated as I make changes to the script over time, so check the Gist comments for additional notes as this post ages. If I get around to making a package out of this (with templates and config and such), there will be a new post about it, of course. Based on a quick search there are a ton of changelog generators already out there, so this will probably remain a script that fits my personal needs perfectly, and is easily hacked around with by others.