diff: do not quit early on stat-dirty files
[gitweb.git] / diff.c
diff --git a/diff.c b/diff.c
index 1e46b575e1940da435a27c10c3ae8a25752efa61..691578b2c6f6d980638980b0c575a8356af5c64d 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4594,6 +4594,11 @@ static int diff_filespec_is_identical(struct diff_filespec *one,
 
 static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
 {
+       if (p->done_skip_stat_unmatch)
+               return p->skip_stat_unmatch_result;
+
+       p->done_skip_stat_unmatch = 1;
+       p->skip_stat_unmatch_result = 0;
        /*
         * 1. Entries that come from stat info dirtiness
         *    always have both sides (iow, not create/delete),
@@ -4615,8 +4620,8 @@ static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
            diff_populate_filespec(p->two, 1) ||
            (p->one->size != p->two->size) ||
            !diff_filespec_is_identical(p->one, p->two)) /* (2) */
-               return 1;
-       return 0;
+               p->skip_stat_unmatch_result = 1;
+       return p->skip_stat_unmatch_result;
 }
 
 static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
@@ -4792,6 +4797,7 @@ void diff_change(struct diff_options *options,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
        struct diff_filespec *one, *two;
+       struct diff_filepair *p;
 
        if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
            is_submodule_ignored(concatpath, options))
@@ -4818,10 +4824,16 @@ void diff_change(struct diff_options *options,
        fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
        one->dirty_submodule = old_dirty_submodule;
        two->dirty_submodule = new_dirty_submodule;
+       p = diff_queue(&diff_queued_diff, one, two);
 
-       diff_queue(&diff_queued_diff, one, two);
-       if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
-               DIFF_OPT_SET(options, HAS_CHANGES);
+       if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
+               return;
+
+       if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
+           !diff_filespec_check_stat_unmatch(p))
+               return;
+
+       DIFF_OPT_SET(options, HAS_CHANGES);
 }
 
 struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)