{"thread":{"id":"8007","subject":"[PATCH 0/6] gitweb: Add combined diff support","startedAt":"2007-05-06T23:10:02Z","lastAt":"2007-05-16T22:08:24Z","messageCount":12,"participants":["Jakub Narebski","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"41260","messageId":"11784930091585-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":null,"subject":"[PATCH 0/6] gitweb: Add combined diff support","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:02Z","receivedAt":"2007-05-06T23:10:02Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"This series of patches adds support for showing combined diff for\nmerge commits in gitweb, instead of using diff with the first parent\n(for 'commitdiff' view), or not showing difftree (for 'commit' view).\n\nWe use diff -c (diff --combined) and not diff --cc; the latter would\nrequire modifying git_difftree_body and git_patchset_body for the\npossibility that there is line in raw diff output format (in difftree)\nthat doesn't correspond to any patch: the patch part was removed due\nto hunks simplification.\n\nSee also notes in individual patches.\n\n\nDiffstat:\n=========\n\n gitweb/gitweb.css  |   17 ++\n gitweb/gitweb.perl |  480 +++++++++++++++++++++++++++++++++++++++++-----------\n 2 files changed, 394 insertions(+), 103 deletions(-)\n\n\nTable of contents:\n==================\n\n [PATCH 1/6] gitweb: Add parsing of raw combined diff format to parse_difftree_raw_line\n [PATCH 2/6] gitweb: Add combined diff support to git_difftree_body\n [PATCH 3/6] gitweb: Add combined diff support to git_patchset_body\n [PATCH 4/6] gitweb: Make it possible to use pre-parsed info in git_difftree_body\n\nThose patches prepare for adding support for combined diff for\n'commitdiff' and 'commit' views.\n\n\n [PATCH 5/6] gitweb: Show combined diff for merge commits in 'commitdiff' view\n [PATCH 6/6] gitweb: Show combined diff for merge commits in 'commit' view\n\nThose patches add (preliminary) generating combined diff for merge\ncommits for 'commitdiff' view (if there was not provided commit to\ncompare againts), and for 'commit' view.\n\n\n [PATCH 7/6] todo: todo: Remove \"Gitweb diff on merge commits\" entry\n\nThis patch updates TODO list in 'todo' branch.\n\n-- \nJakub Narebski\n"},{"id":"41261","messageId":"11784930111140-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 1/6] gitweb: Add parsing of raw combined diff format to parse_difftree_raw_line","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:03Z","receivedAt":"2007-05-06T23:10:03Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Add parsing line of raw combined diff (\"git diff-tree -c/-cc\" output)\nas described in section \"diff format for merges\" in diff-format.txt\nto parse_difftree_raw_line subroutine.\n\nReturned hash (or hashref) has for combined diff 'nparents' key which\nholds number of parents in a merge. At keys 'from_mode' and 'from_id'\nthere are arrayrefs holding modes and ids, respectively. There is no\n'similarity' value, and there is only 'to_file' value and no\n'from_file' value.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\n gitweb/gitweb.perl |   11 +++++++++++\n 1 files changed, 11 insertions(+), 0 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex ba5cc43..dfba399 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -1495,6 +1495,17 @@ sub parse_difftree_raw_line {\n \t\t\t$res{'file'} = unquote($7);\n \t\t}\n \t}\n+\t# '::100755 100755 100755 60e79ca1b01bc8b057abe17ddab484699a7f5fdb 94067cc5f73388f33722d52ae02f44692bc07490 94067cc5f73388f33722d52ae02f44692bc07490 MR\tgit-gui/git-gui.sh'\n+\t# combined diff (for merge commit)\n+\telsif ($line =~ s/^(::+)((?:[0-7]{6} )+)((?:[0-9a-fA-F]{40} )+)([a-zA-Z]+)\\t(.*)$//) {\n+\t\t$res{'nparents'}  = length($1);\n+\t\t$res{'from_mode'} = [ split(' ', $2) ];\n+\t\t$res{'to_mode'} = pop @{$res{'from_mode'}};\n+\t\t$res{'from_id'} = [ split(' ', $3) ];\n+\t\t$res{'to_id'} = pop @{$res{'from_id'}};\n+\t\t$res{'status'} = [ split('', $4) ];\n+\t\t$res{'to_file'} = unquote($5);\n+\t}\n \t# 'c512b523472485aef4fff9e57b229d9d243c967f'\n \telsif ($line =~ m/^([0-9a-fA-F]{40})$/) {\n \t\t$res{'commit'} = $1;\n-- \n1.5.1.3\n"},{"id":"41262","messageId":"11784930112401-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 2/6] gitweb: Add combined diff support to git_difftree_body","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:04Z","receivedAt":"2007-05-06T23:10:04Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"You have to pass all parents as final parameters of git_difftree_body\nsubroutine; the number of parents of a diff must be equal to the\nnumber derived from parsing git-diff-tree output, raw combined diff\nfor git_difftree_body to display combined diff correctly (but it is\nnot checked).\n\nCurrently the possibility of displaying diffree of combined diff is\nnot used in gitweb code; git_difftree_body is always caled for\nordinary diff, and with only one parent.\n\n\nDescription of output for combined diff:\n----------------------------------------\n\nThe difftree table for combined diff starts with a cell with pathname\nof changed blob (changed file), which if possible is hidden link\n(class=\"list\") to the 'blob' view of final version (if it exists),\nlike for difftree for ordinary diff. If file was deleted in the final\ncommit then filename is not hyperlinked.\n\nThere is no cell with single file status (new, deleted, mode change,\nrename), as for combined diff as there is no single status: different\nparents might have different status.\n\nIf git_difftree_body was called from git_commitdiff (for 'commitdiff'\naction) there is inner link to anchor to appropriate fragment (patch)\nin patchset body; the \"patch\" link does not replace \"diff\" link like\nfor ordinary diff.\n\nEach of \"diff\" links is in separate cell, contrary to output for\nordinary diff in which all links are (at least for now) in a single\ncell.\n\nFor each parent, if file was not present we leave cell empty. If file\nwas deleted in the result, we provide link to 'blob' view. Otherwise\nwe provide link to 'commitdiff' view, even if patch (diff) consist\nonly of extended diff header, and contents is not changed (pure\nrename, pure mode change). The only difference is that link to\n\"blobdiff\" view with no contents change is with 'nochange' class.\n\nAt last, there is provided link to current version of file as \"blob\"\nlink, if the file was not deleted in the result, and lik to history of\na file, if there exists one. (The link to file history might be\nconfused, at least for now, by renames.)\n\nNote that git-diff-tree raw output dor combined diff does not provide\nfilename before change for renames and copies; we use\ngit_get_path_by_hash to get \"src\" filename for renames (this means\nadditional call to git-ls-tree for a _whole_ tree).\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nCurrently the work to find filename _before_ rename for renames (and\ncopies) in combined diff is done during difftree generation (link\ngeneration). It is possible to change it to have this calculation done\non link target, in 'blobdiff' and 'blob' views which lack 'fp' or 'f'\nparameter, and have 'hpb' and 'hp' or 'hb' and 'h' parameters needed\nto find path by hash. Nevertheless renames in combined diff format are\nrare I think, and non-empty combined diff for merge commit\n(non-trivial merge result) is also usually rare.\n\n[The above paragraph should perhaps be added to commit message, but is\nquite long even without it.]\n\n\nThis is preliminary version: difftree output for combined diff is a\nbit crude, and does not display all the information (mode changes,\nrenames, etc.). Nevertheless I think it is a good start.\n\nCSS styling is a bit crude.\n\nPatches (or corrections) and ideas how should HTML output of difftree\n(whatchanged-like output) for combined diff look like are very\nwelcome.\n\n gitweb/gitweb.css  |   17 +++++++\n gitweb/gitweb.perl |  121 +++++++++++++++++++++++++++++++++++++++++++++++++++-\n 2 files changed, 136 insertions(+), 2 deletions(-)\n\ndiff --git a/gitweb/gitweb.css b/gitweb/gitweb.css\nindex 2b023bd..e795b70 100644\n--- a/gitweb/gitweb.css\n+++ b/gitweb/gitweb.css\n@@ -181,6 +181,23 @@ table.diff_tree {\n \tfont-family: monospace;\n }\n \n+table.combined.diff_tree td {\n+\tpadding-right: 24px;\n+}\n+\n+table.combined.diff_tree td.link {\n+\tpadding: 0px 2px;\n+}\n+\n+table.combined.diff_tree td.nochange a {\n+\tcolor: #6666ff;\n+}\n+\n+table.combined.diff_tree td.nochange a:hover,\n+table.combined.diff_tree td.nochange a:visited {\n+\tcolor: #d06666;\n+}\n+\n table.blame {\n \tborder-collapse: collapse;\n }\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex dfba399..c6a2fef 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -1015,6 +1015,30 @@ sub git_get_hash_by_path {\n \treturn $3;\n }\n \n+# get path of entry with given hash at given tree-ish (ref)\n+# used to get 'from' filename for combined diff (merge commit) for renames\n+sub git_get_path_by_hash {\n+\tmy $base = shift || return;\n+\tmy $hash = shift || return;\n+\n+\tlocal $/ = \"\\0\";\n+\n+\topen my $fd, \"-|\", git_cmd(), \"ls-tree\", '-r', '-t', '-z', $base\n+\t\tor return undef;\n+\twhile (my $line = <$fd>) {\n+\t\tchomp $line;\n+\n+\t\t#'040000 tree 595596a6a9117ddba9fe379b6b012b558bac8423\tgitweb'\n+\t\t#'100644 blob e02e90f0429be0d2a69b76571101f20b8f75530f\tgitweb/README'\n+\t\tif ($line =~ m/(?:[0-9]+) (?:.+) $hash\\t(.+)$/) {\n+\t\t\tclose $fd;\n+\t\t\treturn $1;\n+\t\t}\n+\t}\n+\tclose $fd;\n+\treturn undef;\n+}\n+\n ## ......................................................................\n ## git utility functions, directly accessing git repository\n \n@@ -2210,7 +2234,8 @@ sub git_print_tree_entry {\n ## functions printing large fragments of HTML\n \n sub git_difftree_body {\n-\tmy ($difftree, $hash, $parent) = @_;\n+\tmy ($difftree, $hash, @parents) = @_;\n+\tmy ($parent) = $parents[0];\n \tmy ($have_blame) = gitweb_check_feature('blame');\n \tprint \"<div class=\\\"list_head\\\">\\n\";\n \tif ($#{$difftree} > 10) {\n@@ -2218,7 +2243,9 @@ sub git_difftree_body {\n \t}\n \tprint \"</div>\\n\";\n \n-\tprint \"<table class=\\\"diff_tree\\\">\\n\";\n+\tprint \"<table class=\\\"\" .\n+\t      (@parents > 1 ? \"combined \" : \"\") .\n+\t      \"diff_tree\\\">\\n\";\n \tmy $alternate = 1;\n \tmy $patchno = 0;\n \tforeach my $line (@{$difftree}) {\n@@ -2231,6 +2258,96 @@ sub git_difftree_body {\n \t\t}\n \t\t$alternate ^= 1;\n \n+\t\tif (exists $diff{'nparents'}) { # combined diff\n+\n+\t\t\tif ($diff{'to_id'} ne ('0' x 40)) {\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                             hash_base=>$hash),\n+\t\t\t\t              -class => \"list\"}, esc_path($diff{'to_file'})) .\n+\t\t\t\t      \"</td>\\n\";\n+\t\t\t} else {\n+\t\t\t\tprint \"<td>\" .\n+\t\t\t\t      esc_path($diff{'to_file'}) .\n+\t\t\t\t      \"</td>\\n\";\n+\t\t\t}\n+\n+\t\t\tif ($action eq 'commitdiff') {\n+\t\t\t\t# link to patch\n+\t\t\t\t$patchno++;\n+\t\t\t\tprint \"<td class=\\\"link\\\">\" .\n+\t\t\t\t      $cgi->a({-href => \"#patch$patchno\"}, \"patch\") .\n+\t\t\t\t      \" | \" .\n+\t\t\t\t      \"</td>\\n\";\n+\t\t\t}\n+\n+\t\t\tmy $has_history = 0;\n+\t\t\tmy $not_deleted = 0;\n+\t\t\tfor (my $i = 0; $i < $diff{'nparents'}; $i++) {\n+\t\t\t\tmy $hash_parent = $parents[$i];\n+\t\t\t\tmy $from_hash = $diff{'from_id'}[$i];\n+\t\t\t\tmy $from_path = undef;\n+\t\t\t\tmy $status = $diff{'status'}[$i];\n+\n+\t\t\t\t$has_history ||= ($status ne 'A');\n+\t\t\t\t$not_deleted ||= ($status ne 'D');\n+\n+\t\t\t\tif ($status eq 'R' || $status eq 'C') {\n+\t\t\t\t\t$from_path = git_get_path_by_hash($hash_parent, $from_hash);\n+\t\t\t\t}\n+\n+\t\t\t\tif ($status eq 'A') {\n+\t\t\t\t\tprint \"<td  class=\\\"link\\\" align=\\\"right\\\"> | </td>\\n\";\n+\t\t\t\t} elsif ($status eq 'D') {\n+\t\t\t\t\tprint \"<td class=\\\"link\\\">\" .\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              \"blob\" . ($i+1)) .\n+\t\t\t\t\t      \" | </td>\\n\";\n+\t\t\t\t} else {\n+\t\t\t\t\tif ($diff{'to_id'} eq $from_hash) {\n+\t\t\t\t\t\tprint \"<td class=\\\"link nochange\\\">\";\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\tprint \"<td class=\\\"link\\\">\";\n+\t\t\t\t\t}\n+\t\t\t\t\tprint $cgi->a({-href => href(action=>\"blobdiff\",\n+\t\t\t\t\t                             hash=>$diff{'to_id'},\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              \"diff\" . ($i+1)) .\n+\t\t\t\t\t      \" | </td>\\n\";\n+\t\t\t\t}\n+\t\t\t}\n+\n+\t\t\tprint \"<td class=\\\"link\\\">\";\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                             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                             hash_base=>$hash)},\n+\t\t\t\t              \"history\");\n+\t\t\t}\n+\t\t\tprint \"</td>\\n\";\n+\n+\t\t\tprint \"</tr>\\n\";\n+\t\t\tnext; # instead of 'else' clause, to avoid extra indent\n+\t\t}\n+\t\t# else ordinary diff\n+\n \t\tmy ($to_mode_oct, $to_mode_str, $to_file_type);\n \t\tmy ($from_mode_oct, $from_mode_str, $from_file_type);\n \t\tif ($diff{'to_mode'} ne ('0' x 6)) {\n-- \n1.5.1.3\n"},{"id":"41263","messageId":"11784930121052-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 3/6] gitweb: Add combined diff support to git_patchset_body","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:05Z","receivedAt":"2007-05-06T23:10:05Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Calling convention for combined diff similar to the one for\ngit_difftree_body subroutine: difftree info (first parameter) must be\nresult of calling git-diff-tree with -c/--cc option, and all parents\nof a commit must be passed as last parameters. See also description in\n  \"gitweb: Add combined diff support to git_difftree_body\"\n\nThis ability is not used yet.\n\nGenerating \"src\" file name for renames in combined diff was separated\ninto fill_from_file_info subroutine; git_difftree_body was modified to\nuse it. Currently git_difftree_body and git_patchset_body fills this\ninfo separately.\n\nThe from-file line in two-line from-file/to-file header is not\nhyperlinked: there can be more than one \"from\"/\"src\" file. This\ndiffers from HTML output of ordinary (not combined) diff.\n\nformat_diff_line subroutine needs extra $from/$to parameters to format\ncombined diff patch line correctly.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nCurrently the following extended git diff header line in combined diff\n\n\tnew file mode <mode>\n\ngets its <mode> (filetype) explained like for appropriate extended\nheader lines for non-combined (ordinary) diff\n\n\told mode <mode>\n\tnew mode <mode>\n\tdeleted file mode <mode>\n\tnew file mode <mode>\n\tindex <hash>..<hash> <mode>\n\nwhile similar line\n\n\tdeleted file mode <mode>,<mode>\n\ndoes not get <mode> explained. Perhaps we should remove this addition,\nor make explanation using tooltip (and perhaps <abbr> HTML element).\n\n gitweb/gitweb.perl |  221 ++++++++++++++++++++++++++++++++++++++++++----------\n 1 files changed, 181 insertions(+), 40 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex c6a2fef..53ae0b8 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -897,19 +897,34 @@ sub format_subject_html {\n sub format_diff_line {\n \tmy $line = shift;\n \tmy ($from, $to) = @_;\n-\tmy $char = substr($line, 0, 1);\n \tmy $diff_class = \"\";\n \n \tchomp $line;\n \n-\tif ($char eq '+') {\n-\t\t$diff_class = \" add\";\n-\t} elsif ($char eq \"-\") {\n-\t\t$diff_class = \" rem\";\n-\t} elsif ($char eq \"@\") {\n-\t\t$diff_class = \" chunk_header\";\n-\t} elsif ($char eq \"\\\\\") {\n-\t\t$diff_class = \" incomplete\";\n+\tif ($from && $to && ref($from->{'href'}) eq \"ARRAY\") {\n+\t\t# combined diff\n+\t\tmy $prefix = substr($line, 0, scalar @{$from->{'href'}});\n+\t\tif ($line =~ m/^\\@{3}/) {\n+\t\t\t$diff_class = \" chunk_header\";\n+\t\t} elsif ($line =~ m/^\\\\/) {\n+\t\t\t$diff_class = \" incomplete\";\n+\t\t} elsif ($prefix =~ tr/+/+/) {\n+\t\t\t$diff_class = \" add\";\n+\t\t} elsif ($prefix =~ tr/-/-/) {\n+\t\t\t$diff_class = \" rem\";\n+\t\t}\n+\t} else {\n+\t\t# assume ordinary diff\n+\t\tmy $char = substr($line, 0, 1);\n+\t\tif ($char eq '+') {\n+\t\t\t$diff_class = \" add\";\n+\t\t} elsif ($char eq '-') {\n+\t\t\t$diff_class = \" rem\";\n+\t\t} elsif ($char eq '@') {\n+\t\t\t$diff_class = \" chunk_header\";\n+\t\t} elsif ($char eq \"\\\\\") {\n+\t\t\t$diff_class = \" incomplete\";\n+\t\t}\n \t}\n \t$line = untabify($line);\n \tif ($from && $to && $line =~ m/^\\@{2} /) {\n@@ -930,6 +945,39 @@ sub format_diff_line {\n \t\t$line = \"<span class=\\\"chunk_info\\\">@@ $from_text $to_text @@</span>\" .\n \t\t        \"<span class=\\\"section\\\">\" . esc_html($section, -nbsp=>1) . \"</span>\";\n \t\treturn \"<div class=\\\"diff$diff_class\\\">$line</div>\\n\";\n+\t} elsif ($from && $to && $line =~ m/^\\@{3}/) {\n+\t\tmy ($prefix, $ranges, $section) = $line =~ m/^(\\@+) (.*?) \\@+(.*)$/;\n+\t\tmy (@from_text, @from_start, @from_nlines, $to_text, $to_start, $to_nlines);\n+\n+\t\t@from_text = split(' ', $ranges);\n+\t\tfor (my $i = 0; $i < @from_text; ++$i) {\n+\t\t\t($from_start[$i], $from_nlines[$i]) =\n+\t\t\t\t(split(',', substr($from_text[$i], 1)), 0);\n+\t\t}\n+\n+\t\t$to_text   = pop @from_text;\n+\t\t$to_start  = pop @from_start;\n+\t\t$to_nlines = pop @from_nlines;\n+\n+\t\t$line = \"<span class=\\\"chunk_info\\\">$prefix \";\n+\t\tfor (my $i = 0; $i < @from_text; ++$i) {\n+\t\t\tif ($from->{'href'}[$i]) {\n+\t\t\t\t$line .= $cgi->a({-href=>\"$from->{'href'}[$i]#l$from_start[$i]\",\n+\t\t\t\t                  -class=>\"list\"}, $from_text[$i]);\n+\t\t\t} else {\n+\t\t\t\t$line .= $from_text[$i];\n+\t\t\t}\n+\t\t\t$line .= \" \";\n+\t\t}\n+\t\tif ($to->{'href'}) {\n+\t\t\t$line .= $cgi->a({-href=>\"$to->{'href'}#l$to_start\",\n+\t\t\t                  -class=>\"list\"}, $to_text);\n+\t\t} else {\n+\t\t\t$line .= $to_text;\n+\t\t}\n+\t\t$line .= \" $prefix</span>\" .\n+\t\t         \"<span class=\\\"section\\\">\" . esc_html($section, -nbsp=>1) . \"</span>\";\n+\t\treturn \"<div class=\\\"diff$diff_class\\\">$line</div>\\n\";\n \t}\n \treturn \"<div class=\\\"diff$diff_class\\\">\" . esc_html($line, -nbsp=>1) . \"</div>\\n\";\n }\n@@ -2233,6 +2281,39 @@ sub git_print_tree_entry {\n ## ......................................................................\n ## functions printing large fragments of HTML\n \n+sub fill_from_file_info {\n+\tmy ($diff, @parents) = @_;\n+\n+\t$diff->{'from_file'} = [ ];\n+\t$diff->{'from_file'}[$diff->{'nparents'} - 1] = undef;\n+\tfor (my $i = 0; $i < $diff->{'nparents'}; $i++) {\n+\t\tif ($diff->{'status'}[$i] eq 'R' ||\n+\t\t    $diff->{'status'}[$i] eq 'C') {\n+\t\t\t$diff->{'from_file'}[$i] =\n+\t\t\t\tgit_get_path_by_hash($parents[$i], $diff->{'from_id'}[$i]);\n+\t\t}\n+\t}\n+\n+\treturn $diff;\n+}\n+\n+# parameters can be strings, or references to arrays of strings\n+sub from_ids_eq {\n+\tmy ($a, $b) = @_;\n+\n+\tif (ref($a) eq \"ARRAY\" && ref($b) eq \"ARRAY\" && @$a == @$b) {\n+\t\tfor (my $i = 0; $i < @$a; ++$i) {\n+\t\t\treturn 0 unless ($a->[$i] eq $b->[$i]);\n+\t\t}\n+\t\treturn 1;\n+\t} elsif (!ref($a) && !ref($b)) {\n+\t\treturn $a eq $b;\n+\t} else {\n+\t\treturn 0;\n+\t}\n+}\n+\n+\n sub git_difftree_body {\n \tmy ($difftree, $hash, @parents) = @_;\n \tmy ($parent) = $parents[0];\n@@ -2260,6 +2341,8 @@ sub git_difftree_body {\n \n \t\tif (exists $diff{'nparents'}) { # combined diff\n \n+\t\t\tfill_from_file_info(\\%diff, @parents);\n+\n \t\t\tif ($diff{'to_id'} ne ('0' x 40)) {\n \t\t\t\t# file exists in the result (child) commit\n \t\t\t\tprint \"<td>\" .\n@@ -2288,16 +2371,12 @@ sub git_difftree_body {\n \t\t\tfor (my $i = 0; $i < $diff{'nparents'}; $i++) {\n \t\t\t\tmy $hash_parent = $parents[$i];\n \t\t\t\tmy $from_hash = $diff{'from_id'}[$i];\n-\t\t\t\tmy $from_path = undef;\n+\t\t\t\tmy $from_path = $diff{'from_file'}[$i];\n \t\t\t\tmy $status = $diff{'status'}[$i];\n \n \t\t\t\t$has_history ||= ($status ne 'A');\n \t\t\t\t$not_deleted ||= ($status ne 'D');\n \n-\t\t\t\tif ($status eq 'R' || $status eq 'C') {\n-\t\t\t\t\t$from_path = git_get_path_by_hash($hash_parent, $from_hash);\n-\t\t\t\t}\n-\n \t\t\t\tif ($status eq 'A') {\n \t\t\t\t\tprint \"<td  class=\\\"link\\\" align=\\\"right\\\"> | </td>\\n\";\n \t\t\t\t} elsif ($status eq 'D') {\n@@ -2517,7 +2596,8 @@ sub git_difftree_body {\n }\n \n sub git_patchset_body {\n-\tmy ($fd, $difftree, $hash, $hash_parent) = @_;\n+\tmy ($fd, $difftree, $hash, @hash_parents) = @_;\n+\tmy ($hash_parent) = $hash_parents[0];\n \n \tmy $patch_idx = 0;\n \tmy $patch_number = 0;\n@@ -2555,6 +2635,9 @@ sub git_patchset_body {\n \t\t\tif ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {\n \t\t\t\t$from_id = $1;\n \t\t\t\t$to_id   = $2;\n+\t\t\t} elsif ($patch_line =~ m/^index ((?:[0-9a-fA-F]{40},)+[0-9a-fA-F]{40})..([0-9a-fA-F]{40})/) {\n+\t\t\t\t$from_id = [ split(',', $1) ];\n+\t\t\t\t$to_id   = $2;\n \t\t\t}\n \n \t\t\tpush @diff_header, $patch_line;\n@@ -2564,8 +2647,8 @@ sub git_patchset_body {\n \t\t# check if current patch belong to current raw line\n \t\t# and parse raw git-diff line if needed\n \t\tif (defined $diffinfo &&\n-\t\t    $diffinfo->{'from_id'} eq $from_id &&\n-\t\t    $diffinfo->{'to_id'}   eq $to_id) {\n+\t\t    from_ids_eq($diffinfo->{'from_id'}, $from_id) &&\n+\t\t    $diffinfo->{'to_id'} eq $to_id) {\n \t\t\t# this is split patch\n \t\t\tprint \"<div class=\\\"patch cont\\\">\\n\";\n \t\t} else {\n@@ -2579,15 +2662,34 @@ sub git_patchset_body {\n \t\t\t} else {\n \t\t\t\t$diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);\n \t\t\t}\n-\t\t\t$from{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};\n-\t\t\t$to{'file'}   = $diffinfo->{'to_file'}   || $diffinfo->{'file'};\n-\t\t\tif ($diffinfo->{'status'} ne \"A\") { # not new (added) file\n-\t\t\t\t$from{'href'} = href(action=>\"blob\", hash_base=>$hash_parent,\n-\t\t\t\t                     hash=>$diffinfo->{'from_id'},\n-\t\t\t\t                     file_name=>$from{'file'});\n+\t\t\tif ($diffinfo->{'nparents'}) {\n+\t\t\t\t# combined diff\n+\t\t\t\t$from{'file'} = [];\n+\t\t\t\t$from{'href'} = [];\n+\t\t\t\tfill_from_file_info($diffinfo, @hash_parents)\n+\t\t\t\t\tunless exists $diffinfo->{'from_file'};\n+\t\t\t\tfor (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {\n+\t\t\t\t\t$from{'file'}[$i] = $diffinfo->{'from_file'}[$i] || $diffinfo->{'to_file'};\n+\t\t\t\t\tif ($diffinfo->{'status'}[$i] ne \"A\") { # not new (added) file\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} else {\n+\t\t\t\t\t\t$from{'href'}[$i] = undef;\n+\t\t\t\t\t}\n+\t\t\t\t}\n \t\t\t} else {\n-\t\t\t\tdelete $from{'href'};\n+\t\t\t\t$from{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};\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} else {\n+\t\t\t\t\tdelete $from{'href'};\n+\t\t\t\t}\n \t\t\t}\n+\t\t\t$to{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'};\n \t\t\tif ($diffinfo->{'status'} ne \"D\") { # not deleted file\n \t\t\t\t$to{'href'} = href(action=>\"blob\", hash_base=>$hash,\n \t\t\t\t                   hash=>$diffinfo->{'to_id'},\n@@ -2602,19 +2704,34 @@ sub git_patchset_body {\n \n \t\t# print \"git diff\" header\n \t\t$patch_line = shift @diff_header;\n-\t\t$patch_line =~ s!^(diff (.*?) )\"?a/.*$!$1!;\n-\t\tif ($from{'href'}) {\n-\t\t\t$patch_line .= $cgi->a({-href => $from{'href'}, -class => \"path\"},\n-\t\t\t                       'a/' . esc_path($from{'file'}));\n-\t\t} else { # file was added\n-\t\t\t$patch_line .= 'a/' . esc_path($from{'file'});\n-\t\t}\n-\t\t$patch_line .= ' ';\n-\t\tif ($to{'href'}) {\n-\t\t\t$patch_line .= $cgi->a({-href => $to{'href'}, -class => \"path\"},\n-\t\t\t                       'b/' . esc_path($to{'file'}));\n-\t\t} else { # file was deleted\n-\t\t\t$patch_line .= 'b/' . esc_path($to{'file'});\n+\t\tif ($diffinfo->{'nparents'}) {\n+\n+\t\t\t# combined diff\n+\t\t\t$patch_line =~ s!^(diff (.*?) )\"?.*$!$1!;\n+\t\t\tif ($to{'href'}) {\n+\t\t\t\t$patch_line .= $cgi->a({-href => $to{'href'}, -class => \"path\"},\n+\t\t\t\t                       esc_path($to{'file'}));\n+\t\t\t} else { # file was deleted\n+\t\t\t\t$patch_line .= esc_path($to{'file'});\n+\t\t\t}\n+\n+\t\t} else {\n+\n+\t\t\t$patch_line =~ s!^(diff (.*?) )\"?a/.*$!$1!;\n+\t\t\tif ($from{'href'}) {\n+\t\t\t\t$patch_line .= $cgi->a({-href => $from{'href'}, -class => \"path\"},\n+\t\t\t\t                       'a/' . esc_path($from{'file'}));\n+\t\t\t} else { # file was added\n+\t\t\t\t$patch_line .= 'a/' . esc_path($from{'file'});\n+\t\t\t}\n+\t\t\t$patch_line .= ' ';\n+\t\t\tif ($to{'href'}) {\n+\t\t\t\t$patch_line .= $cgi->a({-href => $to{'href'}, -class => \"path\"},\n+\t\t\t\t                       'b/' . esc_path($to{'file'}));\n+\t\t\t} else { # file was deleted\n+\t\t\t\t$patch_line .= 'b/' . esc_path($to{'file'});\n+\t\t\t}\n+\n \t\t}\n \t\tprint \"<div class=\\\"diff header\\\">$patch_line</div>\\n\";\n \n@@ -2631,14 +2748,37 @@ sub git_patchset_body {\n \t\t\t\t$patch_line .= $cgi->a({-href=>$to{'href'}, -class=>\"path\"},\n \t\t\t\t                       esc_path($to{'file'}));\n \t\t\t}\n-\t\t\t# match <mode>\n+\t\t\t# match single <mode>\n \t\t\tif ($patch_line =~ m/\\s(\\d{6})$/) {\n \t\t\t\t$patch_line .= '<span class=\"info\"> (' .\n \t\t\t\t               file_type_long($1) .\n \t\t\t\t               ')</span>';\n \t\t\t}\n \t\t\t# match <hash>\n-\t\t\tif ($patch_line =~ m/^index/) {\n+\t\t\tif ($patch_line =~ m/^index [0-9a-fA-F]{40},[0-9a-fA-F]{40}/) {\n+\t\t\t\t# can match only for combined diff\n+\t\t\t\t$patch_line = 'index ';\n+\t\t\t\tfor (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {\n+\t\t\t\t\tif ($from{'href'}[$i]) {\n+\t\t\t\t\t\t$patch_line .= $cgi->a({-href=>$from{'href'}[$i],\n+\t\t\t\t\t\t                        -class=>\"hash\"},\n+\t\t\t\t\t\t                       substr($diffinfo->{'from_id'}[$i],0,7));\n+\t\t\t\t\t} else {\n+\t\t\t\t\t\t$patch_line .= '0' x 7;\n+\t\t\t\t\t}\n+\t\t\t\t\t# separator\n+\t\t\t\t\t$patch_line .= ',' if ($i < $diffinfo->{'nparents'} - 1);\n+\t\t\t\t}\n+\t\t\t\t$patch_line .= '..';\n+\t\t\t\tif ($to{'href'}) {\n+\t\t\t\t\t$patch_line .= $cgi->a({-href=>$to{'href'}, -class=>\"hash\"},\n+\t\t\t\t\t                       substr($diffinfo->{'to_id'},0,7));\n+\t\t\t\t} else {\n+\t\t\t\t\t$patch_line .= '0' x 7;\n+\t\t\t\t}\n+\n+\t\t\t} elsif ($patch_line =~ m/^index [0-9a-fA-F]{40}..[0-9a-fA-F]{40}/) {\n+\t\t\t\t# can match only for ordinary diff\n \t\t\t\tmy ($from_link, $to_link);\n \t\t\t\tif ($from{'href'}) {\n \t\t\t\t\t$from_link = $cgi->a({-href=>$from{'href'}, -class=>\"hash\"},\n@@ -2674,7 +2814,8 @@ sub git_patchset_body {\n \t\t}\n \t\tnext PATCH if ($patch_line =~ m/^diff /);\n \t\t#assert($patch_line =~ m/^---/) if DEBUG;\n-\t\tif ($from{'href'} && $patch_line =~ m!^--- \"?a/!) {\n+\t\tif (!$diffinfo->{'nparents'} && # not from-file line for combined diff\n+\t\t    $from{'href'} && $patch_line =~ m!^--- \"?a/!) {\n \t\t\t$patch_line = '--- a/' .\n \t\t\t              $cgi->a({-href=>$from{'href'}, -class=>\"path\"},\n \t\t\t                      esc_path($from{'file'}));\n-- \n1.5.1.3\n"},{"id":"41266","messageId":"11784930123353-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 4/6] gitweb: Make it possible to use pre-parsed info in git_difftree_body","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:06Z","receivedAt":"2007-05-06T23:10:06Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Make it possible to use pre-parsed, or generated by hand, difftree\ninfo in git_difftree_body, similarly to how was and is it done in\ngit_patchset_body.\n\nUse just introduced feature in git_commitdiff to parse difftree info\n(raw diff output) only once: difftree info is now parsed in\ngit_commitdiff directly, and parsed information is passed to both\ngit_difftree_body and git_patchset_body. (Till now only git_blobdiff\nmade use of git_patchset_body ability to use pre-parsed or hand\ngenerated info.) Additionally this makes rename info for combined diff\nwith renames (or copies) calculated only once in git_difftree_body;\nthe $difftree is modified and git_patchset_body makes use of added\ninfo.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nThis corrects what was mentioned in the preceding commit (patch):\n\n  Generating \"src\" file name for renames in combined diff was separated\n  into fill_from_file_info subroutine; git_difftree_body was modified to\n  use it. Currently git_difftree_body and git_patchset_body fills this\n  info separately.\n\nNow git_difftree_body fills this info, and git_patchset_body uses it\nin the 'commitdiff' view (git_commitdiff subroutine).\n\n gitweb/gitweb.perl |  139 +++++++++++++++++++++++++++-------------------------\n 1 files changed, 73 insertions(+), 66 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 53ae0b8..b3e2e07 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -2330,7 +2330,13 @@ sub git_difftree_body {\n \tmy $alternate = 1;\n \tmy $patchno = 0;\n \tforeach my $line (@{$difftree}) {\n-\t\tmy %diff = parse_difftree_raw_line($line);\n+\t\tmy $diff;\n+\t\tif (ref($line) eq \"HASH\") {\n+\t\t\t# pre-parsed (or generated by hand)\n+\t\t\t$diff = $line;\n+\t\t} else {\n+\t\t\t$diff = parse_difftree_raw_line($line);\n+\t\t}\n \n \t\tif ($alternate) {\n \t\t\tprint \"<tr class=\\\"dark\\\">\\n\";\n@@ -2339,21 +2345,22 @@ sub git_difftree_body {\n \t\t}\n \t\t$alternate ^= 1;\n \n-\t\tif (exists $diff{'nparents'}) { # combined diff\n+\t\tif (exists $diff->{'nparents'}) { # combined diff\n \n-\t\t\tfill_from_file_info(\\%diff, @parents);\n+\t\t\tfill_from_file_info($diff, @parents)\n+\t\t\t\tunless exists $diff->{'from_file'};\n \n-\t\t\tif ($diff{'to_id'} ne ('0' x 40)) {\n+\t\t\tif ($diff->{'to_id'} ne ('0' x 40)) {\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      $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                             hash_base=>$hash),\n-\t\t\t\t              -class => \"list\"}, esc_path($diff{'to_file'})) .\n+\t\t\t\t              -class => \"list\"}, esc_path($diff->{'to_file'})) .\n \t\t\t\t      \"</td>\\n\";\n \t\t\t} else {\n \t\t\t\tprint \"<td>\" .\n-\t\t\t\t      esc_path($diff{'to_file'}) .\n+\t\t\t\t      esc_path($diff->{'to_file'}) .\n \t\t\t\t      \"</td>\\n\";\n \t\t\t}\n \n@@ -2368,11 +2375,11 @@ sub git_difftree_body {\n \n \t\t\tmy $has_history = 0;\n \t\t\tmy $not_deleted = 0;\n-\t\t\tfor (my $i = 0; $i < $diff{'nparents'}; $i++) {\n+\t\t\tfor (my $i = 0; $i < $diff->{'nparents'}; $i++) {\n \t\t\t\tmy $hash_parent = $parents[$i];\n-\t\t\t\tmy $from_hash = $diff{'from_id'}[$i];\n-\t\t\t\tmy $from_path = $diff{'from_file'}[$i];\n-\t\t\t\tmy $status = $diff{'status'}[$i];\n+\t\t\t\tmy $from_hash = $diff->{'from_id'}[$i];\n+\t\t\t\tmy $from_path = $diff->{'from_file'}[$i];\n+\t\t\t\tmy $status = $diff->{'status'}[$i];\n \n \t\t\t\t$has_history ||= ($status ne 'A');\n \t\t\t\t$not_deleted ||= ($status ne 'D');\n@@ -2388,17 +2395,17 @@ sub git_difftree_body {\n \t\t\t\t\t              \"blob\" . ($i+1)) .\n \t\t\t\t\t      \" | </td>\\n\";\n \t\t\t\t} else {\n-\t\t\t\t\tif ($diff{'to_id'} eq $from_hash) {\n+\t\t\t\t\tif ($diff->{'to_id'} eq $from_hash) {\n \t\t\t\t\t\tprint \"<td class=\\\"link nochange\\\">\";\n \t\t\t\t\t} else {\n \t\t\t\t\t\tprint \"<td class=\\\"link\\\">\";\n \t\t\t\t\t}\n \t\t\t\t\tprint $cgi->a({-href => href(action=>\"blobdiff\",\n-\t\t\t\t\t                             hash=>$diff{'to_id'},\n+\t\t\t\t\t                             hash=>$diff->{'to_id'},\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_name=>$diff->{'to_file'},\n \t\t\t\t\t                             file_parent=>$from_path)},\n \t\t\t\t\t              \"diff\" . ($i+1)) .\n \t\t\t\t\t      \" | </td>\\n\";\n@@ -2408,15 +2415,15 @@ sub git_difftree_body {\n \t\t\tprint \"<td class=\\\"link\\\">\";\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                             hash=>$diff->{'to_id'},\n+\t\t\t\t                             file_name=>$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=>$diff->{'to_file'},\n \t\t\t\t                             hash_base=>$hash)},\n \t\t\t\t              \"history\");\n \t\t\t}\n@@ -2429,29 +2436,29 @@ sub git_difftree_body {\n \n \t\tmy ($to_mode_oct, $to_mode_str, $to_file_type);\n \t\tmy ($from_mode_oct, $from_mode_str, $from_file_type);\n-\t\tif ($diff{'to_mode'} ne ('0' x 6)) {\n-\t\t\t$to_mode_oct = oct $diff{'to_mode'};\n+\t\tif ($diff->{'to_mode'} ne ('0' x 6)) {\n+\t\t\t$to_mode_oct = oct $diff->{'to_mode'};\n \t\t\tif (S_ISREG($to_mode_oct)) { # only for regular file\n \t\t\t\t$to_mode_str = sprintf(\"%04o\", $to_mode_oct & 0777); # permission bits\n \t\t\t}\n-\t\t\t$to_file_type = file_type($diff{'to_mode'});\n+\t\t\t$to_file_type = file_type($diff->{'to_mode'});\n \t\t}\n-\t\tif ($diff{'from_mode'} ne ('0' x 6)) {\n-\t\t\t$from_mode_oct = oct $diff{'from_mode'};\n+\t\tif ($diff->{'from_mode'} ne ('0' x 6)) {\n+\t\t\t$from_mode_oct = oct $diff->{'from_mode'};\n \t\t\tif (S_ISREG($to_mode_oct)) { # only for regular file\n \t\t\t\t$from_mode_str = sprintf(\"%04o\", $from_mode_oct & 0777); # permission bits\n \t\t\t}\n-\t\t\t$from_file_type = file_type($diff{'from_mode'});\n+\t\t\t$from_file_type = file_type($diff->{'from_mode'});\n \t\t}\n \n-\t\tif ($diff{'status'} eq \"A\") { # created\n+\t\tif ($diff->{'status'} eq \"A\") { # created\n \t\t\tmy $mode_chng = \"<span class=\\\"file_status new\\\">[new $to_file_type\";\n \t\t\t$mode_chng   .= \" with mode: $to_mode_str\" if $to_mode_str;\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              -class => \"list\"}, esc_path($diff{'file'}));\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              -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chng</td>\\n\";\n \t\t\tprint \"<td class=\\\"link\\\">\";\n@@ -2461,17 +2468,17 @@ sub git_difftree_body {\n \t\t\t\tprint $cgi->a({-href => \"#patch$patchno\"}, \"patch\");\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\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              \"blob\");\n \t\t\tprint \"</td>\\n\";\n \n-\t\t} elsif ($diff{'status'} eq \"D\") { # deleted\n+\t\t} elsif ($diff->{'status'} eq \"D\") { # deleted\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               -class => \"list\"}, esc_path($diff{'file'}));\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               -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chng</td>\\n\";\n \t\t\tprint \"<td class=\\\"link\\\">\";\n@@ -2481,22 +2488,22 @@ sub git_difftree_body {\n \t\t\t\tprint $cgi->a({-href => \"#patch$patchno\"}, \"patch\");\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\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              \"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=>$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=>$diff->{'file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n-\t\t} elsif ($diff{'status'} eq \"M\" || $diff{'status'} eq \"T\") { # modified, or type changed\n+\t\t} elsif ($diff->{'status'} eq \"M\" || $diff->{'status'} eq \"T\") { # modified, or type changed\n \t\t\tmy $mode_chnge = \"\";\n-\t\t\tif ($diff{'from_mode'} != $diff{'to_mode'}) {\n+\t\t\tif ($diff->{'from_mode'} != $diff->{'to_mode'}) {\n \t\t\t\t$mode_chnge = \"<span class=\\\"file_status mode_chnge\\\">[changed\";\n \t\t\t\tif ($from_file_type ne $to_file_type) {\n \t\t\t\t\t$mode_chnge .= \" from $from_file_type to $to_file_type\";\n@@ -2511,9 +2518,9 @@ sub git_difftree_body {\n \t\t\t\t$mode_chnge .= \"]</span>\\n\";\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              -class => \"list\"}, esc_path($diff{'file'}));\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              -class => \"list\"}, esc_path($diff->{'file'}));\n \t\t\tprint \"</td>\\n\";\n \t\t\tprint \"<td>$mode_chnge</td>\\n\";\n \t\t\tprint \"<td class=\\\"link\\\">\";\n@@ -2522,70 +2529,70 @@ sub git_difftree_body {\n \t\t\t\t$patchno++;\n \t\t\t\tprint $cgi->a({-href => \"#patch$patchno\"}, \"patch\") .\n \t\t\t\t      \" | \";\n-\t\t\t} elsif ($diff{'to_id'} ne $diff{'from_id'}) {\n+\t\t\t} elsif ($diff->{'to_id'} ne $diff->{'from_id'}) {\n \t\t\t\t# \"commit\" view and modified file (not onlu mode changed)\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=>$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=>$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\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               \"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=>$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=>$diff->{'file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n-\t\t} elsif ($diff{'status'} eq \"R\" || $diff{'status'} eq \"C\") { # renamed or copied\n+\t\t} elsif ($diff->{'status'} eq \"R\" || $diff->{'status'} eq \"C\") { # renamed or copied\n \t\t\tmy %status_name = ('R' => 'moved', 'C' => 'copied');\n-\t\t\tmy $nstatus = $status_name{$diff{'status'}};\n+\t\t\tmy $nstatus = $status_name{$diff->{'status'}};\n \t\t\tmy $mode_chng = \"\";\n-\t\t\tif ($diff{'from_mode'} != $diff{'to_mode'}) {\n+\t\t\tif ($diff->{'from_mode'} != $diff->{'to_mode'}) {\n \t\t\t\t# mode also for directories, so we cannot use $to_mode_str\n \t\t\t\t$mode_chng = sprintf(\", mode: %04o\", $to_mode_oct & 0777);\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              -class => \"list\"}, esc_path($diff{'to_file'})) . \"</td>\\n\" .\n+\t\t\t                             hash=>$diff->{'to_id'}, file_name=>$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              -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                             hash=>$diff->{'from_id'}, file_name=>$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 \t\t\tif ($action eq 'commitdiff') {\n \t\t\t\t# link to patch\n \t\t\t\t$patchno++;\n \t\t\t\tprint $cgi->a({-href => \"#patch$patchno\"}, \"patch\") .\n \t\t\t\t      \" | \";\n-\t\t\t} elsif ($diff{'to_id'} ne $diff{'from_id'}) {\n+\t\t\t} elsif ($diff->{'to_id'} ne $diff->{'from_id'}) {\n \t\t\t\t# \"commit\" view and modified file (not only pure rename or copy)\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=>$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=>$diff->{'to_file'}, file_parent=>$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\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              \"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=>$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=>$diff->{'to_file'})},\n \t\t\t              \"history\");\n \t\t\tprint \"</td>\\n\";\n \n@@ -4401,7 +4408,7 @@ sub git_commitdiff {\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\tpush @difftree, scalar parse_difftree_raw_line($line);\n \t\t}\n \n \t} elsif ($format eq 'plain') {\n-- \n1.5.1.3\n"},{"id":"41264","messageId":"11784930131751-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 5/6] gitweb: Show combined diff for merge commits in 'commitdiff' view","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:07Z","receivedAt":"2007-05-06T23:10:07Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"When 'commitdiff' action is requested without 'hp' (hash parent)\nparameter, and commit given by 'h' (hash) parameter is merge commit,\nshow merge as combined diff.\n\nEarlier for merge commits without 'hp' parameter diff to first parent\nwas shown.\n\nNote that in compact combined (--cc) format 'uninteresting' hunks\nomission mechanism can make that there is no patch corresponding to\nline in raw format (difftree) output. That is why (at least for now)\nwe use --combined and not --cc format for showing commitdiff for merge\ncommits.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nNote the following fragment of combined diff format description from\ngit-diff-tree(1) man page; note the final sentence\n\n-c::\n        This flag changes the way a merge commit is displayed\n        (which means it is useful only when the command is given\n        one <tree-ish>, or '--stdin').  It shows the differences\n        from each of the parents to the merge result simultaneously\n        instead of showing pairwise diff between a parent and the\n        result one at a time (which is what the '-m' option does).\n        Furthermore, _it lists only files which were modified\n        from all parents_.\n\nThis means that now 'commitdiff' would show empty diff for all trival\n(tree-level) merges, which I think is a majority of merges. Is showing\nempty diff better than diff to first parent for merges, then? Or do we\nneed some way to show from which parent was final version of a file\ntaken?\n\nCurrently there is no way to generate 'commitdiff' view to one of the\nparents by clicking some link directly from 'commitdiff' view: you\nhave to go via 'commit' view (click on commit subject, which functions\nas switch between 'commitdiff' and 'commit' views, then on \"diff\" link\nnext to one of the parents in commit header). Perhaps this can be\nimproved with improving difftree/whatchanged output for combined\ndiff.\n\n gitweb/gitweb.perl |   12 +++++++-----\n 1 files changed, 7 insertions(+), 5 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex b3e2e07..c0e2473 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -4391,8 +4391,10 @@ sub git_commitdiff {\n \t\t}\n \t}\n \n+\tmy $hash_parent_param = $hash_parent;\n \tif (!defined $hash_parent) {\n-\t\t$hash_parent = $co{'parent'} || '--root';\n+\t\t$hash_parent_param =\n+\t\t\t@{$co{'parents'}} > 1 ? '-c' : $co{'parent'} || '--root';\n \t}\n \n \t# read commitdiff\n@@ -4401,7 +4403,7 @@ sub git_commitdiff {\n \tif ($format eq 'html') {\n \t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n \t\t\t\"--no-commit-id\", \"--patch-with-raw\", \"--full-index\",\n-\t\t\t$hash_parent, $hash, \"--\"\n+\t\t\t$hash_parent_param, $hash, \"--\"\n \t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n \n \t\twhile (my $line = <$fd>) {\n@@ -4413,7 +4415,7 @@ sub git_commitdiff {\n \n \t} elsif ($format eq 'plain') {\n \t\topen $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', @diff_opts,\n-\t\t\t'-p', $hash_parent, $hash, \"--\"\n+\t\t\t'-p', $hash_parent_param, $hash, \"--\"\n \t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n \n \t} else {\n@@ -4469,10 +4471,10 @@ TEXT\n \n \t# write patch\n \tif ($format eq 'html') {\n-\t\tgit_difftree_body(\\@difftree, $hash, $hash_parent);\n+\t\tgit_difftree_body(\\@difftree, $hash, $hash_parent || @{$co{'parents'}});\n \t\tprint \"<br/>\\n\";\n \n-\t\tgit_patchset_body($fd, \\@difftree, $hash, $hash_parent);\n+\t\tgit_patchset_body($fd, \\@difftree, $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.1.3\n"},{"id":"41265","messageId":"11784930133424-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 6/6] gitweb: Show combined diff for merge commits in 'commit' view","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:08Z","receivedAt":"2007-05-06T23:10:08Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"When commit shown is a merge commit (has more than one parent),\ndisplay combined difftree output (result of git-diff-tree -c).\nEarlier (since commit 549ab4a30703012ff3a12b5455d319216805a8db)\ndifftree output (against first parent) was not printed for merges.\n\nExamples of non-trivial merges:\n  5bac4a671907604b5fb4e24ff682d5b0e8431931 (includes rename)\n  addafaf92eeb86033da91323d0d3ad7a496dae83 (five parents)\n  95f97567c1887d77f3a46b42d8622c76414d964d (evil merge)\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nThe same note as for the patch before apply: for trivial merges there\nis no difftree output. But for 'commit' view it doesn't matter much\nbecause there was no difftree output at all for merges.\n\nI plan to add HTML diffstat (using divs with set background color and\nset width for bar graph for diff stats) for merges for 'commit' view\n(diffstat to first parent, aka. \"damages\"), and text diffstat for\n'commitdiff_plain' view. It would be controlled by new %feature.\nBut if somebody else want to implement this, feel free.\n\n\nExamples are included to make it possible to check combined diff\noutput in gitweb: the sha1 of commits should be turned into\nhyperlinks (committags support), and you can click on them to go to\n'commit' view.\n\n gitweb/gitweb.perl |   20 ++++++++------------\n 1 files changed, 8 insertions(+), 12 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex c0e2473..53e6dce 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -4026,14 +4026,13 @@ sub git_commit {\n \t\t$parent = \"--root\";\n \t}\n \tmy @difftree;\n-\tif (@$parents <= 1) {\n-\t\t# difftree output is not printed for merges\n-\t\topen my $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', \"--no-commit-id\",\n-\t\t\t@diff_opts, $parent, $hash, \"--\"\n-\t\t\tor die_error(undef, \"Open git-diff-tree failed\");\n-\t\t@difftree = map { chomp; $_ } <$fd>;\n-\t\tclose $fd or die_error(undef, \"Reading git-diff-tree failed\");\n-\t}\n+\topen my $fd, \"-|\", git_cmd(), \"diff-tree\", '-r', \"--no-commit-id\",\n+\t\t@diff_opts, \n+\t\t(@$parents <= 1 ? $parent : '-c'),\n+\t\t$hash, \"--\"\n+\t\tor die_error(undef, \"Open git-diff-tree failed\");\n+\t@difftree = map { chomp; $_ } <$fd>;\n+\tclose $fd or die_error(undef, \"Reading git-diff-tree failed\");\n \n \t# non-textual hash id's can be cached\n \tmy $expires;\n@@ -4111,10 +4110,7 @@ sub git_commit {\n \tgit_print_log($co{'comment'});\n \tprint \"</div>\\n\";\n \n-\tif (@$parents <= 1) {\n-\t\t# do not output difftree/whatchanged for merges\n-\t\tgit_difftree_body(\\@difftree, $hash, $parent);\n-\t}\n+\tgit_difftree_body(\\@difftree, $hash, @$parents);\n \n \tgit_footer_html();\n }\n-- \n1.5.1.3\n"},{"id":"41267","messageId":"1178493013727-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 7/6] todo: Remove \"Gitweb diff on merge commits\" entry","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-06T23:10:09Z","receivedAt":"2007-05-06T23:10:09Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Signed-off-by: Jakub Narebski <jnareb@gmail.com>\n---\nThis patch applies to 'todo' branch!\n\nPerhaps TODO entry should be replaced (updated) to say about format\nof gitweb diff for merge commits (diffstat in HTML, improving difftree\nfor merges), instead of just deleting it.\n\n TODO |   11 -----------\n 1 files changed, 0 insertions(+), 11 deletions(-)\n\ndiff --git a/TODO b/TODO\nindex 6c603db..305363a 100644\n--- a/TODO\n+++ b/TODO\n@@ -85,17 +85,6 @@ the box.\n \n [jc: limbo?]\n \n-* Gitweb diff on merge commits\n-\n-From: Linus Torvalds <torvalds@osdl.org>\n-Subject: Re: git show and gitweb gives different result for kernel\n-Message-ID: <Pine.LNX.4.64.0610061202060.3952@g5.osdl.org>\n-\n-Maybe allow gitweb to show diff with any parent and diff --cc,\n-not just diff with the first parent for a merge.\n-\n-[jc: Jakub is interested in it]\n-\n * Delegate gitweb part to somebody else.\n \n * Use gitattributes for more things.\n-- \n1.5.1.3\n"},{"id":"41378","messageId":"7vvef45cev.fsf@assigned-by-dhcp.cox.net","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"Re: [PATCH 0/6] gitweb: Add combined diff support","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-08T01:31:20Z","receivedAt":"2007-05-08T01:31:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"I've minimally tried this on my private machine.  Looks pretty\nnice for simple merges, but I think we would want --cc not -c\nmost of the time.\n\nPushed out in 'next'.  Thanks.\n"},{"id":"41385","messageId":"200705080350.26061.jnareb@gmail.com","threadId":"8007","inReplyTo":"7vvef45cev.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/6] gitweb: Add combined diff support","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-08T01:50:25Z","receivedAt":"2007-05-08T01:50:25Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Junio C Hamano wrote:\n\n> I've minimally tried this on my private machine.  Looks pretty\n> nice for simple merges, but I think we would want --cc not -c\n> most of the time.\n\nPlease note that --cc would need some changes to both git_difftree_body \nand git_patchset_body; it is not just matter of replacing \n'-c' by '--cc'. Hunk simplification might mean that whole patch \nvanishes. So sometimes we have difftree (raw diff, whatchanged) line \nwhich does not have corresponding patch, and there should be no \"patch\" \nlink (this is harder part). This mean also that in git_patchset_body we \nneed sometimes to skip some difftree line / difftree info line (this is \neasier part).\n\n-- \nJakub Narebski\nPoland\n"},{"id":"42337","messageId":"11793531552023-git-send-email-jnareb@gmail.com","threadId":"8007","inReplyTo":"11784930091585-git-send-email-jnareb@gmail.com","subject":"[PATCH 7/6] gitweb: Empty patch for merge means trivial merge, not no differences","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-16T22:05:55Z","receivedAt":"2007-05-16T22:05:55Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Earlier commit 4280cde95fa4e3fb012eb6d0c239a7777baaf60c made gitweb\nshow \"No differences found\" message for empty diff, for the HTML\noutput. But for merge commits, either -c format we use or --cc format,\nempty diff doesn't mean no differences, but trivial merge.\n\nShow \"Trivial merge\" message instead of \"No differences found\" for\nmerges.\n\nWhile at it reword conditional in the code for easier reading.\n\nSigned-off-by: Jakub Narebski <jnareb@gmail.com>\n---\n gitweb/gitweb.perl |    9 ++++++++-\n 1 files changed, 8 insertions(+), 1 deletions(-)\n\ndiff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl\nindex 549e027..8c688be 100755\n--- a/gitweb/gitweb.perl\n+++ b/gitweb/gitweb.perl\n@@ -2877,7 +2877,14 @@ sub git_patchset_body {\n \t} continue {\n \t\tprint \"</div>\\n\"; # class=\"patch\"\n \t}\n-\tprint \"<div class=\\\"diff nodifferences\\\">No differences found</div>\\n\" if (!$patch_number);\n+\n+\tif ($patch_number == 0) {\n+\t\tif (@hash_parents > 1) {\n+\t\t\tprint \"<div class=\\\"diff nodifferences\\\">Trivial merge</div>\\n\";\n+\t\t} else {\n+\t\t\tprint \"<div class=\\\"diff nodifferences\\\">No differences found</div>\\n\";\n+\t\t}\n+\t}\n \n \tprint \"</div>\\n\"; # class=\"patchset\"\n }\n-- \n1.5.1.4\n"},{"id":"42338","messageId":"7v646se813.fsf@assigned-by-dhcp.cox.net","threadId":"8007","inReplyTo":"11793531552023-git-send-email-jnareb@gmail.com","subject":"Re: [PATCH 7/6] gitweb: Empty patch for merge means trivial merge, not no differences","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-16T22:08:24Z","receivedAt":"2007-05-16T22:08:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jakub Narebski <jnareb@gmail.com> writes:\n\n> Earlier commit 4280cde95fa4e3fb012eb6d0c239a7777baaf60c made gitweb\n> show \"No differences found\" message for empty diff, for the HTML\n> output. But for merge commits, either -c format we use or --cc format,\n> empty diff doesn't mean no differences, but trivial merge.\n>\n> Show \"Trivial merge\" message instead of \"No differences found\" for\n> merges.\n\nSounds good.  Some people might want to treat \"-s ours\" merge\nspecially (in real life, when two branches fix the same bug\ndifferently the result of the hand-resolution may end up being\nthe same as \"-s ours\" merge), although I do not think it is such\na big deal.\n"}]}