{"thread":{"id":"8254","subject":"[PATCH 1/5] gitweb: Support comparing blobs with different names","startedAt":"2007-05-20T20:23:28Z","lastAt":"2007-08-26T17:21:29Z","messageCount":8,"participants":["Martin Koegler","Petr Baudis"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"42777","messageId":"11796926121641-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"8254","inReplyTo":null,"subject":"[PATCH 1/5] gitweb: Support comparing blobs with different names","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-05-20T20:23:28Z","receivedAt":"2007-05-20T20:23:28Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"Currently, blobdiff can only compare blobs with different file\nnames, if no hb/hpb parameters are present.\n\nThis patch adds support for comparing two blobs specified by any\ncombination of hb/f/h and hpb/fp/hp.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n gitweb/gitweb.perl |  148 +++++++++++++++++++---------------------------------\n 1 files changed, 53 insertions(+), 95 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 5c7011a..63ed14f 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -4238,109 +4238,66 @@ sub git_blobdiff {\n \tmy $fd;\n \tmy @difftree;\n \tmy %diffinfo;\n-\tmy $expires;\n-\n-\t# preparing $fd and %diffinfo for git_patchset_body\n-\t# new style URI\n-\tif (defined $hash_base && defined $hash_parent_base) {\n-\t\tif (defined $file_name) {\n-\t\t\t# read raw output\n-\t\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t\t$hash_parent_base, $hash_base,\n-\t\t\t\t\"--\", (defined $file_parent ? $file_parent : ()), $file_name\n-\t\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n-\t\t\t@difftree = map { chomp; $_ } <$fd>;\n-\t\t\tclose $fd\n-\t\t\t\tor die_error(undef, \"Reading git-diff-tree failed\");\n-\t\t\t@difftree\n-\t\t\t\tor die_error('404 Not Found', \"Blob diff not found\");\n-\n-\t\t} elsif (defined $hash &&\n-\t\t         $hash =~ /[0-9a-fA-F]{40}/) {\n-\t\t\t# try to find filename from $hash\n-\n-\t\t\t# read filtered raw output\n-\t\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t\t$hash_parent_base, $hash_base, \"--\"\n-\t\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n-\t\t\t@difftree =\n-\t\t\t\t# ':100644 100644 03b21826... 3b93d5e7... M\tls-files.c'\n-\t\t\t\t# $hash == to_id\n-\t\t\t\tgrep { /^:[0-7]{6} [0-7]{6} [0-9a-fA-F]{40} $hash/ }\n-\t\t\t\tmap { chomp; $_ } <$fd>;\n-\t\t\tclose $fd\n-\t\t\t\tor die_error(undef, \"Reading git-diff-tree failed\");\n-\t\t\t@difftree\n-\t\t\t\tor die_error('404 Not Found', \"Blob diff not found\");\n+\tmy $expires = '+1d';\n+\tmy ($from, $to);\n \n-\t\t} else {\n-\t\t\tdie_error('404 Not Found', \"Missing one of the blob diff parameters\");\n-\t\t}\n-\n-\t\tif (@difftree > 1) {\n-\t\t\tdie_error('404 Not Found', \"Ambiguous blob diff specification\");\n-\t\t}\n+\t$file_parent ||= $file_name;\n \n-\t\t%diffinfo = parse_difftree_raw_line($difftree[0]);\n-\t\t$file_parent ||= $diffinfo{'from_file'} || $file_name || $diffinfo{'file'};\n-\t\t$file_name   ||= $diffinfo{'to_file'}   || $diffinfo{'file'};\n-\n-\t\t$hash_parent ||= $diffinfo{'from_id'};\n-\t\t$hash        ||= $diffinfo{'to_id'};\n-\n-\t\t# non-textual hash id's can be cached\n-\t\tif ($hash_base =~ m/^[0-9a-fA-F]{40}$/ &&\n-\t\t    $hash_parent_base =~ m/^[0-9a-fA-F]{40}$/) {\n-\t\t\t$expires = '+1d';\n-\t\t}\n+\t# non-textual hash id's can be cached\n+\tif (defined $hash && $hash !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent && $hash_parent !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_base && $hash_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent_base && $hash_parent_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t}\n+\n+\t# if hash parameter is missing, read it from the commit.\n+\tif (defined $hash_base && defined $file_name && !defined $hash) {\n+\t\t$hash = git_get_hash_by_path($hash_base, $file_name);\n+\t}\n \n-\t\t# open patch output\n-\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t'-p', ($format eq 'html' ? \"--full-index\" : ()),\n-\t\t\t$hash_parent_base, $hash_base,\n-\t\t\t\"--\", (defined $file_parent ? $file_parent : ()), $file_name\n-\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\tif (defined $hash_parent_base && defined $file_parent && !defined $hash_parent) {\n+\t    $hash_parent = git_get_hash_by_path($hash_parent_base, $file_parent);\n+\t}\n+\t\n+\tif (!defined $hash || ! defined $hash_parent) {\n+\t\tdie_error('404 Not Found', \"Missing one of the blob diff parameters\");\n \t}\n \n-\t# old/legacy style URI\n-\tif (!%diffinfo && # if new style URI failed\n-\t    defined $hash && defined $hash_parent) {\n-\t\t# fake git-diff-tree raw output\n-\t\t$diffinfo{'from_mode'} = $diffinfo{'to_mode'} = \"blob\";\n-\t\t$diffinfo{'from_id'} = $hash_parent;\n-\t\t$diffinfo{'to_id'}   = $hash;\n-\t\tif (defined $file_name) {\n-\t\t\tif (defined $file_parent) {\n-\t\t\t\t$diffinfo{'status'} = '2';\n-\t\t\t\t$diffinfo{'from_file'} = $file_parent;\n-\t\t\t\t$diffinfo{'to_file'}   = $file_name;\n-\t\t\t} else { # assume not renamed\n-\t\t\t\t$diffinfo{'status'} = '1';\n-\t\t\t\t$diffinfo{'from_file'} = $file_name;\n-\t\t\t\t$diffinfo{'to_file'}   = $file_name;\n-\t\t\t}\n-\t\t} else { # no filename given\n-\t\t\t$diffinfo{'status'} = '2';\n-\t\t\t$diffinfo{'from_file'} = $hash_parent;\n-\t\t\t$diffinfo{'to_file'}   = $hash;\n-\t\t}\n+\tif (defined $hash_base && defined $file_name) {\n+\t\t$to = $hash_base . ':' . $file_name;\n+\t} else {\n+\t\t$to = $hash;\n+\t}\n \n-\t\t# non-textual hash id's can be cached\n-\t\tif ($hash =~ m/^[0-9a-fA-F]{40}$/ &&\n-\t\t    $hash_parent =~ m/^[0-9a-fA-F]{40}$/) {\n-\t\t\t$expires = '+1d';\n-\t\t}\n+\tif (defined $hash_parent_base && defined $file_parent) {\n+\t\t$from = $hash_parent_base . ':' . $file_parent;\n+\t} else {\n+\t\t$from = $hash_parent;\n+\t}\n \n-\t\t# open patch output\n-\t\topen $fd, \"-|\", git_cmd(), \"diff\", @diff_opts,\n-\t\t\t'-p', ($format eq 'html' ? \"--full-index\" : ()),\n-\t\t\t$hash_parent, $hash, \"--\"\n-\t\t\tor die_error(undef, \"Open git-diff failed\");\n-\t} else  {\n-\t\tdie_error('404 Not Found', \"Missing one of the blob diff parameters\")\n-\t\t\tunless %diffinfo;\n+\t# fake git-diff-tree raw output\n+\t$diffinfo{'from_mode'} = $diffinfo{'to_mode'} = \"blob\";\n+\t$diffinfo{'from_id'} = $hash_parent;\n+\t$diffinfo{'to_id'}   = $hash;\n+\tif (defined $file_name) {\n+\t\t$diffinfo{'status'} = '2';\n+\t\t$diffinfo{'from_file'} = $file_parent;\n+\t\t$diffinfo{'to_file'}   = $file_name;\n+\t} else { # no filename given\n+\t\t$diffinfo{'status'} = '2';\n+\t\t$diffinfo{'from_file'} = $hash_parent;\n+\t\t$diffinfo{'to_file'}   = $hash;\n \t}\n \n+\t# open patch output\n+\topen $fd, \"-|\", git_cmd(), \"diff\", @diff_opts, '-p', \"--full-index\",\n+\t($format eq 'html' ? \"--raw\" : ()), $from, $to, \"--\"\n+\t\tor die_error(undef, \"Open git-diff failed\");\n+\n \t# header\n \tif ($format eq 'html') {\n \t\tmy $formats_nav =\n@@ -4364,11 +4321,12 @@ sub git_blobdiff {\n \t\t}\n \n \t} elsif ($format eq 'plain') {\n+\t\tmy $patch_file_name = $file_name || $hash;\n \t\tprint $cgi->header(\n \t\t\t-type => 'text/plain',\n \t\t\t-charset => 'utf-8',\n \t\t\t-expires => $expires,\n-\t\t\t-content_disposition => 'inline; filename=\"' . \"$file_name\" . '.patch\"');\n+\t\t\t-content_disposition => 'inline; filename=\"' . \"$patch_file_name\" . '.patch\"');\n \n \t\tprint \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n \n-- \n1.5.2.rc3.802.g4b4b7\n"},{"id":"42781","messageId":"11796926121315-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"8254","inReplyTo":"11796926121641-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 2/5] gitweb: support filename prefix in git_patchset_body/git_difftree_body","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-05-20T20:23:29Z","receivedAt":"2007-05-20T20:23:29Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"git_treediff supports comparing subdirectories. As the output of\ngit-difftree is missing the path to the compared directories,\nthe links in the output would be wrong.\n\nThe patch adds two new parameters to add the missing path prefix.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n gitweb/gitweb.perl |   72 +++++++++++++++++++++++++++++-----------------------\n 1 files changed, 40 insertions(+), 32 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 63ed14f..33aba86 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -2366,9 +2366,13 @@ sub from_ids_eq {\n \n \n sub git_difftree_body {\n-\tmy ($difftree, $hash, @parents) = @_;\n+\tmy ($difftree, $from_prefix, $to_prefix, $hash, @parents) = @_;\n \tmy ($parent) = $parents[0];\n \tmy ($have_blame) = gitweb_check_feature('blame');\n+\n+\t$from_prefix = !defined $from_prefix ? '' : $from_prefix.'/';\n+\t$to_prefix   = !defined $to_prefix   ? '' : $to_prefix . '/';\n+\n \tprint \"<div class=\\\"list_head\\\">\\n\";\n \tif ($#{$difftree} > 10) {\n \t\tprint(($#{$difftree} + 1) . \" files changed:\\n\");\n@@ -2405,7 +2409,7 @@ sub git_difftree_body {\n \t\t\t\t# file exists in the result (child) commit\n \t\t\t\tprint \"<td>\" .\n \t\t\t\t      $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t\t                             file_name=>$diff->{'to_file'},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash),\n \t\t\t\t              -class => \"list\"}, esc_path($diff->{'to_file'})) .\n \t\t\t\t      \"</td>\\n\";\n@@ -2442,7 +2446,7 @@ sub git_difftree_body {\n \t\t\t\t\t      $cgi->a({-href => href(action=>\"blob\",\n \t\t\t\t\t                             hash_base=>$hash,\n \t\t\t\t\t                             hash=>$from_hash,\n-\t\t\t\t\t                             file_name=>$from_path)},\n+\t\t\t\t\t                             file_name=>$from_prefix.$from_path)},\n \t\t\t\t\t              \"blob\" . ($i+1)) .\n \t\t\t\t\t      \" | </td>\\n\";\n \t\t\t\t} else {\n@@ -2456,8 +2460,8 @@ sub git_difftree_body {\n \t\t\t\t\t                             hash_parent=>$from_hash,\n \t\t\t\t\t                             hash_base=>$hash,\n \t\t\t\t\t                             hash_parent_base=>$hash_parent,\n-\t\t\t\t\t                             file_name=>$diff->{'to_file'},\n-\t\t\t\t\t                             file_parent=>$from_path)},\n+\t\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n+\t\t\t\t\t                             file_parent=>$from_prefix.$from_path)},\n \t\t\t\t\t              \"diff\" . ($i+1)) .\n \t\t\t\t\t      \" | </td>\\n\";\n \t\t\t\t}\n@@ -2467,14 +2471,14 @@ sub git_difftree_body {\n \t\t\tif ($not_deleted) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blob\",\n \t\t\t\t                             hash=>$diff->{'to_id'},\n-\t\t\t\t                             file_name=>$diff->{'to_file'},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash)},\n \t\t\t\t              \"blob\");\n \t\t\t\tprint \" | \" if ($has_history);\n \t\t\t}\n \t\t\tif ($has_history) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"history\",\n-\t\t\t\t                             file_name=>$diff->{'to_file'},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash)},\n \t\t\t\t              \"history\");\n \t\t\t}\n@@ -2508,7 +2512,7 @@ sub git_difftree_body {\n \t\t\t$mode_chng   .= \"]</span>\";\n \t\t\tprint \"<td>\";\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'}),\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chng</td>\\n\";\n@@ -2520,7 +2524,7 @@ sub git_difftree_body {\n \t\t\t\tprint \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'})},\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t              \"blob\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -2528,7 +2532,7 @@ sub git_difftree_body {\n \t\t\tmy $mode_chng = \"<span class=\\\"file_status deleted\\\">[deleted $from_file_type]</span>\";\n \t\t\tprint \"<td>\";\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'from_id'},\n-\t\t\t                             hash_base=>$parent, file_name=>$diff->{'file'}),\n+\t\t\t                             hash_base=>$parent, file_name=>$from_prefix.$diff->{'file'}),\n \t\t\t               -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chng</td>\\n\";\n@@ -2540,15 +2544,15 @@ sub git_difftree_body {\n \t\t\t\tprint \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'from_id'},\n-\t\t\t                             hash_base=>$parent, file_name=>$diff->{'file'})},\n+\t\t\t                             hash_base=>$parent, file_name=>$from_prefix.$diff->{'file'})},\n \t\t\t              \"blob\") . \" | \";\n \t\t\tif ($have_blame) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blame\", hash_base=>$parent,\n-\t\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t\t                             file_name=>$from_prefix.$diff->{'file'})},\n \t\t\t\t              \"blame\") . \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"history\", hash_base=>$parent,\n-\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t                             file_name=>$from_prefix.$diff->{'file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -2570,7 +2574,7 @@ sub git_difftree_body {\n \t\t\t}\n \t\t\tprint \"<td>\";\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'}),\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chnge</td>\\n\";\n@@ -2585,20 +2589,21 @@ sub git_difftree_body {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blobdiff\",\n \t\t\t\t                             hash=>$diff->{'to_id'}, hash_parent=>$diff->{'from_id'},\n \t\t\t\t                             hash_base=>$hash, hash_parent_base=>$parent,\n-\t\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'file'},\n+\t\t\t\t                             file_parent=>$from_prefix.$diff->{'file'})},\n \t\t\t\t              \"diff\") .\n \t\t\t\t      \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$hash, file_name=>$diff->{'file'})},\n+\t\t\t                             hash_base=>$hash, file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t               \"blob\") . \" | \";\n \t\t\tif ($have_blame) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blame\", hash_base=>$hash,\n-\t\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t\t              \"blame\") . \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"history\", hash_base=>$hash,\n-\t\t\t                             file_name=>$diff->{'file'})},\n+\t\t\t                             file_name=>$to_prefix.$diff->{'file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -2612,11 +2617,11 @@ sub git_difftree_body {\n \t\t\t}\n \t\t\tprint \"<td>\" .\n \t\t\t      $cgi->a({-href => href(action=>\"blob\", hash_base=>$hash,\n-\t\t\t                             hash=>$diff->{'to_id'}, file_name=>$diff->{'to_file'}),\n+\t\t\t                             hash=>$diff->{'to_id'}, file_name=>$to_prefix.$diff->{'to_file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'to_file'})) . \"</td>\\n\" .\n \t\t\t      \"<td><span class=\\\"file_status $nstatus\\\">[$nstatus from \" .\n \t\t\t      $cgi->a({-href => href(action=>\"blob\", hash_base=>$parent,\n-\t\t\t                             hash=>$diff->{'from_id'}, file_name=>$diff->{'from_file'}),\n+\t\t\t                             hash=>$diff->{'from_id'}, file_name=>$from_prefix.$diff->{'from_file'}),\n \t\t\t              -class => \"list\"}, esc_path($diff->{'from_file'})) .\n \t\t\t      \" with \" . (int $diff->{'similarity'}) . \"% similarity$mode_chng]</span></td>\\n\" .\n \t\t\t      \"<td class=\\\"link\\\">\";\n@@ -2630,20 +2635,20 @@ sub git_difftree_body {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blobdiff\",\n \t\t\t\t                             hash=>$diff->{'to_id'}, hash_parent=>$diff->{'from_id'},\n \t\t\t\t                             hash_base=>$hash, hash_parent_base=>$parent,\n-\t\t\t\t                             file_name=>$diff->{'to_file'}, file_parent=>$diff->{'from_file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'}, file_parent=>$from_prefix.$diff->{'from_file'})},\n \t\t\t\t              \"diff\") .\n \t\t\t\t      \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash=>$diff->{'to_id'},\n-\t\t\t                             hash_base=>$parent, file_name=>$diff->{'to_file'})},\n+\t\t\t                             hash_base=>$parent, file_name=>$to_prefix.$diff->{'to_file'})},\n \t\t\t              \"blob\") . \" | \";\n \t\t\tif ($have_blame) {\n \t\t\t\tprint $cgi->a({-href => href(action=>\"blame\", hash_base=>$hash,\n-\t\t\t\t                             file_name=>$diff->{'to_file'})},\n+\t\t\t\t                             file_name=>$to_prefix.$diff->{'to_file'})},\n \t\t\t\t              \"blame\") . \" | \";\n \t\t\t}\n \t\t\tprint $cgi->a({-href => href(action=>\"history\", hash_base=>$hash,\n-\t\t\t                            file_name=>$diff->{'to_file'})},\n+\t\t\t                            file_name=>$to_prefix.$diff->{'to_file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -2654,7 +2659,7 @@ sub git_difftree_body {\n }\n \n sub git_patchset_body {\n-\tmy ($fd, $difftree, $hash, @hash_parents) = @_;\n+\tmy ($fd, $difftree, $from_prefix, $to_prefix, $hash, @hash_parents) = @_;\n \tmy ($hash_parent) = $hash_parents[0];\n \n \tmy $patch_idx = 0;\n@@ -2663,6 +2668,9 @@ sub git_patchset_body {\n \tmy $diffinfo;\n \tmy (%from, %to);\n \n+\t$from_prefix = !defined $from_prefix ? '' : $from_prefix.'/';\n+\t$to_prefix   = !defined $to_prefix   ? '' : $to_prefix . '/';\n+\n \tprint \"<div class=\\\"patchset\\\">\\n\";\n \n \t# skip to first patch\n@@ -2733,7 +2741,7 @@ sub git_patchset_body {\n \t\t\t\t\t\t$from{'href'}[$i] = href(action=>\"blob\",\n \t\t\t\t\t\t                         hash_base=>$hash_parents[$i],\n \t\t\t\t\t\t                         hash=>$diffinfo->{'from_id'}[$i],\n-\t\t\t\t\t\t                         file_name=>$from{'file'}[$i]);\n+\t\t\t\t\t\t                         file_name=>$from_prefix.$from{'file'}[$i]);\n \t\t\t\t\t} else {\n \t\t\t\t\t\t$from{'href'}[$i] = undef;\n \t\t\t\t\t}\n@@ -2743,7 +2751,7 @@ sub git_patchset_body {\n \t\t\t\tif ($diffinfo->{'status'} ne \"A\") { # not new (added) file\n \t\t\t\t\t$from{'href'} = href(action=>\"blob\", hash_base=>$hash_parent,\n \t\t\t\t\t                     hash=>$diffinfo->{'from_id'},\n-\t\t\t\t\t                     file_name=>$from{'file'});\n+\t\t\t\t\t                     file_name=>$from_prefix.$from{'file'});\n \t\t\t\t} else {\n \t\t\t\t\tdelete $from{'href'};\n \t\t\t\t}\n@@ -2753,7 +2761,7 @@ sub git_patchset_body {\n \t\t\tif ($diffinfo->{'to_id'} ne ('0' x 40)) { # file exists in result\n \t\t\t\t$to{'href'} = href(action=>\"blob\", hash_base=>$hash,\n \t\t\t\t                   hash=>$diffinfo->{'to_id'},\n-\t\t\t\t                   file_name=>$to{'file'});\n+\t\t\t\t                   file_name=>$to_prefix.$to{'file'});\n \t\t\t} else {\n \t\t\t\tdelete $to{'href'};\n \t\t\t}\n@@ -4180,7 +4188,7 @@ sub git_commit {\n \tgit_print_log($co{'comment'});\n \tprint \"</div>\\n\";\n \n-\tgit_difftree_body(\\@difftree, $hash, @$parents);\n+\tgit_difftree_body(\\@difftree, undef, undef, $hash, @$parents);\n \n \tgit_footer_html();\n }\n@@ -4338,7 +4346,7 @@ sub git_blobdiff {\n \tif ($format eq 'html') {\n \t\tprint \"<div class=\\\"page_body\\\">\\n\";\n \n-\t\tgit_patchset_body($fd, [ \\%diffinfo ], $hash_base, $hash_parent_base);\n+\t\tgit_patchset_body($fd, [ \\%diffinfo ], undef, undef, $hash_base, $hash_parent_base);\n \t\tclose $fd;\n \n \t\tprint \"</div>\\n\"; # class=\"page_body\"\n@@ -4495,10 +4503,10 @@ TEXT\n \n \t# write patch\n \tif ($format eq 'html') {\n-\t\tgit_difftree_body(\\@difftree, $hash, $hash_parent || @{$co{'parents'}});\n+\t\tgit_difftree_body(\\@difftree, undef, undef, $hash, $hash_parent || @{$co{'parents'}});\n \t\tprint \"<br/>\\n\";\n \n-\t\tgit_patchset_body($fd, \\@difftree, $hash, $hash_parent || @{$co{'parents'}});\n+\t\tgit_patchset_body($fd, \\@difftree, undef, undef, $hash, $hash_parent || @{$co{'parents'}});\n \t\tclose $fd;\n \t\tprint \"</div>\\n\"; # class=\"page_body\"\n \t\tgit_footer_html();\n-- \n1.5.2.rc3.802.g4b4b7\n"},{"id":"42779","messageId":"11796926121911-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"8254","inReplyTo":"11796926121315-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 3/5] gitweb: Add treediff view","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-05-20T20:23:30Z","receivedAt":"2007-05-20T20:23:30Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"git_treediff supports comparing different trees. A tree can be specified\neither as hash or as base hash and filename.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n gitweb/gitweb.perl |  116 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 116 insertions(+), 0 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 33aba86..d161c8b 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -480,6 +480,8 @@ my %actions = (\n \t\"tag\" => \\&git_tag,\n \t\"tags\" => \\&git_tags,\n \t\"tree\" => \\&git_tree,\n+\t\"treediff\" => \\&git_treediff,\n+\t\"treediff_plain\" => \\&git_treediff_plain,\n \t\"snapshot\" => \\&git_snapshot,\n \t\"object\" => \\&git_object,\n \t# those below don't need $project\n@@ -4523,6 +4525,120 @@ sub git_commitdiff_plain {\n \tgit_commitdiff('plain');\n }\n \n+sub git_treediff {\n+\tmy $format = shift || 'html';\n+\tmy $expires = '+1d';\n+\n+\t# non-textual hash id's can be cached\n+\tif (defined $hash && $hash !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent && $hash_parent !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_base && $hash_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t} elsif (defined $hash_parent_base && $hash_parent_base !~ m/^[0-9a-fA-F]{40}$/) {\n+\t\t$expires = undef;\n+\t}\n+\n+\t# we need to prepare $formats_nav before any parameter munging\n+\tmy $formats_nav;\n+\tif ($format eq 'html') {\n+\t\t$formats_nav =\n+\t\t\t$cgi->a({-href => href(action=>\"treediff_plain\",\n+\t\t\t\t\t\t\t\t   hash=>$hash, hash_parent=>$hash_parent,\n+\t\t\t\t\t\t\t\t   hash_base=>$hash_base, hash_parent_base=>$hash_parent_base,\n+\t\t\t\t\t\t\t\t   file_name=>$file_name, file_parent=>$file_parent)},\n+\t\t\t\t\t\"raw\");\n+\t}\n+\n+\tif (!defined $hash) {\n+\t\tif (!defined $hash_base) {\n+\t\t\tdie_error(undef,'tree parameter missing');\n+\t\t}\n+\t\t$hash = $hash_base;\n+\t\t$hash .= \":\".$file_name if (defined $file_name);\n+\t}\n+\t\n+\tif (!defined $hash_parent) {\n+\t\tif (!defined $hash_parent_base) {\n+\t\t\tdie_error(undef,'tree parameter missing');\n+\t\t}\n+\t\t$hash_parent = $hash_parent_base;\n+\t\t$hash_parent .= \":\".$file_parent if (defined $file_parent);\n+\t}\n+\n+\t# read treediff\n+\tmy $fd;\n+\tmy @difftree;\n+\tif ($format eq 'html') {\n+\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n+\t\t\"--no-commit-id\", \"--patch-with-raw\", \"--full-index\",\n+\t\t$hash_parent, $hash, \"--\"\n+\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\t\t\n+\t\twhile (my $line = <$fd>) {\n+\t\t\tchomp $line;\n+\t\t\t# empty line ends raw part of diff-tree output\n+\t\t\tlast unless $line;\n+\t\t\tpush @difftree, $line;\n+\t\t}\n+\t\t\n+\t} elsif ($format eq 'plain') {\n+\t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n+\t\t'-p', $hash_parent, $hash, \"--\"\n+\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\t\t\n+\t} else {\n+\t\tdie_error(undef, \"Unknown treediff format\");\n+\t}\n+\n+\t# write header\n+\tif ($format eq 'html') {\n+\t\tgit_header_html(undef, $expires);\n+\t\tif (defined $hash_base && (my %co = parse_commit($hash_base))) {\n+\t\t\tgit_print_page_nav('','', $hash_base,$co{'tree'},$hash_base, $formats_nav);\n+\t\t\tgit_print_header_div('commit', esc_html($co{'title'}), $hash_base);\n+\t\t} else {\n+\t\t\tprint \"<div class=\\\"page_nav\\\"><br/>$formats_nav<br/></div>\\n\";\n+\t\t\tprint \"<div class=\\\"title\\\">$hash vs $hash_parent</div>\\n\";\n+\t\t}\n+\t\tprint \"<div class=\\\"page_body\\\">\\n\";\n+\t\t\n+\t} elsif ($format eq 'plain') {\n+\t\tmy $filename = basename($project) . \"-$hash-$hash_parent.patch\";\n+\t\t\n+\t\tprint $cgi->header(\n+\t\t\t\t\t\t   -type => 'text/plain',\n+\t\t\t\t\t\t   -charset => 'utf-8',\n+\t\t\t\t\t\t   -expires => $expires,\n+\t\t\t\t\t\t   -content_disposition => 'inline; filename=\"' . \"$filename\" . '\"');\n+\t\t\n+\t\tprint \"X-Git-Url: \" . $cgi->self_url() . \"\\n\\n\";\n+\t\tprint \"---\\n\\n\";\n+\t}\n+\t\n+\t# write patch\n+\tif ($format eq 'html') {\n+\t\tgit_difftree_body(\\@difftree, $file_parent, $file_name, $hash_base, $hash_parent_base);\n+\t\tprint \"<br/>\\n\";\n+\n+\t\tgit_patchset_body($fd, \\@difftree, $file_parent, $file_name, $hash_base, $hash_parent_base);\n+\t\tclose $fd;\n+\t\tprint \"</div>\\n\"; # class=\"page_body\"\n+\t\tgit_footer_html();\n+\n+\t} elsif ($format eq 'plain') {\n+\t\tlocal $/ = undef;\n+\t\tprint <$fd>;\n+\t\tclose $fd\n+\t\t\tor print \"Reading git-diff-tree failed\\n\";\n+\t}\n+}\n+\n+sub git_treediff_plain {\n+\tgit_treediff('plain');\n+}\n+\n sub git_history {\n \tif (!defined $hash_base) {\n \t\t$hash_base = git_get_head_hash($project);\n-- \n1.5.2.rc3.802.g4b4b7\n"},{"id":"42778","messageId":"11796926122089-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"8254","inReplyTo":"11796926121911-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 4/5] gitweb: Selecting diffs in JavaScript","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-05-20T20:23:31Z","receivedAt":"2007-05-20T20:23:31Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"The adds support for selecting arbitrary diffs, if the client browser supports\nJavaScript.\n\nSigned-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n---\n Makefile           |    6 +-\n git-instaweb.sh    |    7 ++\n gitweb/gitweb.js   |  298 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n gitweb/gitweb.perl |    6 +\n 4 files changed, 316 insertions(+), 1 deletions(-)\n create mode 100644 gitweb/gitweb.js\n\ndiff --git a/Makefile b/Makefile\nindex 521c003..2d04ef9 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -167,6 +167,7 @@ GITWEB_HOMETEXT = indextext.html\n GITWEB_CSS = gitweb.css\n GITWEB_LOGO = git-logo.png\n GITWEB_FAVICON = git-favicon.png\n+GITWEB_JS = gitweb.js\n GITWEB_SITE_HEADER =\n GITWEB_SITE_FOOTER =\n \n@@ -811,13 +812,14 @@ gitweb/gitweb.cgi: gitweb/gitweb.perl\n \t    -e 's|++GITWEB_CSS++|$(GITWEB_CSS)|g' \\\n \t    -e 's|++GITWEB_LOGO++|$(GITWEB_LOGO)|g' \\\n \t    -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \\\n+\t    -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \\\n \t    -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \\\n \t    -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \\\n \t    $< >$@+ && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\n \n-git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css\n+git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css gitweb/gitweb.js\n \t$(QUIET_GEN)rm -f $@ $@+ && \\\n \tsed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \\\n \t    -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \\\n@@ -826,6 +828,8 @@ git-instaweb: git-instaweb.sh gitweb/gitweb.cgi gitweb/gitweb.css\n \t    -e '/@@GITWEB_CGI@@/d' \\\n \t    -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \\\n \t    -e '/@@GITWEB_CSS@@/d' \\\n+\t    -e '/@@GITWEB_JS@@/r gitweb/gitweb.js' \\\n+\t    -e '/@@GITWEB_JS@@/d' \\\n \t    $@.sh > $@+ && \\\n \tchmod +x $@+ && \\\n \tmv $@+ $@\ndiff --git a/git-instaweb.sh b/git-instaweb.sh\nindex cbc7418..8cb62f1 100755\n--- a/git-instaweb.sh\n+++ b/git-instaweb.sh\n@@ -233,8 +233,15 @@ gitweb_css () {\n EOFGITWEB\n }\n \n+gitweb_js () {\n+\tcat > \"$1\" <<\\EOFGITWEB\n+@@GITWEB_JS@@\n+EOFGITWEB\n+}\n+\n gitweb_cgi $GIT_DIR/gitweb/gitweb.cgi\n gitweb_css $GIT_DIR/gitweb/gitweb.css\n+gitweb_js $GIT_DIR/gitweb/gitweb.js\n \n case \"$httpd\" in\n *lighttpd*)\ndiff --git a/gitweb/gitweb.js b/gitweb/gitweb.js\nnew file mode 100644\nindex 0000000..cacab5a\n--- /dev/null\n+++ b/gitweb/gitweb.js\n@@ -0,0 +1,298 @@\n+/* Javascript functions for gitweb\n+\n+  (C) 2007 Martin Koegler <mkoegler@auto.tuwien.ac.at>\n+\n+  This file is licensed under the GPL v2, or (at your option) any later version.\n+*/\n+\n+function getCookie (name)\n+{\n+  var name = name + \"=\";\n+  var c = document.cookie;\n+  var p = c.indexOf (name);\n+  if (p == -1)\n+    return null;\n+  c = c.substr (p + name.length, c.length);\n+  p = c.indexOf (\";\");\n+  if (p == -1)\n+    return c;\n+  else\n+    return c.substr (0, p);\n+}\n+\n+function insertAfter (elem, node)\n+{\n+  if (node.nextSibling)\n+    node.parentNode.insertBefore (elem, node.nextSibling);\n+  else\n+    node.parentNode.appendChild (elem);\n+}\n+\n+function createLink (href, linktext)\n+{\n+  var l = document.createElement (\"a\");\n+  l.appendChild (document.createTextNode (linktext));\n+  l.href = href;\n+  return l;\n+}\n+\n+function createLinkGroup (href1, basetxt, href2, difftxt)\n+{\n+  var l = document.createElement (\"span\");\n+  l.appendChild (document.createTextNode (\" (\"));\n+  l.appendChild (createLink (href1, basetxt));\n+  l.appendChild (document.createTextNode (\" | \"));\n+  l.appendChild (createLink (href2, difftxt));\n+  l.appendChild (document.createTextNode (\") \"));\n+  return l;\n+}\n+\n+function GitRef ()\n+{\n+  this.t = null;\n+  this.h = null;\n+  this.hb = null;\n+  this.f = null;\n+  this.p = null;\n+  this.ToRef = ToRef;\n+}\n+\n+function ToRef ()\n+{\n+  var parts = new Array ();\n+  if (this.f)\n+    parts.push (\"f=\" + this.f);\n+  if (this.h)\n+    parts.push (\"h=\" + this.h);\n+  if (this.hb)\n+    parts.push (\"hb=\" + this.hb);\n+  if (this.t)\n+    parts.push (\"t=\" + this.t);\n+  if (this.p)\n+    parts.push (\"p=\" + this.p);\n+  return parts.join (\"@\");\n+}\n+\n+function splitGitRef (ref)\n+{\n+  var parts = ref.split (\"@\");\n+  var res = new GitRef ();\n+  var i;\n+  for (i = 0; i < parts.length; i++)\n+    {\n+      var p = parts[i].split (\"=\");\n+      res[p[0]] = p[1];\n+    }\n+  return res;\n+}\n+\n+function GitURL (base)\n+{\n+  this.base = base;\n+  this.p = null;\n+  this.a = null;\n+  this.f = null;\n+  this.fp = null;\n+  this.h = null;\n+  this.hp = null;\n+  this.hb = null;\n+  this.hpb = null;\n+  this.pg = null;\n+  this.o = null;\n+  this.s = null;\n+  this.st = null;\n+  this.ToURL = ToURL;\n+  this.ToRef = UrlToRef;\n+  this.ToDUrl = ToDUrl;\n+}\n+\n+function ToURL ()\n+{\n+  var parts = new Array ();\n+  if (this.p)\n+    parts.push (\"p=\" + this.p);\n+  if (this.a)\n+    parts.push (\"a=\" + this.a);\n+  if (this.f)\n+    parts.push (\"f=\" + this.f);\n+  if (this.fp)\n+    parts.push (\"fp=\" + this.fp);\n+  if (this.h)\n+    parts.push (\"h=\" + this.h);\n+  if (this.hp)\n+    parts.push (\"hp=\" + this.hp);\n+  if (this.hb)\n+    parts.push (\"hb=\" + this.hb);\n+  if (this.hpb)\n+    parts.push (\"hpb=\" + this.hpb);\n+  if (this.o)\n+    parts.push (\"o=\" + this.o);\n+  if (this.s)\n+    parts.push (\"s=\" + this.s);\n+  if (this.st)\n+    parts.push (\"st=\" + this.st);\n+  return this.base + \"?\" + parts.join (\";\");\n+}\n+\n+function UrlToRef (type)\n+{\n+  var res = new GitRef;\n+  res.f = this.f;\n+  res.h = this.h;\n+  res.hb = this.hb;\n+  res.t = type;\n+  res.p = this.p;\n+  return res.ToRef ();\n+}\n+\n+function ToDUrl (type)\n+{\n+  var res = new GitURL (this.base);\n+  res.f = this.f;\n+  res.h = this.h;\n+  res.hb = this.hb;\n+  res.p = this.p;\n+  res.a = type;\n+  return res.ToURL ();\n+}\n+\n+function splitGitURL (url)\n+{\n+  var Urls = url.split (\"?\");\n+  var res = new GitURL (Urls[0]);\n+  if (Urls.length > 1)\n+    {\n+      var parts = Urls[1].split (\";\");\n+      var i;\n+      for (i = 0; i < parts.length; i++)\n+\t{\n+\t  var p = parts[i].split (\"=\");\n+\t  res[p[0]] = p[1];\n+\t}\n+    }\n+  return res;\n+}\n+\n+function base (ref)\n+{\n+  document.cookie = \"basename=\" + ref;\n+}\n+\n+function diff (url)\n+{\n+  var c = getCookie (\"basename\");\n+  if (!c)\n+    {\n+      alert (\"no diff base selected\");\n+      return;\n+    }\n+  c = splitGitRef (c);\n+  url = splitGitURL (url);\n+\n+  if (c.p != url.p)\n+    {\n+      alert (\"base object in an other repository\");\n+      return;\n+    }\n+\n+  if (c.t == 'commit' && url.a == 'commit')\n+    {\n+      url.a = 'commitdiff';\n+      if (!c.h || !url.h)\n+\t{\n+\t  alert (\"commit diff not possible\");\n+\t  return;\n+\t}\n+      url.hb = null;\n+      url.f = null;\n+      url.hp = c.h;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'blob' && url.a == 'blob')\n+    {\n+      url.a = 'blobdiff';\n+      url.hp = c.h;\n+      url.hpb = c.hb;\n+      url.fp = c.f;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'tree' && url.a == 'tree')\n+    {\n+      url.a = 'treediff';\n+      url.hpb = c.hb;\n+      url.hp = c.h;\n+      url.fp = c.f;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'commit' && url.a == 'tree')\n+    {\n+      url.a = 'treediff';\n+      url.hpb = c.h;\n+      url.hp = null;\n+      url.fp = null;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  if (c.t == 'tree' && url.a == 'commit')\n+    {\n+      url.a = 'treediff';\n+      url.hpb = c.hb;\n+      url.hp = c.h;\n+      url.fp = c.f;\n+      url.hb = url.h;\n+      url.h = null;\n+      document.location.href = url.ToURL ();\n+      return;\n+    }\n+  alert (\"diff not possible\");\n+}\n+\n+function GitAddLinks ()\n+{\n+  var links = document.getElementsByTagName (\"a\");\n+  var i;\n+\n+  for (i = 0; i < links.length; i++)\n+    {\n+      var link = links[i];\n+      var url = splitGitURL (link.href);\n+      if (link.innerHTML == 'commit' || link.innerHTML == 'tag')\n+\t{\n+\t  if (!url.h)\n+\t    continue;\n+\t  var l =\n+\t    createLinkGroup (\"javascript:base('\" + url.ToRef ('commit') +\n+\t\t\t     \"')\", \"base\",\n+\t\t\t     \"javascript:diff('\" + url.ToDUrl ('commit') +\n+\t\t\t     \"')\", \"diff\");\n+\t  insertAfter (l, link);\n+\t}\n+      if (link.innerHTML == 'blob')\n+\t{\n+\t  if (!url.h && !(url.hb && url.f))\n+\t    continue;\n+\t  var l =\n+\t    createLinkGroup (\"javascript:base('\" + url.ToRef ('blob') + \"')\",\n+\t\t\t     \"base\",\n+\t\t\t     \"javascript:diff('\" + url.ToDUrl ('blob') + \"')\",\n+\t\t\t     \"diff\");\n+\t  insertAfter (l, link);\n+\t}\n+      if (link.innerHTML == 'tree')\n+\t{\n+\t  if (!url.h && !(url.hb && url.f))\n+\t    continue;\n+\t  var l =\n+\t    createLinkGroup (\"javascript:base('\" + url.ToRef ('tree') + \"')\",\n+\t\t\t     \"base\",\n+\t\t\t     \"javascript:diff('\" + url.ToDUrl ('tree') + \"')\",\n+\t\t\t     \"diff\");\n+\t  insertAfter (l, link);\n+\t}\n+    }\n+}\n+\n+window.onload = GitAddLinks;\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex d161c8b..f59a4b5 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -61,6 +61,8 @@ our $stylesheet = undef;\n our $logo = \"++GITWEB_LOGO++\";\n # URI of GIT favicon, assumed to be image/png type\n our $favicon = \"++GITWEB_FAVICON++\";\n+# URI of gitweb.js\n+our $gitwebjs = \"++GITWEB_JS++\";\n \n # URI and label (title) of GIT logo link\n #our $logo_url = \"http://www.kernel.org/pub/software/scm/git/docs/\";\n@@ -1909,6 +1911,10 @@ EOF\n \t\tprint qq(<link rel=\"shortcut icon\" href=\"$favicon\" type=\"image/png\"/>\\n);\n \t}\n \n+\tif (defined $gitwebjs) {\n+\t\tprint qq(<script src=\"$gitwebjs\" type=\"text/javascript\"></script>\\n);\n+\t}\n+\n \tprint \"</head>\\n\" .\n \t      \"<body>\\n\";\n \n-- \n1.5.2.rc3.802.g4b4b7\n"},{"id":"42780","messageId":"11796926121907-git-send-email-mkoegler@auto.tuwien.ac.at","threadId":"8254","inReplyTo":"11796926122089-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"[PATCH 5/5] gitweb: Incremental blame","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-05-20T20:23:32Z","receivedAt":"2007-05-20T20:23:32Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"Rewrite ontop of diff patches + some performance tuning.\n---\nThe first chunk is the new version of the link rewriting for git-blame.\nIt does not need the blamelink class.\n\nAs gitweb.js is included in each page (and I didn't wanted to add a second JavaScript file),\nI added the content of blame.js at the end of gitweb.js.\n\nI also tried some optimizations. In IceWeasel 2.0.0.3 (= FireFox), the blame of sha1_file.c\nneeds now 33 instead of 46 seconds on my computer.\n\nThe \"optimizations\" are not tested in other browsers. According to my experience,\nI expect that the incremental blame in IE will be slower then in Mozilla.\n\n gitweb/gitweb.js   |  181 ++++++++++++++++++++++++++++++++++++++++++++++++++++\n gitweb/gitweb.perl |   92 ++++++++++++++++++++++++---\n 2 files changed, 264 insertions(+), 9 deletions(-)\n\ndiff --git a/gitweb/gitweb.js b/gitweb/gitweb.js\nindex cacab5a..001fac6 100644\n--- a/gitweb/gitweb.js\n+++ b/gitweb/gitweb.js\n@@ -259,6 +259,11 @@ function GitAddLinks ()\n     {\n       var link = links[i];\n       var url = splitGitURL (link.href);\n+      if (url.a == \"blame\")\n+\t{\n+\t  url.a = \"blame_incremental\";\n+\t  link.href = url.ToURL();\n+\t}\n       if (link.innerHTML == 'commit' || link.innerHTML == 'tag')\n \t{\n \t  if (!url.h)\n@@ -296,3 +301,179 @@ function GitAddLinks ()\n }\n \n window.onload = GitAddLinks;\n+\n+// Blame Javascript functions\n+// Copyright (C) 2007, Fredrik Kuivinen <frekui@gmail.com>\n+// modifed by Martin Koegler <mkoegler@auto.tuwien.ac.at>\n+\n+function createRequestObject() {\n+\tvar ro;\n+\tif (window.XMLHttpRequest) {\n+\t\tro = new XMLHttpRequest();\n+\t} else {\n+\t\tro = new ActiveXObject(\"Microsoft.XMLHTTP\");\n+\t}\n+\treturn ro;\n+}\n+\n+var http;\n+var baseUrl;\n+\n+// 'commits' is an associative map. It maps SHA1s to Commit objects.\n+var commits = new Object();\n+\n+function Commit(sha1)\n+{\n+\tthis.sha1 = sha1;\n+}\n+\n+function zeroPad(n)\n+{\n+\tif (n < 10)\n+\t\treturn '0' + n;\n+\telse\n+\t\treturn n.toString();\n+}\n+\n+function handleLine(commit)\n+{\n+\t/* This is the structure of the HTML fragment we are working\n+\t   with:\n+\t   \n+\t   <tr id=\"l123\" class=\"light2\">\n+\t   <td class=\"sha1\" title=\"\">\n+\t   <a href=\"\"></a>\n+\t   </td>\n+\t   <td class=\"linenr\">\n+\t   <a class=\"linenr\" href=\"\">123</a>\n+\t   </td>\n+\t   <td class=\"pre\"># times (my ext3 doesn&#39;t).</td>\n+\t   </tr>\n+\t */\n+\tvar tr = document.getElementById('l'+commit.resline);\n+\tvar linkurl = baseUrl + ';a=blame_incremental;hb=' + commit.sha1\n+\t  + ';f=' + commit.filename + '#l' + commit.srcline;\n+\n+\tvar date = new Date();\n+\tdate.setTime(commit.authorTime * 1000);\n+\tvar dateStr = date.getUTCFullYear() + '-'\n+\t  + zeroPad(date.getUTCMonth()+1) + '-'\n+\t  + zeroPad(date.getUTCDate());\n+\tvar timeStr = zeroPad(date.getUTCHours()) + ':'\n+\t  + zeroPad(date.getUTCMinutes()) + ':'\n+\t  + zeroPad(date.getUTCSeconds());\n+\tvar title = commit.author + ', ' + dateStr + ' ' + timeStr;\n+\n+\tfor (var i = 0; i < commit.numlines; i++) {\n+\t\ttr.firstChild.title = title;\n+\t\tvar shaAnchor = tr.firstChild.firstChild;\n+\t\tif (i == 0) {\n+\t\t\tshaAnchor.href = baseUrl + ';a=commit;h=' + commit.sha1;\n+\t\t\tshaAnchor.innerHTML = commit.sha1.substr(0, 8);\n+\t\t} else {\n+\t\t  if (shaAnchor.innerHTML != '')\n+\t\t    shaAnchor.innerHTML = '';\n+\t\t}\n+\n+\t\ttr.firstChild.nextSibling.firstChild.href = linkurl;\n+\n+\t\ttr = tr.nextSibling;\n+\t\twhile (tr && tr.nodeType == 3)\n+\t\t  tr = tr.nextSibling;\n+\t}\n+}\n+\n+function fixColors()\n+{\n+\tvar colorClasses = ['light2', 'dark2'];\n+\tvar tr = document.getElementById('l1');\n+\tvar colorClass = 0;\n+\n+\twhile (tr) {\n+\t\tif (tr.firstChild.firstChild.innerHTML != '')\n+\t\t\tcolorClass = (colorClass+1)%2;\n+\n+\t\tif (tr.className != colorClasses[colorClass])\n+\t\t  tr.className = colorClasses[colorClass];\n+\t\ttr = tr.nextSibling;\n+\t\twhile (tr && tr.nodeType == 3)\n+\t\t  tr = tr.nextSibling;\n+\t}\n+}\n+\n+var prevDataLength = -1;\n+var nextLine = 0;\n+var inProgress = false;\n+\n+var curCommit = new Commit();\n+\n+function handleResponse() {\n+\tif (http.readyState != 4 && http.readyState != 3)\n+\t\treturn;\n+\n+\t// In konqueror http.responseText is sometimes null here...\n+\tif (http.responseText === null)\n+\t\treturn;\n+\n+\tif (inProgress)\n+\t\treturn;\n+\telse\n+\t\tinProgress = true;\n+\n+\twhile (prevDataLength != http.responseText.length) {\n+\t\tif (http.readyState == 4\n+\t\t    && prevDataLength == http.responseText.length) {\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tprevDataLength = http.responseText.length;\n+\t\tvar response = http.responseText.substring(nextLine);\n+\t\tvar lines = response.split('\\n');\n+\t\tnextLine = nextLine + response.lastIndexOf('\\n') + 1;\n+\t\tif (response[response.length-1] != '\\n') {\n+\t\t\tlines.pop();\n+\t\t}\n+\n+\t\tfor (var i = 0; i < lines.length; i++) {\n+\t\t\tvar split = lines[i].split(' ');\n+\t\t\tif (split.length == 4 && split[0].length == 40) {\n+\t\t\t\tvar sha1 = split[0];\n+\t\t\t\tvar c = commits[sha1];\n+\t\t\t\tif (!c) {\n+\t\t\t\t\tc = new Commit(sha1);\n+\t\t\t\t\tcommits[sha1] = c;\n+\t\t\t\t}\n+\n+\t\t\t\tc.srcline = split[1];\n+\t\t\t\tc.resline = split[2];\n+\t\t\t\tc.numlines = split[3];\n+\t\t\t\tcurCommit = c;\n+\t\t\t} else {\n+\t\t\t\tvar info = split[0];\n+\t\t\t\tvar data = lines[i].substr (info.length + 1);\n+\t\t\t\tif (info == 'filename') {\n+\t\t\t\t\tcurCommit.filename = data;\n+\t\t\t\t\thandleLine(curCommit);\n+\t\t\t\t} else if (info == 'author') {\n+\t\t\t\t\tcurCommit.author = data;\n+\t\t\t\t} else if (info == 'author-time') {\n+\t\t\t\t\tcurCommit.authorTime = parseInt(data);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (http.readyState == 4 && prevDataLength == http.responseText.length)\n+\t\tfixColors();\n+\n+\tinProgress = false;\n+}\n+\n+function startBlame(blamedataUrl, bUrl)\n+{\n+\tbaseUrl = bUrl;\n+\thttp = createRequestObject();\n+\thttp.open('get', blamedataUrl);\n+\thttp.onreadystatechange = handleResponse;\n+\thttp.send(null);\n+}\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex f59a4b5..45787a6 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -462,6 +462,8 @@ $git_dir = \"$projectroot/$project\" if $project;\n # dispatch\n my %actions = (\n \t\"blame\" => \\&git_blame2,\n+\t\"blame_incremental\" => \\&git_blame_incremental,\n+\t\"blame_data\" => \\&git_blame_data,\n \t\"blobdiff\" => \\&git_blobdiff,\n \t\"blobdiff_plain\" => \\&git_blobdiff_plain,\n \t\"blob\" => \\&git_blob,\n@@ -562,7 +564,7 @@ sub href(%) {\n \t\t\tpush @result, $symbol . \"=\" . esc_param($params{$name});\n \t\t}\n \t}\n-\t$href .= \"?\" . join(';', @result) if scalar @result;\n+\t$href .= \"?\" . join(';', @result) if $params{-partial_query} or scalar @result;\n \n \treturn $href;\n }\n@@ -3517,7 +3519,47 @@ sub git_tag {\n \tgit_footer_html();\n }\n \n-sub git_blame2 {\n+sub git_blame_data {\n+\tmy $fd;\n+\tmy $ftype;\n+\n+\tmy ($have_blame) = gitweb_check_feature('blame');\n+\tif (!$have_blame) {\n+\t\tdie_error('403 Permission denied', \"Permission denied\");\n+\t}\n+\tdie_error('404 Not Found', \"File name not defined\") if (!$file_name);\n+\t$hash_base ||= git_get_head_hash($project);\n+\tdie_error(undef, \"Couldn't find base commit\") unless ($hash_base);\n+\tmy %co = parse_commit($hash_base)\n+\t\tor die_error(undef, \"Reading commit failed\");\n+\tif (!defined $hash) {\n+\t\t$hash = git_get_hash_by_path($hash_base, $file_name, \"blob\")\n+\t\t\tor die_error(undef, \"Error looking up file\");\n+\t}\n+\t$ftype = git_get_type($hash);\n+\tif ($ftype !~ \"blob\") {\n+\t\tdie_error(\"400 Bad Request\", \"Object is not a blob\");\n+\t}\n+\topen ($fd, \"-|\", git_cmd(), \"blame\", '--incremental', $hash_base, '--',\n+\t      $file_name)\n+\t\tor die_error(undef, \"Open git-blame --incremental failed\");\n+\n+\tprint $cgi->header(-type=>\"text/plain\", -charset => 'utf-8',\n+\t                   -status=> \"200 OK\");\n+\n+\twhile(<$fd>) {\n+ \t  if (/^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/ or\n+\t     /^author-time |^author |^filename /) {\n+ \t    print;\n+\t  }\n+\t}\n+\n+\tclose $fd or print \"Reading blame data failed\\n\";\n+}\n+\n+sub git_blame_common {\n+\tmy ($type) = @_;\n+\n \tmy $fd;\n \tmy $ftype;\n \n@@ -3536,11 +3578,16 @@ sub git_blame2 {\n \t}\n \t$ftype = git_get_type($hash);\n \tif ($ftype !~ \"blob\") {\n-\t\tdie_error('400 Bad Request', \"Object is not a blob\");\n+\t\tdie_error(\"400 Bad Request\", \"Object is not a blob\");\n+\t}\n+\tif ($type eq 'incremental') {\n+\t\topen ($fd, \"-|\", git_cmd(), 'cat-file', 'blob', $hash)\n+\t\t\tor die_error(undef, \"Open git-cat-file failed\");\n+\t} else {\n+\t\topen ($fd, \"-|\", git_cmd(), 'blame', '-p', '--',\n+\t\t      $file_name, $hash_base)\n+\t\t\tor die_error(undef, \"Open git-blame failed\");\n \t}\n-\topen ($fd, \"-|\", git_cmd(), \"blame\", '-p', '--',\n-\t      $file_name, $hash_base)\n-\t\tor die_error(undef, \"Open git-blame failed\");\n \tgit_header_html();\n \tmy $formats_nav =\n \t\t$cgi->a({-href => href(action=>\"blob\", hash=>$hash, hash_base=>$hash_base, file_name=>$file_name)},\n@@ -3564,9 +3611,19 @@ sub git_blame2 {\n <tr><th>Commit</th><th>Line</th><th>Data</th></tr>\n HTML\n \tmy %metainfo = ();\n-\twhile (1) {\n-\t\t$_ = <$fd>;\n-\t\tlast unless defined $_;\n+\tmy $linenr = 0;\n+\twhile (<$fd>) {\n+\t\tchomp;\n+\t\tif ($type eq 'incremental') {\n+\t\t\t# Empty stage with just the file contents\n+\t\t\t$linenr += 1;\n+\t\t\tprint \"<tr id=\\\"l$linenr\\\" class=\\\"light2\\\">\";\n+\t\t\tprint '<td class=\"sha1\"><a href=\"\"></a></td>';\n+\t\t\tprint \"<td class=\\\"linenr\\\"><a class=\\\"linenr\\\" href=\\\"\\\">$linenr</a></td><td class=\\\"pre\\\">\" . esc_html($_) . \"</td>\\n\";\n+\t\t\tprint \"</tr>\\n\";\n+\t\t\tnext;\n+\t\t}\n+\n \t\tmy ($full_rev, $orig_lineno, $lineno, $group_size) =\n \t\t    /^([0-9a-f]{40}) (\\d+) (\\d+)(?: (\\d+))?$/;\n \t\tif (!exists $metainfo{$full_rev}) {\n@@ -3618,13 +3675,30 @@ HTML\n \t\tprint \"<td class=\\\"pre\\\">\" . esc_html($data) . \"</td>\\n\";\n \t\tprint \"</tr>\\n\";\n \t}\n+\n \tprint \"</table>\\n\";\n \tprint \"</div>\";\n \tclose $fd\n \t\tor print \"Reading blob failed\\n\";\n+\n+\tif ($type eq 'incremental') {\n+\t\tprint \"<script type=\\\"text/javascript\\\">\\n\";\n+\t\tprint \"startBlame(\\\"\" . href(action=>\"blame_data\", hash_base=>$hash_base, file_name=>$file_name) . \"\\\", \\\"\" .\n+\t\t  href(-partial_query=>1) . \"\\\");\\n\";\n+\t\tprint \"</script>\\n\";\n+\t}\n+\n \tgit_footer_html();\n }\n \n+sub git_blame_incremental {\n+\tgit_blame_common('incremental');\n+}\n+\n+sub git_blame2 {\n+\tgit_blame_common('oneshot');\n+}\n+\n sub git_blame {\n \tmy $fd;\n \n-- \n1.5.2.rc3.802.g4b4b7\n"},{"id":"51536","messageId":"20070826011742.GF1219@pasky.or.cz","threadId":"8254","inReplyTo":"11796926122089-git-send-email-mkoegler@auto.tuwien.ac.at","subject":"Re: [PATCH 4/5] gitweb: Selecting diffs in JavaScript","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2007-08-26T01:17:43Z","receivedAt":"2007-08-26T01:17:43Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Sun, May 20, 2007 at 10:23:31PM CEST, Martin Koegler wrote:\n> The adds support for selecting arbitrary diffs, if the client browser supports\n> JavaScript.\n> \n> Signed-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n\nJFYI, I've just enabled it on repo.or.cz experimentally. Please anyone\ntell me what you think.\n\n(Just click at almost any view in gitweb and marvel at the extra base\nand diff links smiling everywhere.)\n\nI'll dump my mind state here, horribly sleepy. Sorry for the\nincomprehensible rant. :-)\n\nOne thing for certain is that I would get rid of GitAddLinks and instead\nhave href() add the extra links there, by default display: none and\njavascript code making it show. Also, there are obvious UI bugs, like\ncommit and tree entries for commits having redundant base/diff links;\nand Firefox doesn't expand table cells properly for the additional\nlinks. None of these bugs is easily fixable I think.\n\nBut maybe it needs more general overhaul and the links added explicitly\nin the views, because it really makes sense to have only a single\nlinkpair per entry and it would be good to have this always at the same\nplace, and perhaps in a different color. Hmm. And it seems that it's\ngetting in the way, overally.\n\nHmm.\n\nWhat about having another item in the main action menu, 'diff'?\nBase/diff links are by default display: none but show up when you click\nat 'diff', in green. They will keep showing up until you click 'diff'\nagain. When you click 'base', both the selected base link and main\n'diff' link changes color to red.\n\n\nOh the naivity that I've already lost about that someone might make a\npatch while I'm sleeping... ;-)\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nEver try. Ever fail. No matter. // Try again. Fail again. Fail better.\n\t\t-- Samuel Beckett\n"},{"id":"51566","messageId":"20070826161701.GA3300@auto.tuwien.ac.at","threadId":"8254","inReplyTo":"20070826011742.GF1219@pasky.or.cz","subject":"Re: [PATCH 4/5] gitweb: Selecting diffs in JavaScript","fromName":"Martin Koegler","fromEmail":"mkoegler@auto.tuwien.ac.at","sentAt":"2007-08-26T16:17:01Z","receivedAt":"2007-08-26T16:17:01Z","isPatch":true,"sender":{"key":"mkoegler@auto.tuwien.ac.at","avatar":null},"body":"On Sun, Aug 26, 2007 at 03:17:43AM +0200, Petr Baudis wrote:\n> On Sun, May 20, 2007 at 10:23:31PM CEST, Martin Koegler wrote:\n> > The adds support for selecting arbitrary diffs, if the client browser supports\n> > JavaScript.\n> > \n> > Signed-off-by: Martin Koegler <mkoegler@auto.tuwien.ac.at>\n> \n> JFYI, I've just enabled it on repo.or.cz experimentally. Please anyone\n> tell me what you think.\n\nI would also be interessed in this.\n\n> (Just click at almost any view in gitweb and marvel at the extra base\n> and diff links smiling everywhere.)\n>\n> I'll dump my mind state here, horribly sleepy. Sorry for the\n> incomprehensible rant. :-)\n\nI can't see them.\n\nhttp://repo.or.cz/w/git/repo.git?a=search&h=HEAD&st=grep&s=GitAddLinks\nreveals, that the function GitAddLinks is never called.\nYou should add a call to GitAddLinks in fixBlameLinks or call\nboth functions in <body onload=\"...\">.\n\n> One thing for certain is that I would get rid of GitAddLinks and instead\n> have href() add the extra links there, by default display: none and\n> javascript code making it show.\n\ndisplay: none will only work in CSS capable browses, but not text\nbrowsers. Also why do we want do increase the size of each generated\npage?\n\n> Also, there are obvious UI bugs, like\n> commit and tree entries for commits having redundant base/diff links;\n\nIs this really a bug? I think it makes the interface more consistent.\n\nWould it be clear for a (new) user, why some tree entries have the\nbase/diff links and some not?\n\n> and Firefox doesn't expand table cells properly for the additional\n> links. None of these bugs is easily fixable I think.\n\nIn which context?\n\nIn eg. http://repo.or.cz/w/git.git?a=log;h=gitgui-0.8.1, there are\ndisplay errors (even without the base/diff links), if the font size is\nzommed.  In this case, the problem is that there is no real\ntable. The links (div.log_link) are position: relative, so they don't\nincreate the height of the enclosing div. Additionall it has an hardcoded\nwidth in pixels.\n\n> But maybe it needs more general overhaul and the links added explicitly\n> in the views, because it really makes sense to have only a single\n> linkpair per entry and it would be good to have this always at the same\n> place, and perhaps in a different color. Hmm. And it seems that it's\n> getting in the way, overally.\n\nUnless this should be come part of the official gitweb, adding each\nlink explicitly would be a maintaince nightmare.\n\nChanging the color of the base/diff links is no problem. If somebody\nis interessed in this (and tells me, which colors I should use), I can\nadapt my patch.\n\n> What about having another item in the main action menu, 'diff'?\n> Base/diff links are by default display: none but show up when you click\n> at 'diff', in green. They will keep showing up until you click 'diff'\n> again. When you click 'base', both the selected base link and main\n> 'diff' link changes color to red.\n\nWe could call GitAddLinks, if the user clicks on the diff link instead\nof calling GitAddLinks at page load time.\n\nI could rewrite the JavaScript for this, if you think it is so more useful.\n\nmfg Martin Kögler\n"},{"id":"51576","messageId":"20070826172129.GK1219@pasky.or.cz","threadId":"8254","inReplyTo":"20070826161701.GA3300@auto.tuwien.ac.at","subject":"Re: [PATCH 4/5] gitweb: Selecting diffs in JavaScript","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2007-08-26T17:21:29Z","receivedAt":"2007-08-26T17:21:29Z","isPatch":true,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"On Sun, Aug 26, 2007 at 06:17:01PM CEST, Martin Koegler wrote:\n> http://repo.or.cz/w/git/repo.git?a=search&h=HEAD&st=grep&s=GitAddLinks\n> reveals, that the function GitAddLinks is never called.\n> You should add a call to GitAddLinks in fixBlameLinks or call\n> both functions in <body onload=\"...\">.\n\nWhoops, sorry - I already had that in, but must have accidentally\nremoved it again.\n\n> > One thing for certain is that I would get rid of GitAddLinks and instead\n> > have href() add the extra links there, by default display: none and\n> > javascript code making it show.\n> \n> display: none will only work in CSS capable browses, but not text\n> browsers. Also why do we want do increase the size of each generated\n> page?\n\nThese are both good points. The only thing I'm worried about is browser\nperformance; at least my Firefox can take noticeable few hundreds of\nmilliseconds to insert the links to only moderately sized pages.\n\n> > Also, there are obvious UI bugs, like\n> > commit and tree entries for commits having redundant base/diff links;\n> \n> Is this really a bug? I think it makes the interface more consistent.\n> \n> Would it be clear for a (new) user, why some tree entries have the\n> base/diff links and some not?\n\nMy aim is rather to have every single _entry_ to have a single base/diff\nlinkpair. Having two linkpairs seems more confusing to me.\n\n> > But maybe it needs more general overhaul and the links added explicitly\n> > in the views, because it really makes sense to have only a single\n> > linkpair per entry and it would be good to have this always at the same\n> > place, and perhaps in a different color. Hmm. And it seems that it's\n> > getting in the way, overally.\n> \n> Unless this should be come part of the official gitweb, adding each\n> link explicitly would be a maintaince nightmare.\n\nThis should become part of the official gitweb, what's the point\notherwise. :-)\n\n> Changing the color of the base/diff links is no problem. If somebody\n> is interessed in this (and tells me, which colors I should use), I can\n> adapt my patch.\n>\n> > What about having another item in the main action menu, 'diff'?\n> > Base/diff links are by default display: none but show up when you click\n> > at 'diff', in green. They will keep showing up until you click 'diff'\n> > again. When you click 'base', both the selected base link and main\n> > 'diff' link changes color to red.\n> \n> We could call GitAddLinks, if the user clicks on the diff link instead\n> of calling GitAddLinks at page load time.\n> \n> I could rewrite the JavaScript for this, if you think it is so more useful.\n\nThat would be awesome.\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nEver try. Ever fail. No matter. // Try again. Fail again. Fail better.\n\t\t-- Samuel Beckett\n"}]}