Merge branch 'jh/dirstat' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 4 May 2011 21:59:07 +0000 (14:59 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 4 May 2011 21:59:07 +0000 (14:59 -0700)
* jh/dirstat:
--dirstat: In case of renames, use target filename instead of source filename
Teach --dirstat not to completely ignore rearranged lines within a file
--dirstat-by-file: Make it faster and more correct
--dirstat: Describe non-obvious differences relative to --stat or regular diff

1  2 
diff.c
diff --combined diff.c
index 9fa841010cc21bebc464926b15232b2aace0f5ba,abd9cd5f33d40bc236f6e1d2946992cc967f0341..5376d01e1b26f0297e20f14bd8adcfefd374ab08
--- 1/diff.c
--- 2/diff.c
+++ b/diff.c
@@@ -23,7 -23,7 +23,7 @@@
  #endif
  
  static int diff_detect_rename_default;
 -static int diff_rename_limit_default = 200;
 +static int diff_rename_limit_default = 400;
  static int diff_suppress_blank_empty;
  int diff_use_color_default = -1;
  static const char *diff_word_regex_cfg;
@@@ -628,7 -628,7 +628,7 @@@ struct diff_words_style 
        const char *newline;
  };
  
 -struct diff_words_style diff_words_styles[] = {
 +static struct diff_words_style diff_words_styles[] = {
        { DIFF_WORDS_PORCELAIN, {"+", "\n"}, {"-", "\n"}, {" ", "\n"}, "~\n" },
        { DIFF_WORDS_PLAIN, {"{+", "+}"}, {"[-", "-]"}, {"", ""}, "\n" },
        { DIFF_WORDS_COLOR, {"", ""}, {"", ""}, {"", ""}, "\n" }
@@@ -1242,7 -1242,7 +1242,7 @@@ static void show_stats(struct diffstat_
        uintmax_t max_change = 0, max_len = 0;
        int total_files = data->nr;
        int width, name_width;
 -      const char *reset, *set, *add_c, *del_c;
 +      const char *reset, *add_c, *del_c;
        const char *line_prefix = "";
        struct strbuf *msg = NULL;
  
  
        /* Find the longest filename and max number of changes */
        reset = diff_get_color_opt(options, DIFF_RESET);
 -      set   = diff_get_color_opt(options, DIFF_PLAIN);
        add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
        del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
  
@@@ -1538,8 -1539,36 +1538,36 @@@ static void show_dirstat(struct diff_op
                struct diff_filepair *p = q->queue[i];
                const char *name;
                unsigned long copied, added, damage;
+               int content_changed;
  
-               name = p->one->path ? p->one->path : p->two->path;
+               name = p->two->path ? p->two->path : p->one->path;
+               if (p->one->sha1_valid && p->two->sha1_valid)
+                       content_changed = hashcmp(p->one->sha1, p->two->sha1);
+               else
+                       content_changed = 1;
+               if (!content_changed) {
+                       /*
+                        * The SHA1 has not changed, so pre-/post-content is
+                        * identical. We can therefore skip looking at the
+                        * file contents altogether.
+                        */
+                       damage = 0;
+                       goto found_damage;
+               }
+               if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) {
+                       /*
+                        * In --dirstat-by-file mode, we don't really need to
+                        * look at the actual file contents at all.
+                        * The fact that the SHA1 changed is enough for us to
+                        * add this file to the list of results
+                        * (with each file contributing equal damage).
+                        */
+                       damage = 1;
+                       goto found_damage;
+               }
  
                if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
                        diff_populate_filespec(p->one, 0);
                /*
                 * Original minus copied is the removed material,
                 * added is the new material.  They are both damages
-                * made to the preimage. In --dirstat-by-file mode, count
-                * damaged files, not damaged lines. This is done by
-                * counting only a single damaged line per file.
+                * made to the preimage.
+                * If the resulting damage is zero, we know that
+                * diffcore_count_changes() considers the two entries to
+                * be identical, but since content_changed is true, we
+                * know that there must have been _some_ kind of change,
+                * so we force all entries to have damage > 0.
                 */
                damage = (p->one->size - copied) + added;
-               if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0)
+               if (!damage)
                        damage = 1;
  
+ found_damage:
                ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
                dir.files[dir.nr].name = name;
                dir.files[dir.nr].changed = damage;