# [PATCH 6/6] gitweb: use blame --porcelain

3 messages from 2006-10-05 to 2006-10-05. Participants: Junio C Hamano.
Thread: https://gitlist.dev/t/5827

## Junio C Hamano, 2006-10-05 21:07

Subject: [PATCH 6/6] gitweb: use blame --porcelain
Message-ID: <7vwt7ebhe9.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vwt7ebhe9.fsf%40assigned-by-dhcp.cox.net

```
This makes gitweb (git_blame2) to use "blame --porcelain", which
lets the caller to figure out which line in the original version
each line comes from.  Using this information, change the
behaviour of clicking the line number to go to the line of the
blame output for the original commit.

Before, clicking the line number meant "scoll up to show this
line at the beginning of the page", which was not all that
useful.  The new behaviour lets you click on the line you are
interested in to view the line in the context it was introduced,
and keep digging deeper as you examine it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 * I've tested this only very lightly but it seems to be quite
   pleasant to use.

 gitweb/gitweb.perl |   65 +++++++++++++++++++++++++++++++++++----------------
 1 files changed, 44 insertions(+), 21 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index d217187..29a56c3 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -971,6 +971,9 @@ sub parse_date {
 	$date{'hour_local'} = $hour;
 	$date{'minute_local'} = $min;
 	$date{'tz_local'} = $tz;
+	$date{'iso-tz'} = sprintf ("%04d-%02d-%02d %02d:%02d:%02d %s",
+				   1900+$year, $mon+1, $mday,
+				   $hour, $min, $sec, $tz);
 	return %date;
 }
 
@@ -2496,7 +2499,8 @@ sub git_blame2 {
 	if ($ftype !~ "blob") {
 		die_error("400 Bad Request", "Object is not a blob");
 	}
-	open ($fd, "-|", git_cmd(), "blame", '-l', '--', $file_name, $hash_base)
+	open ($fd, "-|", git_cmd(), "blame", '--porcelain', '--',
+	      $file_name, $hash_base)
 		or die_error(undef, "Open git-blame failed");
 	git_header_html();
 	my $formats_nav =
@@ -2520,33 +2524,52 @@ sub git_blame2 {
 <table class="blame">
 <tr><th>Commit</th><th>Line</th><th>Data</th></tr>
 HTML
-	while (<$fd>) {
-		my ($full_rev, $author, $date, $lineno, $data) =
-			/^([0-9a-f]{40}).*?\s\((.*?)\s+([-\d]+ [:\d]+ [-+\d]+)\s+(\d+)\)\s(.*)/;
+	my %metainfo = ();
+	while (1) {
+		$_ = <$fd>;
+		last unless defined $_;
+		my ($full_rev, $lineno, $orig_lineno, $group_size) =
+		    /^([0-9a-f]{40}) (\d+) (\d+)(?: (\d+))?$/;
+		if (!exists $metainfo{$full_rev}) {
+			$metainfo{$full_rev} = {};
+		}
+		my $meta = $metainfo{$full_rev};
+		while (<$fd>) {
+			last if (s/^\t//);
+			if (/^(\S+) (.*)$/) {
+				$meta->{$1} = $2;
+			}
+		}
+		my $data = $_;
 		my $rev = substr($full_rev, 0, 8);
-		my $print_c8 = 0;
-
-		if (!defined $last_rev) {
-			$last_rev = $full_rev;
-			$print_c8 = 1;
-		} elsif ($last_rev ne $full_rev) {
-			$last_rev = $full_rev;
+		my $author = $meta->{'author'};
+		my %date = parse_date($meta->{'author-time'},
+				      $meta->{'author-tz'});
+		my $date = $date{'iso-tz'};
+		if ($group_size) {
 			$current_color = ++$current_color % $num_colors;
-			$print_c8 = 1;
 		}
 		print "<tr class=\"$rev_color[$current_color]\">\n";
-		print "<td class=\"sha1\"";
-		if ($print_c8 == 1) {
+		if ($group_size) {
+			print "<td class=\"sha1\"";
 			print " title=\"$author, $date\"";
-		}
-		print ">";
-		if ($print_c8 == 1) {
-			print $cgi->a({-href => href(action=>"commit", hash=>$full_rev, file_name=>$file_name)},
+			print " rowspan=\"$group_size\"" if ($group_size > 1);
+			print ">";
+			print $cgi->a({-href => href(action=>"commit",
+						     hash=>$full_rev,
+						     file_name=>$file_name)},
 				      esc_html($rev));
+			print "</td>\n";
 		}
-		print "</td>\n";
-		print "<td class=\"linenr\"><a id=\"l$lineno\" href=\"#l$lineno\" class=\"linenr\">" .
-		      esc_html($lineno) . "</a></td>\n";
+		my $blamed = href(action => 'blame',
+				  file_name => $meta->{'filename'},
+				  hash_base => $full_rev);
+		print "<td class=\"linenr\">";
+		print $cgi->a({ -href => "$blamed#l$lineno",
+				-id => "l$lineno",
+				-class => "linenr" },
+			      esc_html($lineno));
+		print "</td>";
 		print "<td class=\"pre\">" . esc_html($data) . "</td>\n";
 		print "</tr>\n";
 	}
-- 
1.4.2.3.g866f3

```

## Junio C Hamano, 2006-10-05 21:18

Subject: Re: [PATCH 6/6] gitweb: use blame --porcelain
Message-ID: <7vlknubgwj.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7vlknubgwj.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <7vwt7ebhe9.fsf@assigned-by-dhcp.cox.net>

```
Side note.

This change does not give any more information (other than the
link to the corresponding line in the original version) than the
current gitweb in "next", but "blame --porcelain" returns richer
information than it used to be available, most notably the
summary line.  It might be interesting to enhance the title pop-up
mechanism to show them on mouse-over, but I was too lazy ;-).

I've considered making the commit-8 link to link not to the
commit page for the originating commit but to the corresponding
line in the blame page for it, but opted to take over the line
number link, which was serving far less useful purpose.  Your
keyboard has PgUp and PgDn to let you navigate within the same
blame output.

As I noted in the log message for [3/6], I suspect that the
curent implementation to show the original line number is
unnecessarily inefficient.  Improvement is much encouraged.
Again, I am too lazy to look into it right now.

```

## Junio C Hamano, 2006-10-05 21:48

Subject: Re: [PATCH 6/6] gitweb: use blame --porcelain
Message-ID: <7v4puibfj6.fsf@assigned-by-dhcp.cox.net>
URL: https://gitlist.dev/e/7v4puibfj6.fsf%40assigned-by-dhcp.cox.net
In-Reply-To: <7vwt7ebhe9.fsf@assigned-by-dhcp.cox.net>

```
Found a stupid typo...

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index feb768f..8b97357 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -2589,7 +2589,7 @@ HTML
 				  file_name => $meta->{'filename'},
 				  hash_base => $full_rev);
 		print "<td class=\"linenr\">";
-		print $cgi->a({ -href => "$blamed#l$lineno",
+		print $cgi->a({ -href => "$blamed#l$orig_lineno",
 				-id => "l$lineno",
 				-class => "linenr" },
 			      esc_html($lineno));

```
