Created
April 9, 2013 12:45
-
-
Save boucman/5345430 to your computer and use it in GitHub Desktop.
JohnFlux's nifty git graphing tool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
eval "require Git::Repository; require IPC::Run; 1" or die "Please do: sudo apt-get install libgit-repository-perl graphviz libipc-run-perl - Missing libraries"; | |
use Git::Repository; | |
use IPC::Run qw( run ); | |
my $svg_filename = "plot.svg"; | |
if (!defined($ARGV[0]) || $ARGV[0] eq "-h" || $ARGV[0] eq "--help") { | |
print <<"EOT"; | |
JohnFlux's nifty git graphing tool | |
================================== | |
This program produces a $svg_filename file in the current folder, for the | |
commits in the given git range in the current git repository. | |
In the SVG, a commit's parents are the commits that last touched the same files | |
that the commit touched. This graph is particularly useful when trying to squash. | |
Multiple lines between the same commits means that those commits both modified the same | |
multiple set of files. | |
Run as $0 [-h|--help] | |
$0 [--stdout] [--nofiles] <git log options>. | |
Examples: | |
#show the last 100 commits: | |
$0 -100 && firefox plot.svg | |
#show all the commits back to branch foo: | |
$0 HEAD...foo && firefox plot.svg | |
#show all the commits back to branch foo and don't show the files in seperate boxes: | |
$0 --nofiles HEAD...foo && firefox plot.svg | |
EOT | |
exit; | |
} | |
my $onlyPrintResult = 0; | |
my $noFiles = 0; | |
if ($ARGV[0] eq "--stdout") { | |
shift; | |
$onlyPrintResult = 1; | |
} | |
if ($ARGV[0] eq "--nofiles") { | |
shift; | |
$noFiles = 1; | |
} | |
my $git = Git::Repository->new( work_tree => '.' ); | |
my @lines = $git->run( log=> '--name-only', '--pretty=format:%h %s', @ARGV); | |
my %filesToSha = (); | |
my %filesToColorIndex = (); | |
my $nextColorIndex = 1; | |
my $sha = ""; | |
my $title = ""; | |
my $nextLineIsSha = 1; | |
my $output =""; | |
$output .= 'digraph "git" {' . "\n"; | |
for my $line ( @lines ) { | |
#Empty line moves us on to the next commit | |
if ($line =~ /^\s*$/) { | |
$nextLineIsSha = 1; | |
} elsif ($nextLineIsSha) { | |
$nextLineIsSha = 0; | |
($sha, $title) = split ' ', $line, 2; | |
my $fullinfo = $git->run( show => '--stat', $sha ); | |
$title =~ s/"/'/g; | |
$fullinfo =~ s/"/'/g; | |
$fullinfo =~ s/\n/ /g; | |
$fullinfo =~ s/ +/ /g; #spaces eat up a lot space since they get encoded to = 6 letters | |
# Firefox can't cope with it being longer than about 3000 characters | |
# but character encodings mean that a single character can expand to many letters. So we just have to guess at | |
# a maximum length here | |
$fullinfo = substr($fullinfo, 0, 1000); | |
$output .= "\"$sha\" [label=\"$sha $title\", tooltip=\"$fullinfo\"]\n"; | |
} else { | |
# $line is a filename that the current $sha commit modified | |
# See http://www.graphviz.org/doc/info/colors.html for a list of color schemes | |
my $colorIndex; | |
if( defined( my $parentSha = $filesToSha{ $line } ) ) { | |
$colorIndex = $filesToColorIndex{ $line }; | |
$output .= "\"$parentSha\" -> { \"$sha\" } ";# no newline - we append the edge properties next | |
$output .= " [edgetooltip=\"$line\", colorscheme=\"paired12\", color=\"$colorIndex\"]\n"; | |
} else { | |
$filesToColorIndex{ $line } = $colorIndex = $nextColorIndex; | |
$nextColorIndex = ($nextColorIndex % 12) +1; # mod 12 because we're using the paired12 colorscheme, which has 12 colors | |
if ($noFiles == 0) { | |
$output .= "\"$line\" [shape=box]\n"; | |
$output .= "\"$line\" -> { \"$sha\" } "; # no newline - we append the edge properties next | |
$output .= " [edgetooltip=\"$line\", colorscheme=\"paired12\", color=\"$colorIndex\"]\n"; | |
} | |
} | |
$filesToSha{ $line } = $sha; | |
} | |
} | |
$output .= "}\n"; | |
if ($onlyPrintResult) { | |
print $output; | |
# Example use of output: | |
# cat tmp.dot | dot -Tsvg -o plot.svg | |
# | |
# Or to make the result tall instead of wide: | |
# cat tmp.dot | ccomps -Cx | dot | gvpack -array_1 | neato -n2 -Tsvg -o plot.svg | |
} else { | |
run [ qw(ccomps -Cx) ], '<', \$output, "|", [ qw(dot) ], "|", [ qw(gvpack -array_1) ], "|", [ qw( neato -n2 -Tsvg -o ), $svg_filename ]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment