A little git activity graphing tool
[u/fanf2/git-graph.git] / git-graph
CommitLineData
cce87900
TF
1#!/usr/bin/perl
2
3use warnings;
4use strict;
5
6use Getopt::Long qw{:config gnu_getopt posix_default};
7use Term::ReadKey;
8
9$0 =~ s{^.*/([^/]+)$}{$1};
10
11sub stop { exit 1; } # because 'die' uses a weird exit status
12sub wail { warn "$0: @_\n"; }
13sub fail { wail @_; stop; }
14sub fale { fail "@_: $!"; }
15
16my %opt;
17GetOptions(\%opt, qw{
18 cancel
19 overlay
20 stack
21}) or stop;
22
23$opt{stack} = 1 unless $opt{cancel} or $opt{overlay};
24
25my @log = qx{git log --pretty=format:%ai --shortstat};
26
27my %add;
28my %del;
29
30my $addmax = 0;
31my $delmax = 0;
32my $canmax = 0;
33
34while (@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
60my $max = $opt{cancel} ? $canmax :
61 $opt{stack} ? $addmax + $delmax :
62 $addmax > $delmax ? $addmax : $delmax;
63my $width = [GetTerminalSize]->[0] - 12;
64my $scale = $width / $max;
65
66for 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}