Hi, a few days ago, I posted an ASCII representation of a commit graph. This was really tedious, so I wrote a simple script to generate it (and also to prove that I am not making everything a builtin). It takes revision range arguments, so if you call it with '-25 229ed74' on the git repository, you will get this: A---C-----F---------------------Q---------------Y / / / / B D-E G-------K-------O-P---R---T-U-V-W-X / ,-----' H-I-J---L-M-N---------S Now, without further ado, the script. -- snipsnap -- #!/usr/bin/perl if ($#ARGV < 1) { print STDERR "Usage: $ARGV0 <revision range>\n"; exit(1); } open INPUT, 'git rev-list --parents ' . join(' ', @ARGV) . '|'; %commits=(); @list=(); sub add_parents ($$) { my $parents = $_[0]; my $y = $_[1]; foreach my $parent (split / /,$parents) { if ($commits->{$parent} == undef) { $commits->{$parent} = { 'y' => $y++, 'sha1' => $parent }; } else { if ($commits->{$parent}->{y} < $y) { $commits->{$parent}->{y} = $y++; } else { $y = $commits->{$parent}->{y} + 1; } } } } # expects output of `rev-list --parents --topo-order` $i = 0; while (<INPUT>) { if (/^([0-9a-f]{40}) ?(.*)$/) { $sha1 = $1; $parents = $2; if ($commits->{$sha1} == undef) { $commits->{$sha1} = { 'y' => 0, 'sha1' => $sha1, }; } else { $commits->{$sha1}->{index} = $#list; } $commits->{$sha1}->{parents} = $parents; $list[$i] = $commits->{$sha1}; $commits->{$sha1}->{index} = $i++; add_parents($parents, $commits->{$sha1}->{y}); } } close INPUT; if ($#list >= 26) { print STDERR "Cannot draw more than 26 revs."; exit(1); } # make labels $height = 0; for ($i = 0; $i <= $#list; $i++) { $list[$i]->{x} = $#list - $i; $list[$i]->{label} = chr(0x41 + $list[$i]->{x}); if ($height < $list[$i]->{y}) { $height = $list[$i]->{y}; } } # make a canvas $width = $#list * 2 + 1; $height = $height * 2 + 1; @canvas = (); for ($i = 0; $i < $height; $i++) { $canvas[$i] = ' ' x $width . "\n"; } sub set_cell ($$$) { my $x = $_[0]; my $y = $_[1]; my $c = $_[2]; $canvas[$y] = substr($canvas[$y], 0, $x) . $c . substr($canvas[$y], $x + 1); } sub get_cell ($$) { my $x = $_[0]; my $y = $_[1]; return substr($canvas[$y], $x, 1); } sub msg($) { my $info = $_[0]; return $info->{label} . ": " . $info->{x} . ", " . $info->{y}; } sub draw_line ($$) { my $commit1 = $_[0]; my $commit2 = $_[1]; my $x1 = $commit1->{x}; my $y1 = $commit1->{y}; my $x2 = $commit2->{x}; my $y2 = $commit2->{y}; if ($y1 == $y2) { for (my $i = $x1 * 2 - 1; $i > $x2 * 2; $i--) { set_cell($i, $y1 * 2, "-"); } } else { my $is_straight = 0; my $factor = ($y2 - $y1) / ($x1 - $x2); my $i; if ($x1 - $x2 == $y2 - $y1) { $is_straight = 1; for ($i = $x1 * 2 - 1; $i > $x2 * 2; $i -= 2) { my $y = $y1 * 2 + ($x1 * 2 - $i) * $factor; my $c = get_cell($i, int($y)); if ($c ne ' ' && $c ne '-') { $is_straight = 0; } } } if ($is_straight) { for ($i = $x1 * 2 - 1; $i > $x2 * 2; $i--) { my $y = $y1 * 2 + ($x1 * 2 - $i) * $factor; my $c = (get_cell($i, int($y)) ne ' ') ? '+' : '/'; set_cell($i, int($y), $c); } } else { set_cell($x1 * 2 - 1, $y1 * 2 + 1, '\''); for ($i = $x1 * 2 - 2; $i > $x2 * 2 + 1; $i--) { set_cell($i, $y1 * 2 + 1, '-'); } set_cell($x2 * 2 + 1, $y1 * 2 + 1, ','); for ($i = $y1 * 2 + 2; $i < $y2 * 2; $i++) { my $c = (get_cell($x2 * 2, $i) ne ' ') ? '+' : '|'; set_cell($x2 * 2, $i, $c); } } } } # draw it for ($i = 0; $i <= $#list; $i++) { $info = $list[$i]; $x = $info->{x} * 2; $y = $info->{y} * 2; set_cell ($x, $y, $info->{label}); foreach my $parent (split / /,$info->{parents}) { if ($commits->{$parent}->{index} != undef) { draw_line($info, $commits->{$parent}); } } } print @canvas; - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html