Some Perl to generate Debian-style changelogs from git logs with tags for versions.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
2.8 KiB

#!/usr/bin/env perl
=head1 NAME
git-changelog - generate a Debian changelog based on tags or on all commits
git-changeloge [ B<--project=...> B<--distribution=...>]
Should produce a Debian changelog, more or less, based on the git commit log
and tags for the current directory.
The idea here is that each tag represents a version, and should contain bullet
points for each commit since the previous version.
=head1 CAVEATS
Urgency is just hardcoded to "high". I guess it probably ought to be...
Sensitive to semver or something? I don't really know.
=head1 AUTHOR
Brennen Bearnes
=head1 COPYING
Knock yourself out.
To the extent possible under law, Brennen Bearnes has waived all copyright and
related or neighboring rights to git-changelog.
use warnings;
use strict;
use 5.10.0;
use Getopt::Long;
use POSIX qw(strftime);
my $project_name = 'project';
my $distribution = 'distribution';
"project:s" => \$project_name,
"distribution:s" => \$distribution,
# See PRETTY FORMATS in git-log(1) for placeholders.
open (my $logstream, "git log --reverse --pretty='format:%H\t%d\t%aD\t%aN\t%aE\t%s' |")
or die("$0: Failed to run git\n$!\n");
my @changes;
my @changelog_entries;
while (my $line = <$logstream>)
my @fields = split "\t", $line;
my ($hash, $decoration, $date, $author_name, $author_mail, $subject) = @fields;
my $author = "$author_name <$author_mail>";
# Tags come in from the decoration field - placeholder %d - with (tag: foo)
# That might or might not be followed with other stuff like (tag: foo, ...)
# There's probably a fragile assumption in this, I'm not quite sure what
# happens when more than one tag points at the same commit.
my $tag;
if ($decoration =~ m{^[ ] \( tag:[ ](.*?) \) }x) {
$tag = $1;
if ($tag =~ m/(.*?),/) {
$tag = $1;
# Accumulate commit subject lines:
push @changes, $subject;
# Every time we hit a tag, create a changelog entry with the accumulated
# bullet points from changes represented by all the preceding commits.
if ($tag) {
my $bullets = '';
foreach my $change (@changes) {
if ($change) {
$bullets .= " * $change\n";
# Clear out the change list.
@changes = ();
push @changelog_entries,
changelog($tag, $date, $author, $project_name, $bullets, $distribution);
# Reverse these so they're in the proper new-to-old order:
foreach my $entry (reverse @changelog_entries) {
say $entry;
# Pretty much just a template.
sub changelog {
my ($tag, $date, $author, $project_name, $body, $distribution) = @_;
return <<"CHANGELOG";
$project_name ($tag) $distribution; urgency=high
-- $author $date