Shell tricks: Changelogs with Git
I’ve been collecting some shell tricks. The list got long enough to warrant a few posts, so this is part one of a few. I’m going to add them to the “Bash Fun” series rather than creating a new one, so that’s the place if you want to track them.
I should mention that serial posts on my blog don’t have a permanent address, but you can find them all on the Topics page, in the “Series” tab. Every post in a series gets a box at the bottom linking to all the other posts in the series.
The first trick I want to share is how to generate a changelog from all of the commits to a Git repository since the last release. It should be noted that the git-extras
package (available through brew
) has similar functionality already built in. I just wanted something I could customize.
The first thing you need to do is find the date of the last annotated tag, which git-flow will create when you do a git flow release
. If you use the git-extras and do a git release
this is also available. Barring all of that, you’ll need to do your own annotated tags at the time of a release for this to work.
To get the last annotated tag:
git rev-list --tags --max-count=1
To list the date of the tag incorporate that command into a git show
command by executing it inline:
git show -s --format=%ad `git rev-list --tags --max-count=1`
You can use that command to put the date into a shell variable:
lastdate=$(git show -s --format=%ad `git rev-list --tags --max-count=1`)
And then use that to limit the git log
command to commits “since” the last tag, displaying just their date and subject lines:
git log --oneline --pretty=format:"%ad: %s" --date=short --since="$lastdate"
For my changelog, I don’t need the date, but I’d like to include any additional info in the commit body and a Markdown list prefix in the format string:
git log --pretty=format:"- %s%n%b" --since="$lastdate"
You can add a date back in using %cd
(committer date) or %ad
(author date) in the format string. You’d probably want to include the --date=short
flag with that as well.
Putting it all together into one command, you get:
git log --pretty=format:"- %s%n%b" --since="$(git show -s --format=%ad `git rev-list --tags --max-count=1`)"
The Markdown formatting isn’t perfect off the bat if you include the full commit body, as I haven’t found a way to have multiline messages automatically indented without a lot of sed
/awk
work. It just takes a little editing, though.
Now just redirect the output to a file or pipe it to pbcopy
and you have a changelog ready for editing and adding to your release. You can make a shell function for that, or include it as a git alias. I like the shell function approach for this one just because it does allow me to do extra formatting and processing of the output more conveniently.
Good luck, and may generating your release notes be as painless as possible.
Ryan Irelan has produced a series of shell trick videos based on BrettTerpstra.com posts. Readers can get 10% off using the coupon code TERPSTRA
.