diff: handle diffstat of rewritten binary files
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 5d713145879d88339a3ea6bef207129f3cac3fef..14a354147c6c61d369497626ce0bda8e5b4b3060 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1615,7 +1615,7 @@ static void builtin_diff(const char *name_a,
                const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
                const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
                show_submodule_summary(o->file, one ? one->path : two->path,
-                               one->sha1, two->sha1,
+                               one->sha1, two->sha1, two->dirty_submodule,
                                del, add, reset);
                return;
        }
@@ -1811,26 +1811,31 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                data->is_unmerged = 1;
                return;
        }
-       if (complete_rewrite) {
+
+       if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
+               if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+                       die("unable to read files to diff");
+               data->is_binary = 1;
+               data->added = mf2.size;
+               data->deleted = mf1.size;
+       }
+
+       else if (complete_rewrite) {
                diff_populate_filespec(one, 0);
                diff_populate_filespec(two, 0);
                data->deleted = count_lines(one->data, one->size);
                data->added = count_lines(two->data, two->size);
-               goto free_and_return;
        }
-       if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
-               die("unable to read files to diff");
 
-       if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
-               data->is_binary = 1;
-               data->added = mf2.size;
-               data->deleted = mf1.size;
-       } else {
+       else {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
                xdemitcb_t ecb;
 
+               if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+                       die("unable to read files to diff");
+
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
@@ -1838,7 +1843,6 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                              &xpp, &xecfg, &ecb);
        }
 
- free_and_return:
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
 }
@@ -2029,9 +2033,14 @@ static int populate_from_stdin(struct diff_filespec *s)
 static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
 {
        int len;
-       char *data = xmalloc(100);
+       char *data = xmalloc(100), *dirty = "";
+
+       /* Are we looking at the work tree? */
+       if (!s->sha1_valid && s->dirty_submodule)
+               dirty = "-dirty";
+
        len = snprintf(data, 100,
-               "Subproject commit %s\n", sha1_to_hex(s->sha1));
+                      "Subproject commit %s%s\n", sha1_to_hex(s->sha1), dirty);
        s->data = data;
        s->size = len;
        s->should_free = 1;
@@ -3673,6 +3682,23 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
        *q = outq;
 }
 
+static int diffnamecmp(const void *a_, const void *b_)
+{
+       const struct diff_filepair *a = *((const struct diff_filepair **)a_);
+       const struct diff_filepair *b = *((const struct diff_filepair **)b_);
+       const char *name_a, *name_b;
+
+       name_a = a->one ? a->one->path : a->two->path;
+       name_b = b->one ? b->one->path : b->two->path;
+       return strcmp(name_a, name_b);
+}
+
+void diffcore_fix_diff_index(struct diff_options *options)
+{
+       struct diff_queue_struct *q = &diff_queued_diff;
+       qsort(q->queue, q->nr, sizeof(q->queue[0]), diffnamecmp);
+}
+
 void diffcore_std(struct diff_options *options)
 {
        if (options->skip_stat_unmatch)
@@ -3714,7 +3740,7 @@ int diff_result_code(struct diff_options *opt, int status)
 void diff_addremove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
-                   const char *concatpath)
+                   const char *concatpath, unsigned dirty_submodule)
 {
        struct diff_filespec *one, *two;
 
@@ -3746,8 +3772,10 @@ void diff_addremove(struct diff_options *options,
 
        if (addremove != '+')
                fill_filespec(one, sha1, mode);
-       if (addremove != '-')
+       if (addremove != '-') {
                fill_filespec(two, sha1, mode);
+               two->dirty_submodule = dirty_submodule;
+       }
 
        diff_queue(&diff_queued_diff, one, two);
        if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
@@ -3758,7 +3786,8 @@ void diff_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
-                const char *concatpath)
+                const char *concatpath,
+                unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
        struct diff_filespec *one, *two;
 
@@ -3771,6 +3800,8 @@ void diff_change(struct diff_options *options,
                const unsigned char *tmp_c;
                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
+               tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule;
+                       new_dirty_submodule = tmp;
        }
 
        if (options->prefix &&
@@ -3781,6 +3812,8 @@ void diff_change(struct diff_options *options,
        two = alloc_filespec(concatpath);
        fill_filespec(one, old_sha1, old_mode);
        fill_filespec(two, new_sha1, new_mode);
+       one->dirty_submodule = old_dirty_submodule;
+       two->dirty_submodule = new_dirty_submodule;
 
        diff_queue(&diff_queued_diff, one, two);
        if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))