X-Git-Url: https://git.ladys.computer/Gitweb/blobdiff_plain/3d5a4ed91ab80ecb065d6fa79792a77d00d88af2ce5c2140228c045e52c447c4..8018cb3bd77596fbd2687f078e0e5add76b848e109828a9aa8ad9876aee69e8e:/gitweb.perl
diff --git a/gitweb.perl b/gitweb.perl
old mode 100755
new mode 100644
index adfb99f..8b6c0c3
--- a/gitweb.perl
+++ b/gitweb.perl
@@ -102,11 +102,15 @@ our %feature = (
'sub' => \&feature_pickaxe,
'override' => 0,
'default' => [1]},
+
+ 'pathinfo' => {
+ 'override' => 0,
+ 'default' => [0]},
);
sub gitweb_check_feature {
my ($name) = @_;
- return undef unless exists $feature{$name};
+ return unless exists $feature{$name};
my ($sub, $override, @defaults) = (
$feature{$name}{'sub'},
$feature{$name}{'override'},
@@ -155,6 +159,13 @@ sub feature_snapshot {
return ($ctype, $suffix, $command);
}
+sub gitweb_have_snapshot {
+ my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
+ my $have_snapshot = (defined $ctype && defined $suffix);
+
+ return $have_snapshot;
+}
+
# To enable system wide have in $GITWEB_CONFIG
# $feature{'pickaxe'}{'default'} = [1];
# To have project specific config enable override in $GITWEB_CONFIG
@@ -200,9 +211,10 @@ if (defined $action) {
}
}
+# parameters which are pathnames
our $project = $cgi->param('p');
if (defined $project) {
- if (!validate_input($project) ||
+ if (!validate_pathname($project) ||
!(-d "$projectroot/$project") ||
!(-e "$projectroot/$project/HEAD") ||
($export_ok && !(-e "$projectroot/$project/$export_ok")) ||
@@ -214,46 +226,48 @@ if (defined $project) {
our $file_name = $cgi->param('f');
if (defined $file_name) {
- if (!validate_input($file_name)) {
+ if (!validate_pathname($file_name)) {
die_error(undef, "Invalid file parameter");
}
}
our $file_parent = $cgi->param('fp');
if (defined $file_parent) {
- if (!validate_input($file_parent)) {
+ if (!validate_pathname($file_parent)) {
die_error(undef, "Invalid file parent parameter");
}
}
+# parameters which are refnames
our $hash = $cgi->param('h');
if (defined $hash) {
- if (!validate_input($hash)) {
+ if (!validate_refname($hash)) {
die_error(undef, "Invalid hash parameter");
}
}
our $hash_parent = $cgi->param('hp');
if (defined $hash_parent) {
- if (!validate_input($hash_parent)) {
+ if (!validate_refname($hash_parent)) {
die_error(undef, "Invalid hash parent parameter");
}
}
our $hash_base = $cgi->param('hb');
if (defined $hash_base) {
- if (!validate_input($hash_base)) {
+ if (!validate_refname($hash_base)) {
die_error(undef, "Invalid hash base parameter");
}
}
our $hash_parent_base = $cgi->param('hpb');
if (defined $hash_parent_base) {
- if (!validate_input($hash_parent_base)) {
+ if (!validate_refname($hash_parent_base)) {
die_error(undef, "Invalid hash parent base parameter");
}
}
+# other parameters
our $page = $cgi->param('pg');
if (defined $page) {
if ($page =~ m/[^0-9]/) {
@@ -283,7 +297,7 @@ sub evaluate_path_info {
$project =~ s,/*[^/]*$,,;
}
# validate project
- $project = validate_input($project);
+ $project = validate_pathname($project);
if (!$project ||
($export_ok && !-e "$projectroot/$project/$export_ok") ||
($strict_export && !project_in_list($project))) {
@@ -300,15 +314,16 @@ sub evaluate_path_info {
$pathname =~ s,^/+,,;
if (!$pathname || substr($pathname, -1) eq "/") {
$action ||= "tree";
+ $pathname =~ s,/$,,;
} else {
$action ||= "blob_plain";
}
- $hash_base ||= validate_input($refname);
- $file_name ||= validate_input($pathname);
+ $hash_base ||= validate_refname($refname);
+ $file_name ||= validate_pathname($pathname);
} elsif (defined $refname) {
# we got "project.git/branch"
$action ||= "shortlog";
- $hash ||= validate_input($refname);
+ $hash ||= validate_refname($refname);
}
}
evaluate_path_info();
@@ -364,6 +379,7 @@ exit;
sub href(%) {
my %params = @_;
+ my $href = $my_uri;
my @mapping = (
project => "p",
@@ -382,6 +398,19 @@ sub href(%) {
$params{'project'} = $project unless exists $params{'project'};
+ my ($use_pathinfo) = gitweb_check_feature('pathinfo');
+ if ($use_pathinfo) {
+ # use PATH_INFO for project name
+ $href .= "/$params{'project'}" if defined $params{'project'};
+ delete $params{'project'};
+
+ # Summary just uses the project path URL
+ if (defined $params{'action'} && $params{'action'} eq 'summary') {
+ delete $params{'action'};
+ }
+ }
+
+ # now encode the parameters explicitly
my @result = ();
for (my $i = 0; $i < @mapping; $i += 2) {
my ($name, $symbol) = ($mapping[$i], $mapping[$i+1]);
@@ -389,23 +418,43 @@ sub href(%) {
push @result, $symbol . "=" . esc_param($params{$name});
}
}
- return "$my_uri?" . join(';', @result);
+ $href .= "?" . join(';', @result) if scalar @result;
+
+ return $href;
}
## ======================================================================
## validation, quoting/unquoting and escaping
-sub validate_input {
- my $input = shift;
+sub validate_pathname {
+ my $input = shift || return undef;
- if ($input =~ m/^[0-9a-fA-F]{40}$/) {
- return $input;
+ # no '.' or '..' as elements of path, i.e. no '.' nor '..'
+ # at the beginning, at the end, and between slashes.
+ # also this catches doubled slashes
+ if ($input =~ m!(^|/)(|\.|\.\.)(/|$)!) {
+ return undef;
}
- if ($input =~ m/(^|\/)(|\.|\.\.)($|\/)/) {
+ # no null characters
+ if ($input =~ m!\0!) {
return undef;
}
- if ($input =~ m/[^a-zA-Z0-9_\x80-\xff\ \t\.\/\-\+\#\~\%]/) {
+ return $input;
+}
+
+sub validate_refname {
+ my $input = shift || return undef;
+
+ # textual hashes are O.K.
+ if ($input =~ m/^[0-9a-fA-F]{40}$/) {
+ return $input;
+ }
+ # it must be correct pathname
+ $input = validate_pathname($input)
+ or return undef;
+ # restrictions on ref name according to git-check-ref-format
+ if ($input =~ m!(/\.|\.\.|[\000-\040\177 ~^:?*\[]|/$)!) {
return undef;
}
return $input;
@@ -414,6 +463,15 @@ sub validate_input {
# quote unsafe chars, but keep the slash, even when it's not
# correct, but quoted slashes look too horrible in bookmarks
sub esc_param {
+ my $str = shift;
+ $str =~ s/([^A-Za-z0-9\-_.~()\/:@])/sprintf("%%%02X", ord($1))/eg;
+ $str =~ s/\+/%2B/g;
+ $str =~ s/ /\+/g;
+ return $str;
+}
+
+# quote unsafe chars in whole URL, so some charactrs cannot be quoted
+sub esc_url {
my $str = shift;
$str =~ s/([^A-Za-z0-9\-_.~();\/;?:@&=])/sprintf("%%%02X", ord($1))/eg;
$str =~ s/\+/%2B/g;
@@ -427,6 +485,7 @@ sub esc_html {
$str = decode("utf8", $str, Encode::FB_DEFAULT);
$str = escapeHTML($str);
$str =~ s/\014/^L/g; # escape FORM FEED (FF) character (e.g. in COPYING file)
+ $str =~ s/\033/^[/g; # "escape" ESCAPE (\e) character (e.g. commit 20a3847d8a5032ce41f90dcc68abfb36e6fee9b1)
return $str;
}
@@ -626,7 +685,7 @@ sub format_subject_html {
if (length($short) < length($long)) {
return $cgi->a({-href => $href, -class => "list subject",
- -title => $long},
+ -title => decode("utf8", $long, Encode::FB_DEFAULT)},
esc_html($short) . $extra);
} else {
return $cgi->a({-href => $href, -class => "list subject"},
@@ -717,8 +776,9 @@ sub git_get_project_config {
sub git_get_hash_by_path {
my $base = shift;
my $path = shift || return undef;
+ my $type = shift;
- my $tree = $base;
+ $path =~ s,/+$,,;
open my $fd, "-|", git_cmd(), "ls-tree", $base, "--", $path
or die_error(undef, "Open git-ls-tree failed");
@@ -727,6 +787,10 @@ sub git_get_hash_by_path {
#'100644 blob 0fa3f3a66fb6a137f6ec2c19351ed4d807070ffa panic.c'
$line =~ m/^([0-9]+) (.+) ([0-9a-fA-F]{40})\t(.+)$/;
+ if (defined $type && $type ne $2) {
+ # type doesn't match
+ return undef;
+ }
return $3;
}
@@ -746,7 +810,7 @@ sub git_get_project_description {
sub git_get_project_url_list {
my $path = shift;
- open my $fd, "$projectroot/$path/cloneurl" or return undef;
+ open my $fd, "$projectroot/$path/cloneurl" or return;
my @git_project_url_list = map { chomp; $_ } <$fd>;
close $fd;
@@ -785,7 +849,7 @@ sub git_get_projects_list {
# 'git%2Fgit.git Linus+Torvalds'
# 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
# 'linux%2Fhotplug%2Fudev.git Greg+Kroah-Hartman'
- open my ($fd), $projects_list or return undef;
+ open my ($fd), $projects_list or return;
while (my $line = <$fd>) {
chomp $line;
my ($path, $owner) = split ' ', $line;
@@ -1276,7 +1340,7 @@ sub git_header_html {
if (defined $action) {
$title .= "/$action";
if (defined $file_name) {
- $title .= " - $file_name";
+ $title .= " - " . esc_html($file_name);
if ($action eq "tree" && $file_name !~ m|/$|) {
$title .= "/";
}
@@ -1332,7 +1396,7 @@ EOF
"" .
"
" .
"\n";
- print $cgi->a({-href => esc_param($home_link)}, $home_link_str) . " / ";
+ print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
if (defined $project) {
print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
if (defined $action) {
@@ -1513,12 +1577,15 @@ sub git_print_page_path {
my $fullname = '';
print "
";
+ print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
+ -title => 'tree root'}, "[$project]");
+ print " / ";
foreach my $dir (@dirname) {
- $fullname .= $dir . '/';
+ $fullname .= ($fullname ? '/' : '') . $dir;
print $cgi->a({-href => href(action=>"tree", file_name=>$fullname,
hash_base=>$hb),
-title => $fullname}, esc_html($dir));
- print "/";
+ print " / ";
}
if (defined $type && $type eq 'blob') {
print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
@@ -1528,7 +1595,6 @@ sub git_print_page_path {
print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
hash_base=>$hb),
-title => $name}, esc_html($basename));
- print "/";
} else {
print esc_html($basename);
}
@@ -1602,48 +1668,45 @@ sub git_print_tree_entry {
my %base_key = ();
$base_key{hash_base} = $hash_base if defined $hash_base;
+ # The format of a table row is: mode list link. Where mode is
+ # the mode of the entry, list is the name of the entry, an href,
+ # and link is the action links of the entry.
+
print "
" . mode_str($t->{'mode'}) . " | \n";
if ($t->{'type'} eq "blob") {
print "
" .
- $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key),
- -class => "list"}, esc_html($t->{'name'})) .
- " | \n" .
- "
" .
- $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "blob");
+ $cgi->a({-href => href(action=>"blob", hash=>$t->{'hash'},
+ file_name=>"$basedir$t->{'name'}", %base_key),
+ -class => "list"}, esc_html($t->{'name'})) . " | \n";
+ print "
";
if ($have_blame) {
- print " | " .
- $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- "blame");
+ print $cgi->a({-href => href(action=>"blame", hash=>$t->{'hash'},
+ file_name=>"$basedir$t->{'name'}", %base_key)},
+ "blame");
}
if (defined $hash_base) {
- print " | " .
- $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
+ if ($have_blame) {
+ print " | ";
+ }
+ print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")},
"history");
}
print " | " .
- $cgi->a({-href => href(action=>"blob_plain",
- hash=>$t->{'hash'}, file_name=>"$basedir$t->{'name'}")},
- "raw") .
- " | \n";
+ $cgi->a({-href => href(action=>"blob_plain", hash_base=>$hash_base,
+ file_name=>"$basedir$t->{'name'}")},
+ "raw");
+ print "\n";
} elsif ($t->{'type'} eq "tree") {
- print "
" .
- $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
- file_name=>"$basedir$t->{'name'}", %base_key)},
- esc_html($t->{'name'})) .
- " | \n" .
- "
" .
- $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
+ print " | ";
+ print $cgi->a({-href => href(action=>"tree", hash=>$t->{'hash'},
file_name=>"$basedir$t->{'name'}", %base_key)},
- "tree");
+ esc_html($t->{'name'}));
+ print " | \n";
+ print "
";
if (defined $hash_base) {
- print " | " .
- $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
+ print $cgi->a({-href => href(action=>"history", hash_base=>$hash_base,
file_name=>"$basedir$t->{'name'}")},
"history");
}
@@ -1664,7 +1727,7 @@ sub git_difftree_body {
print "\n";
print "\n";
- my $alternate = 0;
+ my $alternate = 1;
my $patchno = 0;
foreach my $line (@{$difftree}) {
my %diff = parse_difftree_raw_line($line);
@@ -1697,47 +1760,42 @@ sub git_difftree_body {
my $mode_chng = "[new $to_file_type";
$mode_chng .= " with mode: $to_mode_str" if $to_mode_str;
$mode_chng .= "]";
- print "| " .
- $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
+ print " | ";
+ print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
hash_base=>$hash, file_name=>$diff{'file'}),
- -class => "list"}, esc_html($diff{'file'})) .
- " | \n" .
- "$mode_chng | \n" .
- "" .
- $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
- hash_base=>$hash, file_name=>$diff{'file'})},
- "blob");
+ -class => "list"}, esc_html($diff{'file'}));
+ print " | \n";
+ print "$mode_chng | \n";
+ print "";
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print " | " .
- $cgi->a({-href => "#patch$patchno"}, "patch");
+ print $cgi->a({-href => "#patch$patchno"}, "patch");
}
print " | \n";
} elsif ($diff{'status'} eq "D") { # deleted
my $mode_chng = "[deleted $from_file_type]";
- print "" .
- $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
+ print " | ";
+ print $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
hash_base=>$parent, file_name=>$diff{'file'}),
- -class => "list"}, esc_html($diff{'file'})) .
- " | \n" .
- "$mode_chng | \n" .
- "" .
- $cgi->a({-href => href(action=>"blob", hash=>$diff{'from_id'},
- hash_base=>$parent, file_name=>$diff{'file'})},
- "blob") .
- " | ";
+ -class => "list"}, esc_html($diff{'file'}));
+ print " | \n";
+ print "$mode_chng | \n";
+ print "";
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print " | " .
- $cgi->a({-href => "#patch$patchno"}, "patch");
+ print $cgi->a({-href => "#patch$patchno"}, "patch");
+ print " | ";
}
+ print $cgi->a({-href => href(action=>"blame", hash_base=>$parent,
+ file_name=>$diff{'file'})},
+ "blame") . " | ";
print $cgi->a({-href => href(action=>"history", hash_base=>$parent,
- file_name=>$diff{'file'})},
- "history") .
- " | \n";
+ file_name=>$diff{'file'})},
+ "history");
+ print "\n";
} elsif ($diff{'status'} eq "M" || $diff{'status'} eq "T") { # modified, or type changed
my $mode_chnge = "";
@@ -1756,42 +1814,32 @@ sub git_difftree_body {
$mode_chnge .= "]\n";
}
print "";
- if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
- print $cgi->a({-href => href(action=>"blobdiff",
- hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
- hash_base=>$hash, hash_parent_base=>$parent,
- file_name=>$diff{'file'}),
- -class => "list"}, esc_html($diff{'file'}));
- } else { # only mode changed
- print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
- hash_base=>$hash, file_name=>$diff{'file'}),
- -class => "list"}, esc_html($diff{'file'}));
- }
- print " | \n" .
- "$mode_chnge | \n" .
- "" .
- $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
- hash_base=>$hash, file_name=>$diff{'file'})},
- "blob");
+ print $cgi->a({-href => href(action=>"blob", hash=>$diff{'to_id'},
+ hash_base=>$hash, file_name=>$diff{'file'}),
+ -class => "list"}, esc_html($diff{'file'}));
+ print " | \n";
+ print "$mode_chnge | \n";
+ print "";
if ($diff{'to_id'} ne $diff{'from_id'}) { # modified
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print " | " .
- $cgi->a({-href => "#patch$patchno"}, "patch");
+ print $cgi->a({-href => "#patch$patchno"}, "patch");
} else {
- print " | " .
- $cgi->a({-href => href(action=>"blobdiff",
- hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
- hash_base=>$hash, hash_parent_base=>$parent,
- file_name=>$diff{'file'})},
- "diff");
+ print $cgi->a({-href => href(action=>"blobdiff",
+ hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+ hash_base=>$hash, hash_parent_base=>$parent,
+ file_name=>$diff{'file'})},
+ "diff");
}
+ print " | ";
}
- print " | " .
- $cgi->a({-href => href(action=>"history",
- hash_base=>$hash, file_name=>$diff{'file'})},
- "history");
+ print $cgi->a({-href => href(action=>"blame", hash_base=>$hash,
+ file_name=>$diff{'file'})},
+ "blame") . " | ";
+ print $cgi->a({-href => href(action=>"history", hash_base=>$hash,
+ file_name=>$diff{'file'})},
+ "history");
print " | \n";
} elsif ($diff{'status'} eq "R" || $diff{'status'} eq "C") { # renamed or copied
@@ -1811,25 +1859,27 @@ sub git_difftree_body {
hash=>$diff{'from_id'}, file_name=>$diff{'from_file'}),
-class => "list"}, esc_html($diff{'from_file'})) .
" with " . (int $diff{'similarity'}) . "% similarity$mode_chng]\n" .
- "" .
- $cgi->a({-href => href(action=>"blob", hash_base=>$hash,
- hash=>$diff{'to_id'}, file_name=>$diff{'to_file'})},
- "blob");
+ " | ";
if ($diff{'to_id'} ne $diff{'from_id'}) {
if ($action eq 'commitdiff') {
# link to patch
$patchno++;
- print " | " .
- $cgi->a({-href => "#patch$patchno"}, "patch");
+ print $cgi->a({-href => "#patch$patchno"}, "patch");
} else {
- print " | " .
- $cgi->a({-href => href(action=>"blobdiff",
- hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
- hash_base=>$hash, hash_parent_base=>$parent,
- file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
- "diff");
+ print $cgi->a({-href => href(action=>"blobdiff",
+ hash=>$diff{'to_id'}, hash_parent=>$diff{'from_id'},
+ hash_base=>$hash, hash_parent_base=>$parent,
+ file_name=>$diff{'to_file'}, file_parent=>$diff{'from_file'})},
+ "diff");
}
+ print " | ";
}
+ print $cgi->a({-href => href(action=>"blame", hash_base=>$parent,
+ file_name=>$diff{'from_file'})},
+ "blame") . " | ";
+ print $cgi->a({-href => href(action=>"history", hash_base=>$parent,
+ file_name=>$diff{'from_file'})},
+ "history");
print " | \n";
} # we should not encounter Unmerged (U) or Unknown (X) status
@@ -1967,14 +2017,11 @@ sub git_shortlog_body {
# uses global variable $project
my ($revlist, $from, $to, $refs, $extra) = @_;
- my ($ctype, $suffix, $command) = gitweb_check_feature('snapshot');
- my $have_snapshot = (defined $ctype && defined $suffix);
-
$from = 0 unless defined $from;
$to = $#{$revlist} if (!defined $to || $#{$revlist} < $to);
print "\n";
- my $alternate = 0;
+ my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
my $commit = $revlist->[$i];
#my $ref = defined $refs ? format_ref_marker($refs, $commit) : '';
@@ -1994,11 +2041,9 @@ sub git_shortlog_body {
href(action=>"commit", hash=>$commit), $ref);
print "\n" .
"| " .
- $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
- $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
- if ($have_snapshot) {
- print " | " . $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
- }
+ $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
+ $cgi->a({-href => href(action=>"tree", hash=>$commit, hash_base=>$commit)}, "tree") . " | " .
+ $cgi->a({-href => href(action=>"snapshot", hash=>$commit)}, "snapshot");
print " | \n" .
"\n";
}
@@ -2018,7 +2063,7 @@ sub git_history_body {
$to = $#{$revlist} unless (defined $to && $to <= $#{$revlist});
print "\n";
- my $alternate = 0;
+ my $alternate = 1;
for (my $i = $from; $i <= $to; $i++) {
if ($revlist->[$i] !~ m/^([0-9a-fA-F]{40})/) {
next;
@@ -2047,9 +2092,8 @@ sub git_history_body {
href(action=>"commit", hash=>$commit), $ref);
print "\n" .
"| " .
- $cgi->a({-href => href(action=>"commit", hash=>$commit)}, "commit") . " | " .
- $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff") . " | " .
- $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype);
+ $cgi->a({-href => href(action=>$ftype, hash_base=>$commit, file_name=>$file_name)}, $ftype) . " | " .
+ $cgi->a({-href => href(action=>"commitdiff", hash=>$commit)}, "commitdiff");
if ($ftype eq 'blob') {
my $blob_current = git_get_hash_by_path($hash_base, $file_name);
@@ -2082,7 +2126,7 @@ sub git_tags_body {
$to = $#{$taglist} if (!defined $to || $#{$taglist} < $to);
print " | |