Merge branch 'master' of git://repo.or.cz/git-gui
[gitweb.git] / gitweb / gitweb.perl
index aee4f239ae2e75d1eed2ebbb926145aa57be5936..a6383dc85b99ead405e1961888d06bb8ff8f3931 100755 (executable)
@@ -1058,25 +1058,51 @@ sub format_extended_diff_header_line {
 
 # format from-file/to-file diff header
 sub format_diff_from_to_header {
-       my ($from_line, $to_line, $diffinfo, $from, $to) = @_;
+       my ($from_line, $to_line, $diffinfo, $from, $to, @parents) = @_;
        my $line;
        my $result = '';
 
        $line = $from_line;
        #assert($line =~ m/^---/) if DEBUG;
-       # no extra formatting "^--- /dev/null"
-       if ($line =~ m!^--- "?a/!) {
-               if (!$diffinfo->{'nparents'} && # multiple 'from'
-                   $from->{'href'}) {
-                       $line = '--- a/' .
-                               $cgi->a({-href=>$from->{'href'}, -class=>"path"},
-                                       esc_path($from->{'file'}));
-               } else {
-                       $line = '--- a/' .
-                               esc_path($from->{'file'});
+       # no extra formatting for "^--- /dev/null"
+       if (! $diffinfo->{'nparents'}) {
+               # ordinary (single parent) diff
+               if ($line =~ m!^--- "?a/!) {
+                       if ($from->{'href'}) {
+                               $line = '--- a/' .
+                                       $cgi->a({-href=>$from->{'href'}, -class=>"path"},
+                                               esc_path($from->{'file'}));
+                       } else {
+                               $line = '--- a/' .
+                                       esc_path($from->{'file'});
+                       }
+               }
+               $result .= qq!<div class="diff from_file">$line</div>\n!;
+
+       } else {
+               # combined diff (merge commit)
+               for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
+                       if ($from->{'href'}[$i]) {
+                               $line = '--- ' .
+                                       $cgi->a({-href=>href(action=>"blobdiff",
+                                                            hash_parent=>$diffinfo->{'from_id'}[$i],
+                                                            hash_parent_base=>$parents[$i],
+                                                            file_parent=>$from->{'file'}[$i],
+                                                            hash=>$diffinfo->{'to_id'},
+                                                            hash_base=>$hash,
+                                                            file_name=>$to->{'file'}),
+                                                -class=>"path",
+                                                -title=>"diff" . ($i+1)},
+                                               $i+1) .
+                                       '/' .
+                                       $cgi->a({-href=>$from->{'href'}[$i], -class=>"path"},
+                                               esc_path($from->{'file'}[$i]));
+                       } else {
+                               $line = '--- /dev/null';
+                       }
+                       $result .= qq!<div class="diff from_file">$line</div>\n!;
                }
        }
-       $result .= qq!<div class="diff from_file">$line</div>\n!;
 
        $line = $to_line;
        #assert($line =~ m/^\+\+\+/) if DEBUG;
@@ -1096,6 +1122,31 @@ sub format_diff_from_to_header {
        return $result;
 }
 
+# create note for patch simplified by combined diff
+sub format_diff_cc_simplified {
+       my ($diffinfo, @parents) = @_;
+       my $result = '';
+
+       $result .= "<div class=\"diff header\">" .
+                  "diff --cc ";
+       if (!is_deleted($diffinfo)) {
+               $result .= $cgi->a({-href => href(action=>"blob",
+                                                 hash_base=>$hash,
+                                                 hash=>$diffinfo->{'to_id'},
+                                                 file_name=>$diffinfo->{'to_file'}),
+                                   -class => "path"},
+                                  esc_path($diffinfo->{'to_file'}));
+       } else {
+               $result .= esc_path($diffinfo->{'to_file'});
+       }
+       $result .= "</div>\n" . # class="diff header"
+                  "<div class=\"diff nodifferences\">" .
+                  "Simple merge" .
+                  "</div>\n"; # class="diff nodifferences"
+
+       return $result;
+}
+
 # format patch (diff) line (not to be used for diff headers)
 sub format_diff_line {
        my $line = shift;
@@ -2947,13 +2998,33 @@ sub git_patchset_body {
                        # advance raw git-diff output if needed
                        $patch_idx++ if defined $diffinfo;
 
-                       # read and prepare patch information
-                       if (ref($difftree->[$patch_idx]) eq "HASH") {
-                               # pre-parsed (or generated by hand)
-                               $diffinfo = $difftree->[$patch_idx];
-                       } else {
-                               $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
+                       # compact combined diff output can have some patches skipped
+                       # find which patch (using pathname of result) we are at now
+                       my $to_name;
+                       if ($diff_header[0] =~ m!^diff --cc "?(.*)"?$!) {
+                               $to_name = $1;
                        }
+
+                       do {
+                               # read and prepare patch information
+                               if (ref($difftree->[$patch_idx]) eq "HASH") {
+                                       # pre-parsed (or generated by hand)
+                                       $diffinfo = $difftree->[$patch_idx];
+                               } else {
+                                       $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
+                               }
+
+                               # check if current raw line has no patch (it got simplified)
+                               if (defined $to_name && $to_name ne $diffinfo->{'to_file'}) {
+                                       print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
+                                             format_diff_cc_simplified($diffinfo, @hash_parents) .
+                                             "</div>\n";  # class="patch"
+
+                                       $patch_idx++;
+                                       $patch_number++;
+                               }
+                       } until (!defined $to_name || $to_name eq $diffinfo->{'to_file'} ||
+                                $patch_idx > $#$difftree);
                        # modifies %from, %to hashes
                        parse_from_to_diffinfo($diffinfo, \%from, \%to, @hash_parents);
                        if ($diffinfo->{'nparents'}) {
@@ -3026,7 +3097,8 @@ sub git_patchset_body {
                #assert($patch_line =~ m/^\+\+\+/) if DEBUG;
 
                print format_diff_from_to_header($last_patch_line, $patch_line,
-                                                $diffinfo, \%from, \%to);
+                                                $diffinfo, \%from, \%to,
+                                                @hash_parents);
 
                # the patch itself
        LINE:
@@ -3042,6 +3114,27 @@ sub git_patchset_body {
                print "</div>\n"; # class="patch"
        }
 
+       # for compact combined (--cc) format, with chunk and patch simpliciaction
+       # patchset might be empty, but there might be unprocessed raw lines
+       for ($patch_idx++ if $patch_number > 0;
+            $patch_idx < @$difftree;
+            $patch_idx++) {
+               # read and prepare patch information
+               if (ref($difftree->[$patch_idx]) eq "HASH") {
+                       # pre-parsed (or generated by hand)
+                       $diffinfo = $difftree->[$patch_idx];
+               } else {
+                       $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
+               }
+
+               # generate anchor for "patch" links in difftree / whatchanged part
+               print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
+                     format_diff_cc_simplified($diffinfo, @hash_parents) .
+                     "</div>\n";  # class="patch"
+
+               $patch_number++;
+       }
+
        if ($patch_number == 0) {
                if (@hash_parents > 1) {
                        print "<div class=\"diff nodifferences\">Trivial merge</div>\n";
@@ -4555,7 +4648,11 @@ sub git_commitdiff {
                die_error(undef, "Unknown commit object");
        }
 
-       # we need to prepare $formats_nav before any parameter munging
+       # choose format for commitdiff for merge
+       if (! defined $hash_parent && @{$co{'parents'}} > 1) {
+               $hash_parent = '--cc';
+       }
+       # we need to prepare $formats_nav before almost any parameter munging
        my $formats_nav;
        if ($format eq 'html') {
                $formats_nav =
@@ -4563,7 +4660,8 @@ sub git_commitdiff {
                                               hash=>$hash, hash_parent=>$hash_parent)},
                                "raw");
 
-               if (defined $hash_parent) {
+               if (defined $hash_parent &&
+                   $hash_parent ne '-c' && $hash_parent ne '--cc') {
                        # commitdiff with two commits given
                        my $hash_parent_short = $hash_parent;
                        if ($hash_parent =~ m/^[0-9a-fA-F]{40}$/) {
@@ -4595,6 +4693,17 @@ sub git_commitdiff {
                                ')';
                } else {
                        # merge commit
+                       if ($hash_parent eq '--cc') {
+                               $formats_nav .= ' | ' .
+                                       $cgi->a({-href => href(action=>"commitdiff",
+                                                              hash=>$hash, hash_parent=>'-c')},
+                                               'combined');
+                       } else { # $hash_parent eq '-c'
+                               $formats_nav .= ' | ' .
+                                       $cgi->a({-href => href(action=>"commitdiff",
+                                                              hash=>$hash, hash_parent=>'--cc')},
+                                               'compact');
+                       }
                        $formats_nav .=
                                ' (merge: ' .
                                join(' ', map {
@@ -4607,9 +4716,10 @@ sub git_commitdiff {
        }
 
        my $hash_parent_param = $hash_parent;
-       if (!defined $hash_parent) {
+       if (!defined $hash_parent_param) {
+               # --cc for multiple parents, --root for parentless
                $hash_parent_param =
-                       @{$co{'parents'}} > 1 ? '-c' : $co{'parent'} || '--root';
+                       @{$co{'parents'}} > 1 ? '--cc' : $co{'parent'} || '--root';
        }
 
        # read commitdiff
@@ -4686,10 +4796,14 @@ sub git_commitdiff {
 
        # write patch
        if ($format eq 'html') {
-               git_difftree_body(\@difftree, $hash, $hash_parent || @{$co{'parents'}});
+               my $use_parents = !defined $hash_parent ||
+                       $hash_parent eq '-c' || $hash_parent eq '--cc';
+               git_difftree_body(\@difftree, $hash,
+                                 $use_parents ? @{$co{'parents'}} : $hash_parent);
                print "<br/>\n";
 
-               git_patchset_body($fd, \@difftree, $hash, $hash_parent || @{$co{'parents'}});
+               git_patchset_body($fd, \@difftree, $hash,
+                                 $use_parents ? @{$co{'parents'}} : $hash_parent);
                close $fd;
                print "</div>\n"; # class="page_body"
                git_footer_html();