From: Linus Torvalds Date: Sun, 5 Jun 2005 03:21:35 +0000 (-0700) Subject: Add git-shortlog perl script X-Git-Tag: v0.99~369 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=fa375c7f1b6298b128492b0935e92ecd0fd668e4;p=git.git Add git-shortlog perl script 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. --- diff --git a/Makefile b/Makefile index a5e7552e1..c03b4b6bd 100644 --- 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 index 000000000..1cf870781 --- /dev/null +++ b/git-shortlog @@ -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); +