gitweb: Default to $hash_base or HEAD for $hash in "commit" and "commitdiff"
[git.git] / git-shortlog.perl
blob334fec7477e6e4af646808c54ad7af1357fc5f8b
1 #!/usr/bin/perl -w
3 use strict;
4 use Getopt::Std;
5 use File::Basename qw(basename dirname);
7 our ($opt_h, $opt_n, $opt_s);
8 getopts('hns');
10 $opt_h && usage();
12 sub usage {
13 print STDERR "Usage: ${\basename $0} [-h] [-n] [-s] < <log_data>\n";
14 exit(1);
17 my (%mailmap);
18 my (%email);
19 my (%map);
20 my $pstate = 1;
21 my $n_records = 0;
22 my $n_output = 0;
24 sub shortlog_entry($$) {
25 my ($name, $desc) = @_;
26 my $key = $name;
28 $desc =~ s#/pub/scm/linux/kernel/git/#/.../#g;
29 $desc =~ s#\[PATCH\] ##g;
31 # store description in array, in email->{desc list} map
32 if (exists $map{$key}) {
33 # grab ref
34 my $obj = $map{$key};
36 # add desc to array
37 push(@$obj, $desc);
38 } else {
39 # create new array, containing 1 item
40 my @arr = ($desc);
42 # store ref to array
43 $map{$key} = \@arr;
47 # sort comparison function
48 sub by_name($$) {
49 my ($a, $b) = @_;
51 uc($a) cmp uc($b);
53 sub by_nbentries($$) {
54 my ($a, $b) = @_;
55 my $a_entries = $map{$a};
56 my $b_entries = $map{$b};
58 @$b_entries - @$a_entries || by_name $a, $b;
61 my $sort_method = $opt_n ? \&by_nbentries : \&by_name;
63 sub summary_output {
64 my ($obj, $num, $key);
66 foreach $key (sort $sort_method keys %map) {
67 $obj = $map{$key};
68 $num = @$obj;
69 printf "%s: %u\n", $key, $num;
70 $n_output += $num;
74 sub shortlog_output {
75 my ($obj, $num, $key, $desc);
77 foreach $key (sort $sort_method keys %map) {
78 $obj = $map{$key};
79 $num = @$obj;
81 # output author
82 printf "%s (%u):\n", $key, $num;
84 # output author's 1-line summaries
85 foreach $desc (reverse @$obj) {
86 print " $desc\n";
87 $n_output++;
90 # blank line separating author from next author
91 print "\n";
95 sub changelog_input {
96 my ($author, $desc);
98 while (<>) {
99 # get author and email
100 if ($pstate == 1) {
101 my ($email);
103 next unless /^[Aa]uthor:?\s*(.*?)\s*<(.*)>/;
105 $n_records++;
107 $author = $1;
108 $email = $2;
109 $desc = undef;
111 # cset author fixups
112 if (exists $mailmap{$email}) {
113 $author = $mailmap{$email};
114 } elsif (exists $mailmap{$author}) {
115 $author = $mailmap{$author};
116 } elsif (!$author) {
117 $author = $email;
119 $email{$author}{$email}++;
120 $pstate++;
123 # skip to blank line
124 elsif ($pstate == 2) {
125 next unless /^\s*$/;
126 $pstate++;
129 # skip to non-blank line
130 elsif ($pstate == 3) {
131 next unless /^\s*?(.*)/;
133 # skip lines that are obviously not
134 # a 1-line cset description
135 next if /^\s*From: /;
137 chomp;
138 $desc = $1;
140 &shortlog_entry($author, $desc);
142 $pstate = 1;
145 else {
146 die "invalid parse state $pstate";
151 sub read_mailmap {
152 my ($fh, $mailmap) = @_;
153 while (<$fh>) {
154 chomp;
155 if (/^([^#].*?)\s*<(.*)>/) {
156 $mailmap->{$2} = $1;
161 sub setup_mailmap {
162 read_mailmap(\*DATA, \%mailmap);
163 if (-f '.mailmap') {
164 my $fh = undef;
165 open $fh, '<', '.mailmap';
166 read_mailmap($fh, \%mailmap);
167 close $fh;
171 sub finalize {
172 #print "\n$n_records records parsed.\n";
174 if ($n_records != $n_output) {
175 die "parse error: input records != output records\n";
177 if (0) {
178 for my $author (sort keys %email) {
179 my $e = $email{$author};
180 for my $email (sort keys %$e) {
181 print STDERR "$author <$email>\n";
187 &setup_mailmap;
188 &changelog_input;
189 $opt_s ? &summary_output : &shortlog_output;
190 &finalize;
191 exit(0);
194 __DATA__
196 # Even with git, we don't always have name translations.
197 # So have an email->real name table to translate the
198 # (hopefully few) missing names
200 Adrian Bunk <bunk@stusta.de>
201 Andreas Herrmann <aherrman@de.ibm.com>
202 Andrew Morton <akpm@osdl.org>
203 Andrew Vasquez <andrew.vasquez@qlogic.com>
204 Christoph Hellwig <hch@lst.de>
205 Corey Minyard <minyard@acm.org>
206 David Woodhouse <dwmw2@shinybook.infradead.org>
207 Domen Puncer <domen@coderock.org>
208 Douglas Gilbert <dougg@torque.net>
209 Ed L Cashin <ecashin@coraid.com>
210 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
211 Felix Moeller <felix@derklecks.de>
212 Frank Zago <fzago@systemfabricworks.com>
213 Greg Kroah-Hartman <gregkh@suse.de>
214 James Bottomley <jejb@mulgrave.(none)>
215 James Bottomley <jejb@titanic.il.steeleye.com>
216 Jeff Garzik <jgarzik@pretzel.yyz.us>
217 Jens Axboe <axboe@suse.de>
218 Kay Sievers <kay.sievers@vrfy.org>
219 Mitesh shah <mshah@teja.com>
220 Morten Welinder <terra@gnome.org>
221 Morten Welinder <welinder@anemone.rentec.com>
222 Morten Welinder <welinder@darter.rentec.com>
223 Morten Welinder <welinder@troll.com>
224 Nguyen Anh Quynh <aquynh@gmail.com>
225 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
226 Peter A Jonsson <pj@ludd.ltu.se>
227 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
228 Rudolf Marek <R.Marek@sh.cvut.cz>
229 Rui Saraiva <rmps@joel.ist.utl.pt>
230 Sachin P Sant <ssant@in.ibm.com>
231 Santtu Hyrkk\e,Av\e(B <santtu.hyrkko@gmail.com>
232 Simon Kelley <simon@thekelleys.org.uk>
233 Tejun Heo <htejun@gmail.com>
234 Tony Luck <tony.luck@intel.com>