git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC] gitweb: add 'historyfollow' view that follows renames

From
BGBlucher, Guy <guy.blucher@dsto.defence.gov.au>
Date
Oct 27, 2008, 03:17 UTC
Message-ID
<054F21930D24A0428E5B4588462C7AED0149B4B8@ednex512.dsto.defence.gov.au>
Hi Folks,
>> 
>> What should we add to automatically get all file history?
Show 5 quoted lines
> While the 'commitdiff' view would, in default gitweb configuration, 
> contain information about file renames, currently 'history' view does 
> not support '--follow' option to git-log.  It wouldn't be too hard to 
> add it, but it just wasn't done (well, add to this the fact that 
> --follow works only for simple cases).

We also ran up against this issue because renaming of files in our project is a useful bit of information while browsing file history.

I hacked gitweb to add a 'historyfollow' viewing option in addition to the 'history' option. Yes, '--follow' is expensive so I didn't just make it the default 'history' behaviour.

The only problem with doing it was that parse_commits in gitweb.perl uses git rev-list which doesn't support the '--follow' option like git-log does. A bit of hacking to use 'git log --pretty=raw -z' to make the output look close to that from rev-list means only minor shoe-horning is required (perhaps it would be better to make rev-list understand --follow though?).

I wasn't originally prepared to publish the work here because I don't really think it's the best solution. But considering it's come up... I include a patch inline against gitweb.perl from v1.6.0.3 that implements a 'historyfollow' view.

Feel free to do with it what you will. It would need some substantial tidying up by someone who knows much more about perl than me :)

We use it such that anywhere a 'history' link is provided a 'historyfollow' link is also provided next to it - This patch doesn't implement that bit though.

Hope it helps.

Cheers, Guy.

---
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -478,6 +478,7 @@ my %actions = (
        "forks" => \&git_forks,
        "heads" => \&git_heads,
        "history" => \&git_history,
+       "historyfollow" => \&git_history_follow,
        "log" => \&git_log,
        "rss" => \&git_rss,
        "atom" => \&git_atom,
@@ -2311,25 +2312,39 @@ sub parse_commit {
 }
 
 sub parse_commits {
-       my ($commit_id, $maxcount, $skip, $filename, @args) = @_;
+       my ($commit_id, $maxcount, $skip, $mode, $filename, @args) = @_;
        my @cos;
 
        $maxcount ||= 1;
        $skip ||= 0;
 
        local $/ = "\0";
+        # The '--max-count' argument is not available when doing a
+        # '--follow' to 'git log'
+        my $count_arg = ("--max-count=" . $maxcount) ;
+        if (defined $mode && $mode eq "--follow") {
+            $count_arg = "--follow" ;
+        }
 
-       open my $fd, "-|", git_cmd(), "rev-list",
-               "--header",
+
+       open my $fd, "-|", git_cmd(), "log",
+               "-z",
+               "--pretty=raw",
                @args,
-               ("--max-count=" . $maxcount),
+                ($count_arg ? ($count_arg ) : ()),
                ("--skip=" . $skip),
                @extra_options,
                $commit_id,
                "--",
                ($filename ? ($filename) : ())
-               or die_error(500, "Open git-rev-list failed");
+               or die_error(500, "Open git-log failed");
        while (my $line = <$fd>) {
+               # Need to put a delimiter on the end of output
+                # 'git-log -z' doesn't put one before EOF like rev-list
does
+                $line = ($line . '\0');
+                # Need to strip the word commit from the start so it
+                # looks like rev-list output
+                $line =~ s/^commit // ;
                my %co = parse_commit_text($line);
                push @cos, \%co;
        }
@@ -5363,6 +5378,13 @@ sub git_commitdiff_plain {
 }
 
 sub git_history {
+        my $mode = shift || '';
+        my $history_call = "history";
+
+       if ($mode eq "--follow") {
+           $history_call .= "historyfollow" ;
+       }
+
        if (!defined $hash_base) {
                $hash_base = git_get_head_hash($project);
        }
@@ -5377,7 +5399,7 @@ sub git_history {
        my $limit = sprintf("--max-count=%i", (100 * ($page+1)));
 
        my @commitlist = parse_commits($hash_base, 101, (100 * $page),
-                                      $file_name, "--full-history")
+                                      $mode, $file_name,
"--full-history")
            or die_error(404, "No such file or directory on given
branch");
 
        if (!defined $hash && defined $file_name) {
@@ -5398,7 +5420,7 @@ sub git_history {
        my $paging_nav = '';
        if ($page > 0) {
                $paging_nav .=
-                       $cgi->a({-href => href(action=>"history",
hash=>$hash, hash_base=>$hash_base,
+                       $cgi->a({-href => href(action=>"$history_call",
hash=>$hash, hash_base=>$hash_base,
                                               file_name=>$file_name)},
                                "first");
                $paging_nav .= " &sdot; " .
@@ -5429,6 +5451,11 @@ sub git_history {
        git_footer_html();
 }
 
+sub git_history_follow {
+       git_history('--follow');
+}
+
+
 sub git_search {
        gitweb_check_feature('search') or die_error(403, "Search is
disabled");
        if (!defined $searchtext) {
@@ -5469,7 +5496,7 @@ sub git_search {
                        $greptype = "--committer=";
                }
                $greptype .= $searchtext;
-               my @commitlist = parse_commits($hash, 101, (100 *
$page), undef,
+               my @commitlist = parse_commits($hash, 101, (100 *
$page), undef, undef,
                                               $greptype,
'--regexp-ignore-case',
                                               $search_use_regexp ?
'--extended-regexp' : '--fixed-strings');
 
@@ -5737,7 +5764,7 @@ sub git_feed {
 
        # log/feed of current (HEAD) branch, log of given branch,
history of file/directory
        my $head = $hash || 'HEAD';
-       my @commitlist = parse_commits($head, 150, 0, $file_name);
+       my @commitlist = parse_commits($head, 150, 0, undef,
$file_name);
 
        my %latest_commit;
        my %latest_date;
---

Guy.
____________________________________________________
Guy Blucher
Defence Science and Technology Organisation
AUSTRALIA

IMPORTANT : This email remains the property of the Australian Defence
Organisation and is subject to the jurisdiction of section 70 of the
Crimes Act 1914.  If you have received this email in error, you are
requested to contact the sender and delete the email.
Next: Moore, Robert
Message 1 of 3 in “[RFC] gitweb: add 'historyfollow' view that follows renames”
  1. Blucher, GuyOct 27, 2008
  2. Moore, RobertOct 30, 2008
  3. Jakub NarebskiOct 31, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.