1
-#!/usr/bin/perl -w
2
-my %mailmap = ();
3
-open I, "<", ".mailmap";
4
-while (<I>) {
5
- chomp;
6
- next if /^#/;
7
- if (my ($author, $mail) = /^(.*?)\s+<(.+)>$/) {
8
- $mailmap{$mail} = $author;
9
- }
1
+#!/usr/bin/perl
2
+
3
+use warnings 'all';
4
+use strict;
5
+use Getopt::Long;
6
+
7
+my $match_emails;
8
+my $match_names;
9
+my $order_by = 'count';
10
+Getopt::Long::Configure(qw(bundling));
11
+GetOptions(
12
+ 'emails|e!' => \$match_emails,
13
+ 'names|n!' => \$match_names,
14
+ 'count|c' => sub { $order_by = 'count' },
15
+ 'time|t' => sub { $order_by = 'stamp' },
16
+) or exit 1;
17
+$match_emails = 1 unless $match_names;
18
+
19
+my $email = {};
20
+my $name = {};
21
+
22
+open(my $fh, '-|', "git log --format='%at <%aE> %aN'");
23
+while(<$fh>) {
24
+ my ($t, $e, $n) = /(\S+) <(\S+)> (.*)/;
25
+ mark($email, $e, $n, $t);
26
+ mark($name, $n, $e, $t);
27
}
11
-close I;
12
-
13
-my %mail2author = ();
14
-open I, "git log --pretty='format:%ae %an' |";
15
-while (<I>) {
16
- chomp;
17
- my ($mail, $author) = split(/\t/, $_);
18
- next if exists $mailmap{$mail};
19
- $mail2author{$mail} ||= {};
20
- $mail2author{$mail}{$author} ||= 0;
21
- $mail2author{$mail}{$author}++;
28
+close($fh);
29
+
30
+if ($match_emails) {
31
+ foreach my $e (dups($email)) {
32
+ foreach my $n (vals($email->{$e})) {
33
+ show($n, $e, $email->{$e}->{$n});
34
+ }
35
+ print "\n";
36
+ }
37
}
23
-close I;
24
-
25
-while (my ($mail, $authorcount) = each %mail2author) {
26
- # %$authorcount is ($author => $count);
27
- # sort and show the names from the most frequent ones.
28
- my @names = (map { $_->[0] }
29
- sort { $b->[1] <=> $a->[1] }
30
- map { [$_, $authorcount->{$_}] }
31
- keys %$authorcount);
32
- if (1 < @names) {
33
- for (@names) {
34
- print "$_ <$mail>\n";
38
+if ($match_names) {
39
+ foreach my $n (dups($name)) {
40
+ foreach my $e (vals($name->{$n})) {
41
+ show($n, $e, $name->{$n}->{$e});
42
}
43
+ print "\n";
44
}
45
}
46
+exit 0;
47
48
+sub mark {
49
+ my ($h, $k, $v, $t) = @_;
50
+ my $e = $h->{$k}->{$v} ||= { count => 0, stamp => 0 };
51
+ $e->{count}++;
52
+ $e->{stamp} = $t unless $t < $e->{stamp};
53
+}
54
+
55
+sub dups {
56
+ my $h = shift;
57
+ return grep { keys($h->{$_}) > 1 } keys($h);
58
+}
59
+
60
+sub vals {
61
+ my $h = shift;
62
+ return sort {
63
+ $h->{$b}->{$order_by} <=> $h->{$a}->{$order_by}
64
+ } keys($h);
65
+}
66
+
67
+sub show {
68
+ my ($n, $e, $h) = @_;
69
+ print "$n <$e> ($h->{$order_by})\n";
70
+}