A little git activity graphing tool
[u/fanf2/git-graph.git] / git-graph
1 #!/usr/bin/perl
2
3 use warnings;
4 use strict;
5
6 use Getopt::Long qw{:config gnu_getopt posix_default};
7 use Term::ReadKey;
8
9 $0 =~ s{^.*/([^/]+)$}{$1};
10
11 sub stop { exit 1; } # because 'die' uses a weird exit status
12 sub wail { warn "$0: @_\n"; }
13 sub fail { wail @_; stop; }
14 sub fale { fail "@_: $!"; }
15
16 my %opt;
17 GetOptions(\%opt, qw{
18 cancel
19 overlay
20 stack
21 }) or stop;
22
23 $opt{stack} = 1 unless $opt{cancel} or $opt{overlay};
24
25 my @log = qx{git log --pretty=format:%ai --shortstat};
26
27 my %add;
28 my %del;
29
30 my $addmax = 0;
31 my $delmax = 0;
32 my $canmax = 0;
33
34 while (@log) {
35 my $date = shift @log;
36 my $stat = shift @log;
37 my $blank = shift @log;
38 fail "bad blank line $blank"
39 unless not defined $blank or $blank eq "\n";
40 fail "truncated git log output"
41 unless defined $date and defined $stat;
42 chomp ($date, $stat);
43 $date =~ s{^([0-9-]{10}) [0-9:]{8} [+-][0-9]{4}$}{$1}
44 or fail "bad date $date";
45 $stat =~ m{^\ \d+\ files?\ changed
46 (?:,\ (\d+)\ insertion[s()+]+)?
47 (?:,\ (\d+)\ deletion[s()-]+)?$}x
48 or fail "bad stats $stat";
49 my ($add,$del) = ($1 || 0, $2 || 0);
50 $add{$date} += $add;
51 $del{$date} += $del;
52 $addmax = $add{$date} if $addmax < $add{$date};
53 $delmax = $del{$date} if $delmax < $del{$date};
54 my $can = $add{$date} > $del{$date} ?
55 $add{$date} - $del{$date} :
56 $del{$date} - $add{$date};
57 $canmax = $can if $canmax < $can;
58 }
59
60 my $max = $opt{cancel} ? $canmax :
61 $opt{stack} ? $addmax + $delmax :
62 $addmax > $delmax ? $addmax : $delmax;
63 my $width = [GetTerminalSize]->[0] - 12;
64 my $scale = $width / $max;
65
66 for my $date (sort keys %add) {
67 my $add;
68 my $del;
69 my $mod;
70 if ($opt{cancel}) {
71 if ($add{$date} > $del{$date}) {
72 $add = $add{$date} - $del{$date};
73 $del = $mod = 0;
74 } else {
75 $del = $del{$date} - $add{$date};
76 $add = $mod = 0;
77 }
78 }
79 if ($opt{overlay}) {
80 if ($add{$date} > $del{$date}) {
81 $add = $add{$date} - $del{$date};
82 $del = 0;
83 $mod = $del{$date};
84 } else {
85 $del = $del{$date} - $add{$date};
86 $add = 0;
87 $mod = $add{$date};
88 }
89 }
90 if ($opt{stack}) {
91 $add = $add{$date};
92 $del = $del{$date};
93 $mod = 0;
94 }
95 printf "$date \e[33m%s\e[32m%s\e[31m%s\e[0m\n",
96 "#" x ($mod * $scale),
97 "+" x ($add * $scale),
98 "-" x ($del * $scale);
99 }