{"thread":{"id":"27689","subject":"[PATCH 0/5] gitweb: Improve search code","startedAt":"2011-06-22T15:28:50Z","lastAt":"2011-06-22T19:24:32Z","messageCount":10,"participants":["Jakub Narebski","Phil Hord","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"170466","messageId":"1308756535-29701-1-git-send-email-jnareb@gmail.com","threadId":"27689","inReplyTo":null,"subject":"[PATCH 0/5] gitweb: Improve search code","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T15:28:50Z","receivedAt":"2011-06-22T15:28:50Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Originally I have intended to go with it further, and improve how\nsearch results look like, for example by using 'log' view code to\ndisplay 'commit', 'author' and 'committer' search results, now managed\nby git_search_message.\n\nBut then I realized that I would need committags machinery for that.\nSo what we are left with are some code refactoring and cleanups.\n\nNot for 1.7.6 (not a regression fix).\n\nJakub Narebski (5):\n  gitweb: 'pickaxe' and 'grep' features requires 'search' to be enabled\n  gitweb: Check permissions first in git_search\n  gitweb: Split body of git_search into subroutines\n  gitweb: Clean up code in git_search_* subroutines\n  gitweb: Make git_search_* subroutines render whole pages\n\n gitweb/gitweb.perl |  442 ++++++++++++++++++++++++++++-----------------------\n 1 files changed, 243 insertions(+), 199 deletions(-)\n\n\nP.S. Another addition that I sometimes wanted git to have would be\n'filename' or 'find' search: searching for file by name.\n\nWhat do you think of it?\n-- \n1.7.5\n"},{"id":"170470","messageId":"1308756535-29701-2-git-send-email-jnareb@gmail.com","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"[PATCHv3 1/5] gitweb: 'pickaxe' and 'grep' features requires 'search' to be enabled","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T15:28:51Z","receivedAt":"2011-06-22T15:28:51Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Both 'pickaxe' (searching changes) and 'grep' (searching files)\nrequire basic 'search' feature to be enabled to work.  Enabling\ne.g. only 'pickaxe' won't work.\n\nAdd a comment about this.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nThis is slightly more expanded version than what was sent to git\nmailing list as\n\n  [PATCH (amend)] gitweb: 'pickaxe' and 'grep' features requires 'search' to be enabled\n  http://thread.gmane.org/gmane.comp.version-control.git/176095/focus=176127\n\nWhat's new is comment for 'search' feature.\n\n gitweb/gitweb.perl |    6 ++++++\n 1 files changed, 6 insertions(+), 0 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 0221eb9..fd93d45 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -321,6 +321,10 @@ our %feature = (\n \t# Enable text search, which will list the commits which match author,\n \t# committer or commit text to a given string.  Enabled by default.\n \t# Project specific override is not supported.\n+\t#\n+\t# Note that this controls all search features, which means that if\n+\t# it is disabled, then 'grep' and 'pickaxe' search would also be\n+\t# disabled.\n \t'search' => {\n \t\t'override' => 0,\n \t\t'default' => [1]},\n@@ -328,6 +332,7 @@ our %feature = (\n \t# Enable grep search, which will list the files in currently selected\n \t# tree containing the given string. Enabled by default. This can be\n \t# potentially CPU-intensive, of course.\n+\t# Note that you need to have 'search' feature enabled too.\n \n \t# To enable system wide have in $GITWEB_CONFIG\n \t# $feature{'grep'}{'default'} = [1];\n@@ -342,6 +347,7 @@ our %feature = (\n \t# Enable the pickaxe search, which will list the commits that modified\n \t# a given string in a file. This can be practical and quite faster\n \t# alternative to 'blame', but still potentially CPU-intensive.\n+\t# Note that you need to have 'search' feature enabled too.\n \n \t# To enable system wide have in $GITWEB_CONFIG\n \t# $feature{'pickaxe'}{'default'} = [1];\n-- \n1.7.5\n"},{"id":"170467","messageId":"1308756535-29701-3-git-send-email-jnareb@gmail.com","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"[PATCH 2/5] gitweb: Check permissions first in git_search","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T15:28:52Z","receivedAt":"2011-06-22T15:28:52Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Check first if relevant features: 'search', 'pickaxe', 'grep', as\nappropriate, are enabled before doing anything else in git_search.\nThis should make git_search code more clear.\n\nWhile at it, expand a bit error message (e.g. 'Pickaxe' ->\n'Pickaxe search').\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\n gitweb/gitweb.perl |   30 +++++++++++++++++-------------\n 1 files changed, 17 insertions(+), 13 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex fd93d45..32e50b4 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -7094,7 +7094,23 @@ sub git_history {\n }\n \n sub git_search {\n-\tgitweb_check_feature('search') or die_error(403, \"Search is disabled\");\n+\t$searchtype ||= 'commit';\n+\n+\t# check if appropriate features are enabled\n+\tgitweb_check_feature('search')\n+\t\tor die_error(403, \"Search is disabled\");\n+\tif ($searchtype eq 'pickaxe') {\n+\t\t# pickaxe may take all resources of your box and run for several minutes\n+\t\t# with every query - so decide by yourself how public you make this feature\n+\t\tgitweb_check_feature('pickaxe')\n+\t\t\tor die_error(403, \"Pickaxe search is disabled\");\n+\t}\n+\tif ($searchtype eq 'grep') {\n+\t\t# grep search might be potentially CPU-intensive, too\n+\t\tgitweb_check_feature('grep')\n+\t\t\tor die_error(403, \"Grep search is disabled\");\n+\t}\n+\n \tif (!defined $searchtext) {\n \t\tdie_error(400, \"Text field is empty\");\n \t}\n@@ -7109,18 +7125,6 @@ sub git_search {\n \t\t$page = 0;\n \t}\n \n-\t$searchtype ||= 'commit';\n-\tif ($searchtype eq 'pickaxe') {\n-\t\t# pickaxe may take all resources of your box and run for several minutes\n-\t\t# with every query - so decide by yourself how public you make this feature\n-\t\tgitweb_check_feature('pickaxe')\n-\t\t    or die_error(403, \"Pickaxe is disabled\");\n-\t}\n-\tif ($searchtype eq 'grep') {\n-\t\tgitweb_check_feature('grep')\n-\t\t    or die_error(403, \"Grep is disabled\");\n-\t}\n-\n \tgit_header_html();\n \n \tif ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') {\n-- \n1.7.5\n"},{"id":"170469","messageId":"1308756535-29701-4-git-send-email-jnareb@gmail.com","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"[PATCH 3/5] gitweb: Split body of git_search into subroutines","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T15:28:53Z","receivedAt":"2011-06-22T15:28:53Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Create separate subroutines for handling each of aspects of searching\nthe repository:\n* git_search_mesaage ('commit', 'author', 'committer')\n* git_search_changes ('pickaxe')\n* git_search_content_of_files ('grep')\n\nAlmost pure code movement (and unindent), which you can check e.g. via\n\n  $ git blame -w --date=short -C -C HEAD^.. -- gitweb/gitweb.perl |\n    grep -C 3 -e '^[^^]' | less -S\n\n(assuming that you have this version checked out).  No functional\nchanges.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\n gitweb/gitweb.perl |  381 +++++++++++++++++++++++++++-------------------------\n 1 files changed, 199 insertions(+), 182 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 32e50b4..c350c05 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -5540,6 +5540,197 @@ sub git_remotes_body {\n \t}\n }\n \n+sub git_search_message {\n+\tmy %co = @_;\n+\n+\tmy $greptype;\n+\tif ($searchtype eq 'commit') {\n+\t\t$greptype = \"--grep=\";\n+\t} elsif ($searchtype eq 'author') {\n+\t\t$greptype = \"--author=\";\n+\t} elsif ($searchtype eq 'committer') {\n+\t\t$greptype = \"--committer=\";\n+\t}\n+\t$greptype .= $searchtext;\n+\tmy @commitlist = parse_commits($hash, 101, (100 * $page), undef,\n+\t                               $greptype, '--regexp-ignore-case',\n+\t                               $search_use_regexp ? '--extended-regexp' : '--fixed-strings');\n+\n+\tmy $paging_nav = '';\n+\tif ($page > 0) {\n+\t\t$paging_nav .=\n+\t\t\t$cgi->a({-href => href(action=>\"search\", hash=>$hash,\n+\t\t\t                       searchtext=>$searchtext,\n+\t\t\t                       searchtype=>$searchtype)},\n+\t\t\t        \"first\");\n+\t\t$paging_nav .= \" &sdot; \" .\n+\t\t\t$cgi->a({-href => href(-replay=>1, page=>$page-1),\n+\t\t\t         -accesskey => \"p\", -title => \"Alt-p\"}, \"prev\");\n+\t} else {\n+\t\t$paging_nav .= \"first\";\n+\t\t$paging_nav .= \" &sdot; prev\";\n+\t}\n+\tmy $next_link = '';\n+\tif ($#commitlist >= 100) {\n+\t\t$next_link =\n+\t\t\t$cgi->a({-href => href(-replay=>1, page=>$page+1),\n+\t\t\t         -accesskey => \"n\", -title => \"Alt-n\"}, \"next\");\n+\t\t$paging_nav .= \" &sdot; $next_link\";\n+\t} else {\n+\t\t$paging_nav .= \" &sdot; next\";\n+\t}\n+\n+\tgit_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav);\n+\tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n+\tif ($page == 0 && !@commitlist) {\n+\t\tprint \"<p>No match.</p>\\n\";\n+\t} else {\n+\t\tgit_search_grep_body(\\@commitlist, 0, 99, $next_link);\n+\t}\n+}\n+\n+sub git_search_changes {\n+\tmy %co = @_;\n+\n+\tgit_print_page_nav('','', $hash,$co{'tree'},$hash);\n+\tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n+\n+\tprint \"<table class=\\\"pickaxe search\\\">\\n\";\n+\tmy $alternate = 1;\n+\tlocal $/ = \"\\n\";\n+\topen my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,\n+\t\t'--pretty=format:%H', '--no-abbrev', '--raw', \"-S$searchtext\",\n+\t\t($search_use_regexp ? '--pickaxe-regex' : ());\n+\tundef %co;\n+\tmy @files;\n+\twhile (my $line = <$fd>) {\n+\t\tchomp $line;\n+\t\tnext unless $line;\n+\n+\t\tmy %set = parse_difftree_raw_line($line);\n+\t\tif (defined $set{'commit'}) {\n+\t\t\t# finish previous commit\n+\t\t\tif (%co) {\n+\t\t\t\tprint \"</td>\\n\" .\n+\t\t\t\t      \"<td class=\\\"link\\\">\" .\n+\t\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})}, \"commit\") .\n+\t\t\t\t      \" | \" .\n+\t\t\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'}, hash_base=>$co{'id'})}, \"tree\");\n+\t\t\t\tprint \"</td>\\n\" .\n+\t\t\t\t      \"</tr>\\n\";\n+\t\t\t}\n+\n+\t\t\tif ($alternate) {\n+\t\t\t\tprint \"<tr class=\\\"dark\\\">\\n\";\n+\t\t\t} else {\n+\t\t\t\tprint \"<tr class=\\\"light\\\">\\n\";\n+\t\t\t}\n+\t\t\t$alternate ^= 1;\n+\t\t\t%co = parse_commit($set{'commit'});\n+\t\t\tmy $author = chop_and_escape_str($co{'author_name'}, 15, 5);\n+\t\t\tprint \"<td title=\\\"$co{'age_string_age'}\\\"><i>$co{'age_string_date'}</i></td>\\n\" .\n+\t\t\t      \"<td><i>$author</i></td>\\n\" .\n+\t\t\t      \"<td>\" .\n+\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'}),\n+\t\t\t              -class => \"list subject\"},\n+\t\t\t              chop_and_escape_str($co{'title'}, 50) . \"<br/>\");\n+\t\t} elsif (defined $set{'to_id'}) {\n+\t\t\tnext if ($set{'to_id'} =~ m/^0{40}$/);\n+\n+\t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash_base=>$co{'id'},\n+\t\t\t                             hash=>$set{'to_id'}, file_name=>$set{'to_file'}),\n+\t\t\t              -class => \"list\"},\n+\t\t\t              \"<span class=\\\"match\\\">\" . esc_path($set{'file'}) . \"</span>\") .\n+\t\t\t      \"<br/>\\n\";\n+\t\t}\n+\t}\n+\tclose $fd;\n+\n+\t# finish last commit (warning: repetition!)\n+\tif (%co) {\n+\t\tprint \"</td>\\n\" .\n+\t\t      \"<td class=\\\"link\\\">\" .\n+\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})}, \"commit\") .\n+\t\t      \" | \" .\n+\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'}, hash_base=>$co{'id'})}, \"tree\");\n+\t\tprint \"</td>\\n\" .\n+\t\t      \"</tr>\\n\";\n+\t}\n+\n+\tprint \"</table>\\n\";\n+}\n+\n+sub git_search_files {\n+\tmy %co = @_;\n+\n+\tgit_print_page_nav('','', $hash,$co{'tree'},$hash);\n+\tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n+\n+\tprint \"<table class=\\\"grep_search\\\">\\n\";\n+\tmy $alternate = 1;\n+\tmy $matches = 0;\n+\tlocal $/ = \"\\n\";\n+\topen my $fd, \"-|\", git_cmd(), 'grep', '-n',\n+\t\t$search_use_regexp ? ('-E', '-i') : '-F',\n+\t\t$searchtext, $co{'tree'};\n+\tmy $lastfile = '';\n+\twhile (my $line = <$fd>) {\n+\t\tchomp $line;\n+\t\tmy ($file, $lno, $ltext, $binary);\n+\t\tlast if ($matches++ > 1000);\n+\t\tif ($line =~ /^Binary file (.+) matches$/) {\n+\t\t\t$file = $1;\n+\t\t\t$binary = 1;\n+\t\t} else {\n+\t\t\t(undef, $file, $lno, $ltext) = split(/:/, $line, 4);\n+\t\t}\n+\t\tif ($file ne $lastfile) {\n+\t\t\t$lastfile and print \"</td></tr>\\n\";\n+\t\t\tif ($alternate++) {\n+\t\t\t\tprint \"<tr class=\\\"dark\\\">\\n\";\n+\t\t\t} else {\n+\t\t\t\tprint \"<tr class=\\\"light\\\">\\n\";\n+\t\t\t}\n+\t\t\tprint \"<td class=\\\"list\\\">\".\n+\t\t\t\t$cgi->a({-href => href(action=>\"blob\", hash=>$co{'hash'},\n+\t\t\t\t\t\t       file_name=>\"$file\"),\n+\t\t\t\t\t-class => \"list\"}, esc_path($file));\n+\t\t\tprint \"</td><td>\\n\";\n+\t\t\t$lastfile = $file;\n+\t\t}\n+\t\tif ($binary) {\n+\t\t\tprint \"<div class=\\\"binary\\\">Binary file</div>\\n\";\n+\t\t} else {\n+\t\t\t$ltext = untabify($ltext);\n+\t\t\tif ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) {\n+\t\t\t\t$ltext = esc_html($1, -nbsp=>1);\n+\t\t\t\t$ltext .= '<span class=\"match\">';\n+\t\t\t\t$ltext .= esc_html($2, -nbsp=>1);\n+\t\t\t\t$ltext .= '</span>';\n+\t\t\t\t$ltext .= esc_html($3, -nbsp=>1);\n+\t\t\t} else {\n+\t\t\t\t$ltext = esc_html($ltext, -nbsp=>1);\n+\t\t\t}\n+\t\t\tprint \"<div class=\\\"pre\\\">\" .\n+\t\t\t\t$cgi->a({-href => href(action=>\"blob\", hash=>$co{'hash'},\n+\t\t\t\t\t\t       file_name=>\"$file\").'#l'.$lno,\n+\t\t\t\t\t-class => \"linenr\"}, sprintf('%4i', $lno))\n+\t\t\t\t. ' ' .  $ltext . \"</div>\\n\";\n+\t\t}\n+\t}\n+\tif ($lastfile) {\n+\t\tprint \"</td></tr>\\n\";\n+\t\tif ($matches > 1000) {\n+\t\t\tprint \"<div class=\\\"diff nodifferences\\\">Too many matches, listing trimmed</div>\\n\";\n+\t\t}\n+\t} else {\n+\t\tprint \"<div class=\\\"diff nodifferences\\\">No matches found</div>\\n\";\n+\t}\n+\tclose $fd;\n+\n+\tprint \"</table>\\n\";\n+}\n+\n sub git_search_grep_body {\n \tmy ($commitlist, $from, $to, $extra) = @_;\n \t$from = 0 unless defined $from;\n@@ -7127,190 +7318,16 @@ sub git_search {\n \n \tgit_header_html();\n \n-\tif ($searchtype eq 'commit' or $searchtype eq 'author' or $searchtype eq 'committer') {\n-\t\tmy $greptype;\n-\t\tif ($searchtype eq 'commit') {\n-\t\t\t$greptype = \"--grep=\";\n-\t\t} elsif ($searchtype eq 'author') {\n-\t\t\t$greptype = \"--author=\";\n-\t\t} elsif ($searchtype eq 'committer') {\n-\t\t\t$greptype = \"--committer=\";\n-\t\t}\n-\t\t$greptype .= $searchtext;\n-\t\tmy @commitlist = parse_commits($hash, 101, (100 * $page), undef,\n-\t\t                               $greptype, '--regexp-ignore-case',\n-\t\t                               $search_use_regexp ? '--extended-regexp' : '--fixed-strings');\n-\n-\t\tmy $paging_nav = '';\n-\t\tif ($page > 0) {\n-\t\t\t$paging_nav .=\n-\t\t\t\t$cgi->a({-href => href(action=>\"search\", hash=>$hash,\n-\t\t\t\t                       searchtext=>$searchtext,\n-\t\t\t\t                       searchtype=>$searchtype)},\n-\t\t\t\t        \"first\");\n-\t\t\t$paging_nav .= \" &sdot; \" .\n-\t\t\t\t$cgi->a({-href => href(-replay=>1, page=>$page-1),\n-\t\t\t\t         -accesskey => \"p\", -title => \"Alt-p\"}, \"prev\");\n-\t\t} else {\n-\t\t\t$paging_nav .= \"first\";\n-\t\t\t$paging_nav .= \" &sdot; prev\";\n-\t\t}\n-\t\tmy $next_link = '';\n-\t\tif ($#commitlist >= 100) {\n-\t\t\t$next_link =\n-\t\t\t\t$cgi->a({-href => href(-replay=>1, page=>$page+1),\n-\t\t\t\t         -accesskey => \"n\", -title => \"Alt-n\"}, \"next\");\n-\t\t\t$paging_nav .= \" &sdot; $next_link\";\n-\t\t} else {\n-\t\t\t$paging_nav .= \" &sdot; next\";\n-\t\t}\n-\n-\t\tgit_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav);\n-\t\tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n-\t\tif ($page == 0 && !@commitlist) {\n-\t\t\tprint \"<p>No match.</p>\\n\";\n-\t\t} else {\n-\t\t\tgit_search_grep_body(\\@commitlist, 0, 99, $next_link);\n-\t\t}\n+\tif ($searchtype eq 'commit' ||\n+\t    $searchtype eq 'author' ||\n+\t    $searchtype eq 'committer') {\n+\t\tgit_search_message(%co);\n+\t} elsif ($searchtype eq 'pickaxe') {\n+\t\tgit_search_changes(%co);\n+\t} elsif ($searchtype eq 'grep') {\n+\t\tgit_search_files(%co);\n \t}\n \n-\tif ($searchtype eq 'pickaxe') {\n-\t\tgit_print_page_nav('','', $hash,$co{'tree'},$hash);\n-\t\tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n-\n-\t\tprint \"<table class=\\\"pickaxe search\\\">\\n\";\n-\t\tmy $alternate = 1;\n-\t\tlocal $/ = \"\\n\";\n-\t\topen my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,\n-\t\t\t'--pretty=format:%H', '--no-abbrev', '--raw', \"-S$searchtext\",\n-\t\t\t($search_use_regexp ? '--pickaxe-regex' : ());\n-\t\tundef %co;\n-\t\tmy @files;\n-\t\twhile (my $line = <$fd>) {\n-\t\t\tchomp $line;\n-\t\t\tnext unless $line;\n-\n-\t\t\tmy %set = parse_difftree_raw_line($line);\n-\t\t\tif (defined $set{'commit'}) {\n-\t\t\t\t# finish previous commit\n-\t\t\t\tif (%co) {\n-\t\t\t\t\tprint \"</td>\\n\" .\n-\t\t\t\t\t      \"<td class=\\\"link\\\">\" .\n-\t\t\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})}, \"commit\") .\n-\t\t\t\t\t      \" | \" .\n-\t\t\t\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'}, hash_base=>$co{'id'})}, \"tree\");\n-\t\t\t\t\tprint \"</td>\\n\" .\n-\t\t\t\t\t      \"</tr>\\n\";\n-\t\t\t\t}\n-\n-\t\t\t\tif ($alternate) {\n-\t\t\t\t\tprint \"<tr class=\\\"dark\\\">\\n\";\n-\t\t\t\t} else {\n-\t\t\t\t\tprint \"<tr class=\\\"light\\\">\\n\";\n-\t\t\t\t}\n-\t\t\t\t$alternate ^= 1;\n-\t\t\t\t%co = parse_commit($set{'commit'});\n-\t\t\t\tmy $author = chop_and_escape_str($co{'author_name'}, 15, 5);\n-\t\t\t\tprint \"<td title=\\\"$co{'age_string_age'}\\\"><i>$co{'age_string_date'}</i></td>\\n\" .\n-\t\t\t\t      \"<td><i>$author</i></td>\\n\" .\n-\t\t\t\t      \"<td>\" .\n-\t\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'}),\n-\t\t\t\t              -class => \"list subject\"},\n-\t\t\t\t              chop_and_escape_str($co{'title'}, 50) . \"<br/>\");\n-\t\t\t} elsif (defined $set{'to_id'}) {\n-\t\t\t\tnext if ($set{'to_id'} =~ m/^0{40}$/);\n-\n-\t\t\t\tprint $cgi->a({-href => href(action=>\"blob\", hash_base=>$co{'id'},\n-\t\t\t\t                             hash=>$set{'to_id'}, file_name=>$set{'to_file'}),\n-\t\t\t\t              -class => \"list\"},\n-\t\t\t\t              \"<span class=\\\"match\\\">\" . esc_path($set{'file'}) . \"</span>\") .\n-\t\t\t\t      \"<br/>\\n\";\n-\t\t\t}\n-\t\t}\n-\t\tclose $fd;\n-\n-\t\t# finish last commit (warning: repetition!)\n-\t\tif (%co) {\n-\t\t\tprint \"</td>\\n\" .\n-\t\t\t      \"<td class=\\\"link\\\">\" .\n-\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})}, \"commit\") .\n-\t\t\t      \" | \" .\n-\t\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'}, hash_base=>$co{'id'})}, \"tree\");\n-\t\t\tprint \"</td>\\n\" .\n-\t\t\t      \"</tr>\\n\";\n-\t\t}\n-\n-\t\tprint \"</table>\\n\";\n-\t}\n-\n-\tif ($searchtype eq 'grep') {\n-\t\tgit_print_page_nav('','', $hash,$co{'tree'},$hash);\n-\t\tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n-\n-\t\tprint \"<table class=\\\"grep_search\\\">\\n\";\n-\t\tmy $alternate = 1;\n-\t\tmy $matches = 0;\n-\t\tlocal $/ = \"\\n\";\n-\t\topen my $fd, \"-|\", git_cmd(), 'grep', '-n',\n-\t\t\t$search_use_regexp ? ('-E', '-i') : '-F',\n-\t\t\t$searchtext, $co{'tree'};\n-\t\tmy $lastfile = '';\n-\t\twhile (my $line = <$fd>) {\n-\t\t\tchomp $line;\n-\t\t\tmy ($file, $lno, $ltext, $binary);\n-\t\t\tlast if ($matches++ > 1000);\n-\t\t\tif ($line =~ /^Binary file (.+) matches$/) {\n-\t\t\t\t$file = $1;\n-\t\t\t\t$binary = 1;\n-\t\t\t} else {\n-\t\t\t\t(undef, $file, $lno, $ltext) = split(/:/, $line, 4);\n-\t\t\t}\n-\t\t\tif ($file ne $lastfile) {\n-\t\t\t\t$lastfile and print \"</td></tr>\\n\";\n-\t\t\t\tif ($alternate++) {\n-\t\t\t\t\tprint \"<tr class=\\\"dark\\\">\\n\";\n-\t\t\t\t} else {\n-\t\t\t\t\tprint \"<tr class=\\\"light\\\">\\n\";\n-\t\t\t\t}\n-\t\t\t\tprint \"<td class=\\\"list\\\">\".\n-\t\t\t\t\t$cgi->a({-href => href(action=>\"blob\", hash=>$co{'hash'},\n-\t\t\t\t\t\t\t       file_name=>\"$file\"),\n-\t\t\t\t\t\t-class => \"list\"}, esc_path($file));\n-\t\t\t\tprint \"</td><td>\\n\";\n-\t\t\t\t$lastfile = $file;\n-\t\t\t}\n-\t\t\tif ($binary) {\n-\t\t\t\tprint \"<div class=\\\"binary\\\">Binary file</div>\\n\";\n-\t\t\t} else {\n-\t\t\t\t$ltext = untabify($ltext);\n-\t\t\t\tif ($ltext =~ m/^(.*)($search_regexp)(.*)$/i) {\n-\t\t\t\t\t$ltext = esc_html($1, -nbsp=>1);\n-\t\t\t\t\t$ltext .= '<span class=\"match\">';\n-\t\t\t\t\t$ltext .= esc_html($2, -nbsp=>1);\n-\t\t\t\t\t$ltext .= '</span>';\n-\t\t\t\t\t$ltext .= esc_html($3, -nbsp=>1);\n-\t\t\t\t} else {\n-\t\t\t\t\t$ltext = esc_html($ltext, -nbsp=>1);\n-\t\t\t\t}\n-\t\t\t\tprint \"<div class=\\\"pre\\\">\" .\n-\t\t\t\t\t$cgi->a({-href => href(action=>\"blob\", hash=>$co{'hash'},\n-\t\t\t\t\t\t\t       file_name=>\"$file\").'#l'.$lno,\n-\t\t\t\t\t\t-class => \"linenr\"}, sprintf('%4i', $lno))\n-\t\t\t\t\t. ' ' .  $ltext . \"</div>\\n\";\n-\t\t\t}\n-\t\t}\n-\t\tif ($lastfile) {\n-\t\t\tprint \"</td></tr>\\n\";\n-\t\t\tif ($matches > 1000) {\n-\t\t\t\tprint \"<div class=\\\"diff nodifferences\\\">Too many matches, listing trimmed</div>\\n\";\n-\t\t\t}\n-\t\t} else {\n-\t\t\tprint \"<div class=\\\"diff nodifferences\\\">No matches found</div>\\n\";\n-\t\t}\n-\t\tclose $fd;\n-\n-\t\tprint \"</table>\\n\";\n-\t}\n \tgit_footer_html();\n }\n \n-- \n1.7.5\n"},{"id":"170468","messageId":"1308756535-29701-5-git-send-email-jnareb@gmail.com","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"[PATCH 4/5] gitweb: Clean up code in git_search_* subroutines","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T15:28:54Z","receivedAt":"2011-06-22T15:28:54Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"1. Replace sequence of\n\n     $foo .= \"bar\";\n     $foo .= \"baz\";\n\n   with\n\n     $foo .= \"bar\" .\n             \"baz\";\n\n2. Use href(-replay=>1, -page=>undef) for first page of a multip-page\n   view.\n\n3. Rewrap (rearrange) some lines to reduce their length. Some lines\n   still have more than 80 characters, but lines are shorter now.\n\nNo functional changes.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\n gitweb/gitweb.perl |   29 ++++++++++++++++-------------\n 1 files changed, 16 insertions(+), 13 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex c350c05..1c06476 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -5559,16 +5559,13 @@ sub git_search_message {\n \tmy $paging_nav = '';\n \tif ($page > 0) {\n \t\t$paging_nav .=\n-\t\t\t$cgi->a({-href => href(action=>\"search\", hash=>$hash,\n-\t\t\t                       searchtext=>$searchtext,\n-\t\t\t                       searchtype=>$searchtype)},\n-\t\t\t        \"first\");\n-\t\t$paging_nav .= \" &sdot; \" .\n+\t\t\t$cgi->a({-href => href(-replay=>1, page=>undef)},\n+\t\t\t        \"first\") .\n+\t\t\t\" &sdot; \" .\n \t\t\t$cgi->a({-href => href(-replay=>1, page=>$page-1),\n \t\t\t         -accesskey => \"p\", -title => \"Alt-p\"}, \"prev\");\n \t} else {\n-\t\t$paging_nav .= \"first\";\n-\t\t$paging_nav .= \" &sdot; prev\";\n+\t\t$paging_nav .= \"first &sdot; prev\";\n \t}\n \tmy $next_link = '';\n \tif ($#commitlist >= 100) {\n@@ -5613,10 +5610,13 @@ sub git_search_changes {\n \t\t\tif (%co) {\n \t\t\t\tprint \"</td>\\n\" .\n \t\t\t\t      \"<td class=\\\"link\\\">\" .\n-\t\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})}, \"commit\") .\n+\t\t\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})},\n+\t\t\t\t              \"commit\") .\n \t\t\t\t      \" | \" .\n-\t\t\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'}, hash_base=>$co{'id'})}, \"tree\");\n-\t\t\t\tprint \"</td>\\n\" .\n+\t\t\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'},\n+\t\t\t\t                             hash_base=>$co{'id'})},\n+\t\t\t\t              \"tree\") .\n+\t\t\t\t      \"</td>\\n\" .\n \t\t\t\t      \"</tr>\\n\";\n \t\t\t}\n \n@@ -5650,10 +5650,13 @@ sub git_search_changes {\n \tif (%co) {\n \t\tprint \"</td>\\n\" .\n \t\t      \"<td class=\\\"link\\\">\" .\n-\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})}, \"commit\") .\n+\t\t      $cgi->a({-href => href(action=>\"commit\", hash=>$co{'id'})},\n+\t\t              \"commit\") .\n \t\t      \" | \" .\n-\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'}, hash_base=>$co{'id'})}, \"tree\");\n-\t\tprint \"</td>\\n\" .\n+\t\t      $cgi->a({-href => href(action=>\"tree\", hash=>$co{'tree'},\n+\t\t                             hash_base=>$co{'id'})},\n+\t\t              \"tree\") .\n+\t\t      \"</td>\\n\" .\n \t\t      \"</tr>\\n\";\n \t}\n \n-- \n1.7.5\n"},{"id":"170471","messageId":"1308756535-29701-6-git-send-email-jnareb@gmail.com","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"[PATCH 5/5] gitweb: Make git_search_* subroutines render whole pages","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T15:28:55Z","receivedAt":"2011-06-22T15:28:55Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"This means moving git_header_html() and git_footer_html() invocation\nfrom git_search() to individual git_search_* subroutines.\n\nWhile at it reorganize search-related code a bit, moving invoking of\ngit commands before any output is generated.\n\n\nThis has the following advantages:\n\n* gitweb now shows an error page if there was unknown search type\n  (evaluate_and_validate_params checks only that it looks sanely);\n  remember that we shouldn't call die_error after any output.\n\n* git_search_message is now safe agains die_error in parse_commits\n  (though this is very unlikely).\n\n* gitweb now can check errors while invoking git commands and show\n  error page (again, quite unlikely).\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\n gitweb/gitweb.perl |   38 ++++++++++++++++++++++++++------------\n 1 files changed, 26 insertions(+), 12 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 1c06476..f8df027 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -5577,6 +5577,8 @@ sub git_search_message {\n \t\t$paging_nav .= \" &sdot; next\";\n \t}\n \n+\tgit_header_html();\n+\n \tgit_print_page_nav('','', $hash,$co{'tree'},$hash, $paging_nav);\n \tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n \tif ($page == 0 && !@commitlist) {\n@@ -5584,20 +5586,26 @@ sub git_search_message {\n \t} else {\n \t\tgit_search_grep_body(\\@commitlist, 0, 99, $next_link);\n \t}\n+\n+\tgit_footer_html();\n }\n \n sub git_search_changes {\n \tmy %co = @_;\n \n+\tlocal $/ = \"\\n\";\n+\topen my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,\n+\t\t'--pretty=format:%H', '--no-abbrev', '--raw', \"-S$searchtext\",\n+\t\t($search_use_regexp ? '--pickaxe-regex' : ())\n+\t\t\tor die_error(500, \"Open git-log failed\");\n+\n+\tgit_header_html();\n+\n \tgit_print_page_nav('','', $hash,$co{'tree'},$hash);\n \tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n \n \tprint \"<table class=\\\"pickaxe search\\\">\\n\";\n \tmy $alternate = 1;\n-\tlocal $/ = \"\\n\";\n-\topen my $fd, '-|', git_cmd(), '--no-pager', 'log', @diff_opts,\n-\t\t'--pretty=format:%H', '--no-abbrev', '--raw', \"-S$searchtext\",\n-\t\t($search_use_regexp ? '--pickaxe-regex' : ());\n \tundef %co;\n \tmy @files;\n \twhile (my $line = <$fd>) {\n@@ -5661,21 +5669,27 @@ sub git_search_changes {\n \t}\n \n \tprint \"</table>\\n\";\n+\n+\tgit_footer_html();\n }\n \n sub git_search_files {\n \tmy %co = @_;\n \n+\tlocal $/ = \"\\n\";\n+\topen my $fd, \"-|\", git_cmd(), 'grep', '-n',\n+\t\t$search_use_regexp ? ('-E', '-i') : '-F',\n+\t\t$searchtext, $co{'tree'}\n+\t\t\tor die_error(500, \"Open git-grep failed\");\n+\n+\tgit_header_html();\n+\n \tgit_print_page_nav('','', $hash,$co{'tree'},$hash);\n \tgit_print_header_div('commit', esc_html($co{'title'}), $hash);\n \n \tprint \"<table class=\\\"grep_search\\\">\\n\";\n \tmy $alternate = 1;\n \tmy $matches = 0;\n-\tlocal $/ = \"\\n\";\n-\topen my $fd, \"-|\", git_cmd(), 'grep', '-n',\n-\t\t$search_use_regexp ? ('-E', '-i') : '-F',\n-\t\t$searchtext, $co{'tree'};\n \tmy $lastfile = '';\n \twhile (my $line = <$fd>) {\n \t\tchomp $line;\n@@ -5732,6 +5746,8 @@ sub git_search_files {\n \tclose $fd;\n \n \tprint \"</table>\\n\";\n+\n+\tgit_footer_html();\n }\n \n sub git_search_grep_body {\n@@ -7319,8 +7335,6 @@ sub git_search {\n \t\t$page = 0;\n \t}\n \n-\tgit_header_html();\n-\n \tif ($searchtype eq 'commit' ||\n \t    $searchtype eq 'author' ||\n \t    $searchtype eq 'committer') {\n@@ -7329,9 +7343,9 @@ sub git_search {\n \t\tgit_search_changes(%co);\n \t} elsif ($searchtype eq 'grep') {\n \t\tgit_search_files(%co);\n+\t} else {\n+\t\tdie_error(400, \"Unknown search type\");\n \t}\n-\n-\tgit_footer_html();\n }\n \n sub git_search_help {\n-- \n1.7.5\n"},{"id":"170473","messageId":"4E02220F.10800@cisco.com","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"Re: [PATCH 0/5] gitweb: Improve search code","fromName":"Phil Hord","fromEmail":"hordp@cisco.com","sentAt":"2011-06-22T17:10:39Z","receivedAt":"2011-06-22T17:10:39Z","isPatch":true,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"Admin note: Should I have changed the subject or kept it?\n\nOn 06/22/2011 11:28 AM, Jakub Narebski wrote:\n> P.S. Another addition that I sometimes wanted git to have would be\n> 'filename' or 'find' search: searching for file by name.\n>\n> What do you think of it?\n\nI like it.  +1 from me.\n\nI normally revert to 'git log --name-status | less <CR> /filename.foo',\nwhich is awful, of course.  I've always assumed there's a better way I\nhaven't discovered yet.  But if there is, well... I haven't discovered\nit yet.\n\nThis syntax works on some files, but is limited and/or broken:\n   # Finds all commits touching the file named './foo.bar', iff\n./foo.bar exists in the current commit.\n   git log -- foo.bar\n\nI say 'broken', but maybe it's not; it feels like it is when I do this:\n\n   # Returns zero logs\n   git log -- some-deleted-file.txt\n\n   # Returns at least two logs\n   git log --all -- some-deleted-file.txt\n\nI think I understand why that happens (search optimization), but it is\nunexpected from the user's perspective.  I also suspect it will miss the\n'pre-resurrection' commits for files which were deleted and resurrected\nin the past.\n\n\nWhat do you think of these as new 'Commit limiters' for git log:\n\n       --name=<pattern>, --name-glob=<glob>\n           Limit the commits output to ones touching files that match the\n           specified pattern (regular expression) or glob (shell glob\npattern).\n\nThis could be further modified by --diff-filter, --all-match, etc.\n\n   # Find all commits which deleted a file named **/foo.**\n   git log --name=\"/foo[.]\" --diff-filter=D\n\n   # Find all commits which deleted a file named **/foo.**\n   #   or one named **/bar.**\n   git log --name=\"/foo[.]\" --name=\"/bar[.]\" --diff-filter=D\n\n   # Find all commits which touched both a file named **/foo.**\n   #   and one named **/bar.**\n   git log --name=\"/foo[.]\" --name=\"/bar[.]\" --all-match\n\n\nOr this alternate form:\n\n       --name-pattern, --name-glob\n           Treat all <path> selectors as pattern (regular expression) or\nglob (shell glob pattern).\n\nI think I prefer the former, since the latter does not allow for a\ncombination of raw names, pattern names and glob names.  Also, it does\nnot (intuitively) support --all-match.\n\n   # Find all commits which deleted a file named **/foo.**\n   git log --name-pattern --diff-filter=D -- \"/foo[.]\"\n   git log --name-glob --diff-filter=D -- \"/foo.*\"\n\n   # Find all commits which deleted a file named **/foo.**\n   #   or one named **/bar.**\n   git log --name-pattern --diff-filter=D -- \"/foo[.]\" \"/bar[.]\"\n\n   # Find all commits which touched both a file named **/foo.**\n   #   and one named **/bar.**\n   #  -- Can't be done?\n\nFinally, do the extensions belong on rev-list as well?  The 'git\nrev-list' command seems underpowered compared to 'git log'.\n\nPhil\n"},{"id":"170474","messageId":"201106222000.04854.jnareb@gmail.com","threadId":"27689","inReplyTo":"4E02220F.10800@cisco.com","subject":"Re: [PATCH 0/5] gitweb: Improve search code","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2011-06-22T18:00:03Z","receivedAt":"2011-06-22T18:00:03Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Wed, 22 Jun 2011, Phil Hord wrote:\n> On 06/22/2011 11:28 AM, Jakub Narebski wrote:\n\n> > P.S. Another addition that I sometimes wanted git to have would be\n                                                  ^^^\n\nThis is a typo: I actually wanted to say \"gitweb\" here.\n\nTherefore this discussion is totally OFF-TOPIC now.\n\n> > 'filename' or 'find' search: searching for file by name.\n> >\n> > What do you think of it?\n> \n> I like it.  +1 from me.\n> \n> I normally revert to 'git log --name-status | less <CR> /filename.foo',\n> which is awful, of course.  I've always assumed there's a better way I\n> haven't discovered yet.  But if there is, well... I haven't discovered\n> it yet.\n> \n> This syntax works on some files, but is limited and/or broken:\n>    # Finds all commits touching the file named './foo.bar', iff\n> ./foo.bar exists in the current commit.\n>    git log -- foo.bar\n\nErrr... if you use \"git log foo.bar\" it is true, but \"git log -- foo.bar\"\nwill find commits even if foo.bar existed only in the past... though\nhistory simplification can make git return empty set.\n\n> \n> I say 'broken', but maybe it's not; it feels like it is when I do this:\n> \n>    # Returns zero logs\n>    git log -- some-deleted-file.txt\n> \n>    # Returns at least two logs\n>    git log --all -- some-deleted-file.txt\n\n     git log --full-history -- some-deleted-file.txt\n\nFor example in git.git repository:\n\n   $ # git log --full-history --oneline -- gitweb.pl | cat\n   2ad9331 v053\n   185f09e v049\n   ff7669a v048\n   fbb592a v043\n   [...]\n   e0389bd v001\n   ecb378f v000\n   4c02e3c v000\n   161332a first working version\n\n(Don't you just love Kay Sievers commit messages ;-) ?).\n\n> I think I understand why that happens (search optimization), but it is\n> unexpected from the user's perspective.  I also suspect it will miss the\n> 'pre-resurrection' commits for files which were deleted and resurrected\n> in the past.\n> \n> \n> What do you think of these as new 'Commit limiters' for git log:\n> \n>        --name=<pattern>, --name-glob=<glob>\n>            Limit the commits output to ones touching files that match the\n>            specified pattern (regular expression) or glob (shell glob\n>            pattern).\n\nWhy not use \"git log --full-history -- '<glob>'\" (i.e. remember about\nshell escaping glob)?  I don't know if it works as intended in current\ngit or not...\n\n-- \nJakub Narebski\nPoland\n"},{"id":"170475","messageId":"7vwrgd66hw.fsf@alter.siamese.dyndns.org","threadId":"27689","inReplyTo":"1308756535-29701-1-git-send-email-jnareb@gmail.com","subject":"Re: [PATCH 0/5] gitweb: Improve search code","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-06-22T18:55:23Z","receivedAt":"2011-06-22T18:55:23Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Looks good. Will queue.\n"},{"id":"170476","messageId":"4E024170.6000407@cisco.com","threadId":"27689","inReplyTo":"201106222000.04854.jnareb@gmail.com","subject":"Re: [PATCH 0/5] gitweb: Improve search code","fromName":"Phil Hord","fromEmail":"hordp@cisco.com","sentAt":"2011-06-22T19:24:32Z","receivedAt":"2011-06-22T19:24:32Z","isPatch":true,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"\nOn 06/22/2011 02:00 PM, Jakub Narebski wrote:\n> On Wed, 22 Jun 2011, Phil Hord wrote:\n>> On 06/22/2011 11:28 AM, Jakub Narebski wrote:\n>>> P.S. Another addition that I sometimes wanted git to have would be\n>                                                   ^^^\n>\n> This is a typo: I actually wanted to say \"gitweb\" here.\n>\n> Therefore this discussion is totally OFF-TOPIC now.\nDang.\n\n>> I normally revert to 'git log --name-status | less <CR> /filename.foo',\n>> which is awful, of course.  I've always assumed there's a better way I\n>> haven't discovered yet.  But if there is, well... I haven't discovered\n>> it yet.\n>>\n>> This syntax works on some files, but is limited and/or broken:\n>>    # Finds all commits touching the file named './foo.bar', iff\n>> ./foo.bar exists in the current commit.\n>>    git log -- foo.bar\n> Errr... if you use \"git log foo.bar\" it is true, but \"git log -- foo.bar\"\n> will find commits even if foo.bar existed only in the past... though\n> history simplification can make git return empty set.\n\nThat doesn't work for me.  Does it work for you?  I only see the\ngitweb.pl history if I include --full-history.\n\n    git version\n    #-- git version 1.7.5.rc1\n\n    git log -- gitweb.pl | wc\n    #--   0       0       0\n\n    git log --full-history -- gitweb.pl | wc\n    #--    175     412    4087\n\n\n>> I say 'broken', but maybe it's not; it feels like it is when I do this:\n>>\n>>    # Returns zero logs\n>>    git log -- some-deleted-file.txt\n>>\n>>    # Returns at least two logs\n>>    git log --all -- some-deleted-file.txt\n>      git log --full-history -- some-deleted-file.txt\n>\n\nThanks very much.  That is exactly what I was missing.\n\nI obviously didn't know about --full-history.  I didn't notice it in\nspite of looking for this before and consulting 'git help log'.  So I'm\nguessing the documentation could use some help there.  It's already\npretty crowded, though.  Maybe just a note next to '--all' which, for\nme, served as a distractingly red herring.\n\n> For example in git.git repository:\n>\n>    $ # git log --full-history --oneline -- gitweb.pl | cat\n>    2ad9331 v053\n>    185f09e v049\n>    ff7669a v048\n>    fbb592a v043\n>    [...]\n>    e0389bd v001\n>    ecb378f v000\n>    4c02e3c v000\n>    161332a first working version\n>\n> (Don't you just love Kay Sievers commit messages ;-) ?).\n>\n>> I think I understand why that happens (search optimization), but it is\n>> unexpected from the user's perspective.  I also suspect it will miss the\n>> 'pre-resurrection' commits for files which were deleted and resurrected\n>> in the past.\n>>\n>>\n>> What do you think of these as new 'Commit limiters' for git log:\n>>\n>>        --name=<pattern>, --name-glob=<glob>\n>>            Limit the commits output to ones touching files that match the\n>>            specified pattern (regular expression) or glob (shell glob\n>>            pattern).\n> Why not use \"git log --full-history -- '<glob>'\" (i.e. remember about\n> shell escaping glob)?  I don't know if it works as intended in current\n> git or not...\n>\n\nI think that'll work fine.  But glob paths failed for me when I tried it\nwhile composing the original email.  I think I just mis-interpreted the\nreason for the missing commits when I didn't have --full-history.\n\nAlso, globbing is not mentioned in the '[--] <path>' section of 'git log\n--help'.  In fact, the only references to globs in the 'git log' help\n[1] are related to refs, not filenames.  Ditto for 'git rev-list'.\n\nI initially expected \"git log -- 'foo.*'\" to work.  But it didn't (foo.*\nhad been deleted) or it only partially worked (no --full-history).  So I\ninterpreted this as it being only partially supported.  I did consult\nthe man page, but it did not do anything to correct my wrong\ninterpretation.  A now-enwisened google search turned up a thread [2]\nfrom 2009 apparently pre-dating this feature.\n\nThanks again for the education, Jakub.  I really appreciate how helpful\nthis list is.\n\n[1] excepting '-O'\n[2] http://article.gmane.org/gmane.comp.version-control.git/109506/\n\n\nPhil\n"}]}