--- /dev/null
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use Getopt::Long;
+
+my $byline = undef;
+my @more;
+my $append;
+my $debug;
+
+sub find_author {
+ my $map = shift;
+ for my $name (@_) {
+ my $fh;
+ print STDERR "Checking <$name>..."
+ if ($debug);
+ if (!open($fh, "-|",
+ qw(git log -1 --no-merges),
+ '--format=%an <%ae>',
+ "--author=$name",
+ "--all")) {
+ print STDERR "opening pipe to read from git log failed\n"
+ if ($debug);
+ $map->{$name} = $name;
+ next;
+ }
+ my $line = <$fh>;
+ if ($line) {
+ chomp $line;
+ print STDERR "read <$line> from git log\n"
+ if ($debug);
+ $map->{$name} = $line;
+ } else {
+ print STDERR "read false ($line) from git log\n"
+ if ($debug);
+ $map->{$name} = $name;
+ }
+ }
+}
+
+sub accumulate {
+ push @more, [@_];
+}
+
+sub add_more_bylines {
+ if (@more && !defined $append) {
+ my %names = map { $_->[1] => 1 } @more;
+ my %map = ();
+ my @append;
+ find_author(\%map, keys (%names));
+ for (@more) {
+ my ($tag, $name) = @$_;
+ $tag = ucfirst($tag);
+ push @append, "$tag: $map{$name}";
+ }
+ if (@append) {
+ $append = join("\n", @append) . "\n";
+ } else {
+ $append = "";
+ }
+ }
+ print $append;
+}
+
+my $check_only;
+
+exit 1 unless (GetOptions("signed-off-by=s" => \&accumulate,
+ "acked-by=s" => \&accumulate,
+ "reviewed-by=s" => \&accumulate,
+ "tested-by=s" => \&accumulate,
+ "helped-by=s" => \&accumulate,
+ "check-only!" => \$check_only,
+ "debug!" => \$debug,
+ ));
+
+if ($check_only) {
+ add_more_bylines();
+ exit 0;
+}
+
+while (<>) {
+ if (/^[-A-Za-z]+-by: /) {
+ $byline = 1;
+ } elsif ($byline) {
+ add_more_bylines();
+ $byline = undef;
+ } else {
+ $byline = undef;
+ }
+ print;
+}
+if ($byline) {
+ add_more_bylines();
+}