зеркало из https://github.com/microsoft/git.git
gitweb: Adding a `blame' interface.
This patch adds an interface for `git-blame' to `gitweb.cgi'. Links to it are placed in `git_blob'. Internally the code uses `git-annotate' because `git-blame's output differs for files that have been renamed in the past. However, I like the term `blame' better. [jc: blame can be told to produce the compatible format btw...] Signed-off-by: Florian Forster <octo@verplant.org> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
Родитель
8f732649bc
Коммит
e34ef62148
|
@ -203,6 +203,9 @@ if (!defined $action || $action eq "summary") {
|
||||||
} elsif ($action eq "tag") {
|
} elsif ($action eq "tag") {
|
||||||
git_tag();
|
git_tag();
|
||||||
exit;
|
exit;
|
||||||
|
} elsif ($action eq "blame") {
|
||||||
|
git_blame();
|
||||||
|
exit;
|
||||||
} else {
|
} else {
|
||||||
undef $action;
|
undef $action;
|
||||||
die_error(undef, "Unknown action.");
|
die_error(undef, "Unknown action.");
|
||||||
|
@ -1228,6 +1231,107 @@ sub git_tag {
|
||||||
git_footer_html();
|
git_footer_html();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub git_blame {
|
||||||
|
my $fd;
|
||||||
|
die_error('404 Not Found', "What file will it be, master?") if (!$file_name);
|
||||||
|
$hash_base ||= git_read_head($project);
|
||||||
|
die_error(undef, "Reading commit failed.") unless ($hash_base);
|
||||||
|
my %co = git_read_commit($hash_base)
|
||||||
|
or die_error(undef, "Reading commit failed.");
|
||||||
|
if (!defined $hash) {
|
||||||
|
$hash = git_get_hash_by_path($hash_base, $file_name, "blob")
|
||||||
|
or die_error(undef, "Error lookup file.");
|
||||||
|
}
|
||||||
|
open ($fd, "-|", "$gitbin/git-annotate", '-l', '-t', '-r', $file_name, $hash_base)
|
||||||
|
or die_error(undef, "Open failed.");
|
||||||
|
git_header_html();
|
||||||
|
print "<div class=\"page_nav\">\n" .
|
||||||
|
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=summary")}, "summary") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=shortlog")}, "shortlog") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=log")}, "log") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base")}, "commit") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
|
||||||
|
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$hash;hb=$hash_base;f=$file_name")}, "blob") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;f=$file_name")}, "head") . "<br/>\n";
|
||||||
|
print "</div>\n".
|
||||||
|
"<div>" .
|
||||||
|
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commit;h=$hash_base"), -class => "title"}, esc_html($co{'title'})) .
|
||||||
|
"</div>\n";
|
||||||
|
print "<div class=\"page_path\"><b>" . esc_html($file_name) . "</b></div>\n";
|
||||||
|
print "<div class=\"page_body\">\n";
|
||||||
|
print <<HTML;
|
||||||
|
<table style="border-collapse: collapse;">
|
||||||
|
<tr>
|
||||||
|
<th>Commit</th>
|
||||||
|
<th>Age</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Line</th>
|
||||||
|
<th>Data</th>
|
||||||
|
</tr>
|
||||||
|
HTML
|
||||||
|
my @line_class = (qw(light dark));
|
||||||
|
my $line_class_len = scalar (@line_class);
|
||||||
|
my $line_class_num = $#line_class;
|
||||||
|
while (my $line = <$fd>) {
|
||||||
|
my $long_rev;
|
||||||
|
my $short_rev;
|
||||||
|
my $author;
|
||||||
|
my $time;
|
||||||
|
my $lineno;
|
||||||
|
my $data;
|
||||||
|
my $age;
|
||||||
|
my $age_str;
|
||||||
|
my $age_style;
|
||||||
|
|
||||||
|
chomp $line;
|
||||||
|
$line_class_num = ($line_class_num + 1) % $line_class_len;
|
||||||
|
|
||||||
|
if ($line =~ m/^([0-9a-fA-F]{40})\t\(\s*([^\t]+)\t(\d+) \+\d\d\d\d\t(\d+)\)(.*)$/) {
|
||||||
|
$long_rev = $1;
|
||||||
|
$author = $2;
|
||||||
|
$time = $3;
|
||||||
|
$lineno = $4;
|
||||||
|
$data = $5;
|
||||||
|
} else {
|
||||||
|
print qq( <tr><td colspan="5" style="color: red; background-color: yellow;">Unable to parse: $line</td></tr>\n);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$short_rev = substr ($long_rev, 0, 8);
|
||||||
|
$age = time () - $time;
|
||||||
|
$age_str = age_string ($age);
|
||||||
|
$age_str =~ s/ / /g;
|
||||||
|
$age_style = 'font-style: italic;';
|
||||||
|
$age_style .= ' color: #009900; background: transparent;' if ($age < 60*60*24*2);
|
||||||
|
$age_style .= ' font-weight: bold;' if ($age < 60*60*2);
|
||||||
|
$author = esc_html ($author);
|
||||||
|
$author =~ s/ / /g;
|
||||||
|
# escape tabs
|
||||||
|
while ((my $pos = index($data, "\t")) != -1) {
|
||||||
|
if (my $count = (8 - ($pos % 8))) {
|
||||||
|
my $spaces = ' ' x $count;
|
||||||
|
$data =~ s/\t/$spaces/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data = esc_html ($data);
|
||||||
|
$data =~ s/ / /g;
|
||||||
|
|
||||||
|
print <<HTML;
|
||||||
|
<tr class="$line_class[$line_class_num]">
|
||||||
|
<td style="font-family: monospace;"><a href="$my_uri?${\esc_param ("p=$project;a=commit;h=$long_rev")}" class="text">$short_rev..</a></td>
|
||||||
|
<td style="$age_style">$age_str</td>
|
||||||
|
<td>$author</td>
|
||||||
|
<td style="text-align: right;"><a id="$lineno" href="#$lineno" class="linenr">$lineno</a></td>
|
||||||
|
<td style="font-family: monospace;">$data</td>
|
||||||
|
</tr>
|
||||||
|
HTML
|
||||||
|
} # while (my $line = <$fd>)
|
||||||
|
print "</table>\n\n";
|
||||||
|
close $fd or print "Reading blob failed.\n";
|
||||||
|
print "</div>";
|
||||||
|
git_footer_html();
|
||||||
|
}
|
||||||
|
|
||||||
sub git_tags {
|
sub git_tags {
|
||||||
my $head = git_read_head($project);
|
my $head = git_read_head($project);
|
||||||
git_header_html();
|
git_header_html();
|
||||||
|
@ -1375,7 +1479,8 @@ sub git_blob {
|
||||||
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=commitdiff;h=$hash_base")}, "commitdiff") .
|
||||||
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=tree;h=$co{'tree'};hb=$hash_base")}, "tree") . "<br/>\n";
|
||||||
if (defined $file_name) {
|
if (defined $file_name) {
|
||||||
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
|
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$hash;hb=$hash_base;f=$file_name")}, "blame") .
|
||||||
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash;f=$file_name")}, "plain") .
|
||||||
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head") . "<br/>\n";
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;hb=HEAD;f=$file_name")}, "head") . "<br/>\n";
|
||||||
} else {
|
} else {
|
||||||
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain") . "<br/>\n";
|
print $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob_plain;h=$hash")}, "plain") . "<br/>\n";
|
||||||
|
@ -1496,6 +1601,7 @@ sub git_tree {
|
||||||
"</td>\n" .
|
"</td>\n" .
|
||||||
"<td class=\"link\">" .
|
"<td class=\"link\">" .
|
||||||
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$t_hash$base_key;f=$base$t_name")}, "blob") .
|
$cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blob;h=$t_hash$base_key;f=$base$t_name")}, "blob") .
|
||||||
|
# " | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=blame;h=$t_hash$base_key;f=$base$t_name")}, "blame") .
|
||||||
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$hash_base;f=$base$t_name")}, "history") .
|
" | " . $cgi->a({-href => "$my_uri?" . esc_param("p=$project;a=history;h=$hash_base;f=$base$t_name")}, "history") .
|
||||||
"</td>\n";
|
"</td>\n";
|
||||||
} elsif ($t_type eq "tree") {
|
} elsif ($t_type eq "tree") {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче