Add git-shortlog perl script
authorLinus Torvalds <torvalds@ppc970.osdl.org>
Sun, 5 Jun 2005 03:21:35 +0000 (20:21 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sun, 5 Jun 2005 03:21:35 +0000 (20:21 -0700)
Somebody finally came through - Jeff Garzik gets a gold
star for writing a shortlog script for git, so that I
can do nice release announcments again.

I added name translations from the current kernel history
(and git, for that matter). Hopefully it won't grow at
nearly the same rate the BK equivalent did, since 99% of
the time git records the full name already.

Usage: just do

        git-rev-list --pretty HEAD ^LAST_HEAD | git-shortlog

or, in fact, use any of the other tools (git-diff-tree,
git-whatchanged etc) that use the default "pretty" commit format.

Makefile
git-shortlog [new file with mode: 0755]

index a5e7552..c03b4b6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ INSTALL=install
 SCRIPTS=git git-apply-patch-script git-merge-one-file-script git-prune-script \
        git-pull-script git-tag-script git-resolve-script git-whatchanged \
        git-deltafy-script git-fetch-script git-status-script git-commit-script \
-       git-log-script
+       git-log-script git-shortlog
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
        git-read-tree git-commit-tree git-cat-file git-fsck-cache \
diff --git a/git-shortlog b/git-shortlog
new file mode 100755 (executable)
index 0000000..1cf8707
--- /dev/null
@@ -0,0 +1,167 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+#
+# Even with git, we don't always have name translations.
+# So have an email->real name table to translate the
+# (hopefully few) missing names
+#
+my %mailmap = (
+       'aherrman@de.ibm.com' => 'Andreas Herrmann',
+       'akpm@osdl.org' => 'Andrew Morton',
+       'andrew.vasquez@qlogic.com' => 'Andrew Vasquez',
+       'aquynh@gmail.com' => 'Nguyen Anh Quynh',
+       'axboe@suse.de' => 'Jens Axboe',
+       'blaisorblade@yahoo.it' => 'Paolo \'Blaisorblade\' Giarrusso',
+       'bunk@stusta.de' => 'Adrian Bunk',
+       'domen@coderock.org' => 'Domen Puncer',
+       'dougg@torque.net' => 'Douglas Gilbert',
+       'dwmw2@shinybook.infradead.org' => 'David Woodhouse',
+       'ecashin@coraid.com' => 'Ed L Cashin',
+       'felix@derklecks.de' => 'Felix Moeller',
+       'gregkh@suse.de' => 'Greg Kroah-Hartman',
+       'hch@lst.de' => 'Christoph Hellwig',
+       'htejun@gmail.com' => 'Tejun Heo',
+       'jejb@mulgrave.(none)' => 'James Bottomley',
+       'jejb@titanic.il.steeleye.com' => 'James Bottomley',
+       'jgarzik@pretzel.yyz.us' => 'Jeff Garzik',
+       'johnpol@2ka.mipt.ru' => 'Evgeniy Polyakov',
+       'kay.sievers@vrfy.org' => 'Kay Sievers',
+       'minyard@acm.org' => 'Corey Minyard',
+       'R.Marek@sh.cvut.cz' => 'Rudolf Marek',
+       'simon@thekelleys.org.uk' => 'Simon Kelley',
+       'ssant@in.ibm.com' => 'Sachin P Sant',
+       'tony.luck@intel.com' => 'Tony Luck',
+);
+
+my (%map);
+my $pstate = 1;
+my $n_records = 0;
+my $n_output = 0;
+
+
+sub shortlog_entry($$) {
+       my ($name, $desc) = @_;
+       my $key = $name;
+
+       $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g;
+       $desc =~ s#\[PATCH\] ##g;
+
+       # store description in array, in email->{desc list} map
+       if (exists $map{$key}) {
+               # grab ref
+               my $obj = $map{$key};
+
+               # add desc to array
+               push(@$obj, $desc);
+       } else {
+               # create new array, containing 1 item
+               my @arr = ($desc);
+
+               # store ref to array
+               $map{$key} = \@arr;
+       }
+}
+
+# sort comparison function
+sub by_name($$) {
+       my ($a, $b) = @_;
+
+       uc($a) cmp uc($b);
+}
+
+sub shortlog_output {
+       my ($obj, $key, $desc);
+
+       foreach $key (sort by_name keys %map) {
+               # output author
+               printf "%s:\n", $key;
+
+               # output author's 1-line summaries
+               $obj = $map{$key};
+               foreach $desc (@$obj) {
+                       print "  $desc\n";
+                       $n_output++;
+               }
+
+               # blank line separating author from next author
+               print "\n";
+       }
+}
+
+sub changelog_input {
+       my ($author, $desc);
+
+       while (<>) {
+               # get author and email
+               if ($pstate == 1) {
+                       my ($email);
+
+                       next unless /^Author: (.*)<(.*)>.*$/;
+       
+                       $n_records++;
+       
+                       $author = $1;
+                       $email = $2;
+                       $desc = undef;
+
+                       # trim trailing whitespace.
+                       # why doesn't chomp work?
+                       while ($author && ($author =~ /\s$/)) {
+                               chop $author;
+                       }
+       
+                       # cset author fixups
+                       if (exists $mailmap{$email}) {
+                               $author = $mailmap{$email};
+                       } elsif (exists $mailmap{$author}) {
+                               $author = $mailmap{$author};
+                       } elsif ((!$author) || ($author eq "")) {
+                               $author = $email;
+                       }
+       
+                       $pstate++;
+               }
+       
+               # skip to blank line
+               elsif ($pstate == 2) {
+                       next unless /^\s*$/;
+                       $pstate++;
+               }
+       
+               # skip to non-blank line
+               elsif ($pstate == 3) {
+                       next unless /^\s*(\S.*)$/;
+
+                       # skip lines that are obviously not
+                       # a 1-line cset description
+                       next if /^\s*From: /;
+
+                       chomp;
+                       $desc = $1;
+       
+                       &shortlog_entry($author, $desc);
+       
+                       $pstate = 1;
+               }
+       
+               else {
+                       die "invalid parse state $pstate";
+               }
+       }
+}
+
+sub finalize {
+       #print "\n$n_records records parsed.\n";
+
+       if ($n_records != $n_output) {
+               die "parse error: input records != output records\n";
+       }
+}
+
+&changelog_input;
+&shortlog_output;
+&finalize;
+exit(0);
+