[prev in list] [next in list] [prev in thread] [next in thread] 

List:       git
Subject:    Re: RFC: Very useful script to SVG graph the git commits from a file orientated view
From:       John Tapsell <johnflux () gmail ! com>
Date:       2013-04-04 12:50:37
Message-ID: CAHQ6N+r7RpV3n+Mb3GEyJim7-bwML_OUmveLZjWcRWp_HF-rNQ () mail ! gmail ! com
[Download RAW message or body]

Opps, somehow I forgot to actually attach it.

It's now attached

["graph_git.pl" (application/octet-stream)]

#!/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/&#10;/g;
		$fullinfo =~ s/  +/ /g; #spaces eat up a lot space since they get encoded to &nbsp; \
= 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 ]; }


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic