git-svn: fix handling of filenames with embedded '@'
[gitweb.git] / combine-diff.c
index b4fa9c9f68bc814bd965db01bbbd7a1d8c2b6664..64b20cce2427fcf0cd9565f5e24efce78abb0088 100644 (file)
@@ -585,12 +585,22 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
        sline->p_lno[i] = sline->p_lno[j];
 }
 
+static void dump_quoted_path(const char *prefix, const char *path)
+{
+       fputs(prefix, stdout);
+       if (quote_c_style(path, NULL, NULL, 0))
+               quote_c_style(path, NULL, stdout, 0);
+       else
+               printf("%s", path);
+       putchar('\n');
+}
+
 static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
                           int dense, struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
        unsigned long result_size, cnt, lno;
-       char *result, *cp, *ep;
+       char *result, *cp;
        struct sline *sline; /* survived lines */
        int mode_differs = 0;
        int i, show_hunks, shown_header = 0;
@@ -598,6 +608,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
        int abbrev = opt->full_index ? 40 : DEFAULT_ABBREV;
        mmfile_t result_file;
 
+       context = opt->context;
        /* Read the result of merge first */
        if (!working_tree_file)
                result = grab_blob(elem->sha1, &result_size);
@@ -642,7 +653,6 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
                cnt++; /* incomplete line */
 
        sline = xcalloc(cnt+2, sizeof(*sline));
-       ep = result;
        sline[0].bol = result;
        for (lno = 0; lno <= cnt + 1; lno++) {
                sline[lno].lost_tail = &sline[lno].lost_head;
@@ -692,12 +702,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
 
                if (rev->loginfo)
                        show_log(rev, rev->loginfo, "\n");
-               printf("diff --%s ", dense ? "cc" : "combined");
-               if (quote_c_style(elem->path, NULL, NULL, 0))
-                       quote_c_style(elem->path, NULL, stdout, 0);
-               else
-                       printf("%s", elem->path);
-               putchar('\n');
+               dump_quoted_path(dense ? "diff --cc " : "diff --combined ", elem->path);
                printf("index ");
                for (i = 0; i < num_parent; i++) {
                        abb = find_unique_abbrev(elem->parent[i].sha1,
@@ -728,6 +733,8 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
                        }
                        putchar('\n');
                }
+               dump_quoted_path("--- a/", elem->path);
+               dump_quoted_path("+++ b/", elem->path);
                dump_sline(sline, cnt, num_parent);
        }
        free(result);
@@ -752,7 +759,7 @@ static int show_patch_diff(struct combine_diff_path *elem, int num_parent,
 static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
-       int i, offset, mod_type = 'A';
+       int i, offset;
        const char *prefix;
        int line_termination, inter_name_termination;
 
@@ -764,13 +771,6 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
        if (rev->loginfo)
                show_log(rev, rev->loginfo, "\n");
 
-       for (i = 0; i < num_parent; i++) {
-               if (p->parent[i].mode)
-                       mod_type = 'M';
-       }
-       if (!p->mode)
-               mod_type = 'D';
-
        if (opt->output_format == DIFF_FORMAT_RAW) {
                offset = strlen(COLONS) - num_parent;
                if (offset < 0)
@@ -824,44 +824,52 @@ void show_combined_diff(struct combine_diff_path *p,
        case DIFF_FORMAT_NAME:
                show_raw_diff(p, num_parent, rev);
                return;
-
-       default:
        case DIFF_FORMAT_PATCH:
                show_patch_diff(p, num_parent, dense, rev);
+               return;
+       default:
+               return;
        }
 }
 
-void diff_tree_combined_merge(const unsigned char *sha1,
-                            int dense, struct rev_info *rev)
+void diff_tree_combined(const unsigned char *sha1,
+                       const unsigned char parent[][20],
+                       int num_parent,
+                       int dense,
+                       struct rev_info *rev)
 {
        struct diff_options *opt = &rev->diffopt;
-       struct commit *commit = lookup_commit(sha1);
        struct diff_options diffopts;
-       struct commit_list *parents;
        struct combine_diff_path *p, *paths = NULL;
-       int num_parent, i, num_paths;
+       int i, num_paths;
+       int do_diffstat;
 
+       do_diffstat = (opt->output_format == DIFF_FORMAT_DIFFSTAT ||
+                      opt->with_stat);
        diffopts = *opt;
-       diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
        diffopts.with_raw = 0;
+       diffopts.with_stat = 0;
        diffopts.recursive = 1;
 
-       /* count parents */
-       for (parents = commit->parents, num_parent = 0;
-            parents;
-            parents = parents->next, num_parent++)
-               ; /* nothing */
-
        /* find set of paths that everybody touches */
-       for (parents = commit->parents, i = 0;
-            parents;
-            parents = parents->next, i++) {
-               struct commit *parent = parents->item;
-               diff_tree_sha1(parent->object.sha1, commit->object.sha1, "",
-                              &diffopts);
+       for (i = 0; i < num_parent; i++) {
+               /* show stat against the first parent even
+                * when doing combined diff.
+                */
+               if (i == 0 && do_diffstat)
+                       diffopts.output_format = DIFF_FORMAT_DIFFSTAT;
+               else
+                       diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
+               diff_tree_sha1(parent[i], sha1, "", &diffopts);
                diffcore_std(&diffopts);
                paths = intersect_paths(paths, i, num_parent);
+
+               if (do_diffstat && rev->loginfo)
+                       show_log(rev, rev->loginfo,
+                                opt->with_stat ? "---\n" : "\n");
                diff_flush(&diffopts);
+               if (opt->with_stat)
+                       putchar('\n');
        }
 
        /* find out surviving paths */
@@ -891,3 +899,25 @@ void diff_tree_combined_merge(const unsigned char *sha1,
                free(tmp);
        }
 }
+
+void diff_tree_combined_merge(const unsigned char *sha1,
+                            int dense, struct rev_info *rev)
+{
+       int num_parent;
+       const unsigned char (*parent)[20];
+       struct commit *commit = lookup_commit(sha1);
+       struct commit_list *parents;
+
+       /* count parents */
+       for (parents = commit->parents, num_parent = 0;
+            parents;
+            parents = parents->next, num_parent++)
+               ; /* nothing */
+
+       parent = xmalloc(num_parent * sizeof(*parent));
+       for (parents = commit->parents, num_parent = 0;
+            parents;
+            parents = parents->next, num_parent++)
+               memcpy(parent + num_parent, parents->item->object.sha1, 20);
+       diff_tree_combined(sha1, parent, num_parent, dense, rev);
+}