@matheusbsbs / matheus-bagliano / commits / c04a7155a0
Fork 0

diff: make --dirstat binary-file safe

Instead of counting added and removed lines (and mixing the byte size reported for binary files in the result), summarize the extent of damage the same way as we count similarity for rename detection. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Feb 12, 2008 at 17:06 UTC c04a7155a03e5ef089864912769baf9001f64aa9
1 file changed +60 -23
diff.c
+60 -23
@@ -991,18 +991,23 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
991 }
992 }
993
994 -struct diffstat_dir {
995 - struct diffstat_file **files;
996 - int nr, percent, cumulative;
994 +struct dirstat_file {
995 + const char *name;
996 + unsigned long changed;
997 };
998
999 -static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long changed, const char *base, int baselen)
999 +struct dirstat_dir {
1000 + struct dirstat_file *files;
1001 + int alloc, nr, percent, cumulative;
1002 +};
1003 +
1004 +static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long changed, const char *base, int baselen)
1005 {
1006 unsigned long this_dir = 0;
1007 unsigned int sources = 0;
1008
1009 while (dir->nr) {
1005 - struct diffstat_file *f = *dir->files;
1010 + struct dirstat_file *f = dir->files;
1011 int namelen = strlen(f->name);
1012 unsigned long this;
1013 char *slash;
@@ -1017,10 +1022,7 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
1022 this = gather_dirstat(file, dir, changed, f->name, newbaselen);
1023 sources++;
1024 } else {
1020 - if (f->is_unmerged || f->is_binary)
1021 - this = 0;
1022 - else
1023 - this = f->added + f->deleted;
1025 + this = f->changed;
1026 dir->files++;
1027 dir->nr--;
1028 sources += 2;
@@ -1048,19 +1050,58 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
1050 return this_dir;
1051 }
1052
1051 -static void show_dirstat(struct diffstat_t *data, struct diff_options *options)
1053 +static void show_dirstat(struct diff_options *options)
1054 {
1055 int i;
1056 unsigned long changed;
1055 - struct diffstat_dir dir;
1057 + struct dirstat_dir dir;
1058 + struct diff_queue_struct *q = &diff_queued_diff;
1059 +
1060 + dir.files = NULL;
1061 + dir.alloc = 0;
1062 + dir.nr = 0;
1063 + dir.percent = options->dirstat_percent;
1064 + dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
1065
1057 - /* Calculate total changes */
1066 changed = 0;
1059 - for (i = 0; i < data->nr; i++) {
1060 - if (data->files[i]->is_binary || data->files[i]->is_unmerged)
1067 + for (i = 0; i < q->nr; i++) {
1068 + struct diff_filepair *p = q->queue[i];
1069 + const char *name;
1070 + unsigned long copied, added, damage;
1071 +
1072 + name = p->one->path ? p->one->path : p->two->path;
1073 +
1074 + if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two)) {
1075 + diff_populate_filespec(p->one, 0);
1076 + diff_populate_filespec(p->two, 0);
1077 + diffcore_count_changes(p->one, p->two, NULL, NULL, 0,
1078 + &copied, &added);
1079 + diff_free_filespec_data(p->one);
1080 + diff_free_filespec_data(p->two);
1081 + } else if (DIFF_FILE_VALID(p->one)) {
1082 + diff_populate_filespec(p->one, 1);
1083 + copied = added = 0;
1084 + diff_free_filespec_data(p->one);
1085 + } else if (DIFF_FILE_VALID(p->two)) {
1086 + diff_populate_filespec(p->two, 1);
1087 + copied = 0;
1088 + added = p->two->size;
1089 + diff_free_filespec_data(p->two);
1090 + } else
1091 continue;
1062 - changed += data->files[i]->added;
1063 - changed += data->files[i]->deleted;
1092 +
1093 + /*
1094 + * Original minus copied is the removed material,
1095 + * added is the new material. They are both damages
1096 + * made to the preimage.
1097 + */
1098 + damage = (p->one->size - copied) + added;
1099 +
1100 + ALLOC_GROW(dir.files, dir.nr + 1, dir.alloc);
1101 + dir.files[dir.nr].name = name;
1102 + dir.files[dir.nr].changed = damage;
1103 + changed += damage;
1104 + dir.nr++;
1105 }
1106
1107 /* This can happen even with many files, if everything was renames */
@@ -1068,10 +1109,6 @@ static void show_dirstat(struct diffstat_t *data, struct diff_options *options)
1109 return;
1110
1111 /* Show all directories with more than x% of the changes */
1071 - dir.files = data->files;
1072 - dir.nr = data->nr;
1073 - dir.percent = options->dirstat_percent;
1074 - dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE;
1112 gather_dirstat(options->file, &dir, changed, "", 0);
1113 }
1114
@@ -3095,7 +3132,7 @@ void diff_flush(struct diff_options *options)
3132 separator++;
3133 }
3134
3098 - if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIRSTAT)) {
3135 + if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) {
3136 struct diffstat_t diffstat;
3137
3138 memset(&diffstat, 0, sizeof(struct diffstat_t));
@@ -3105,8 +3142,6 @@ void diff_flush(struct diff_options *options)
3142 if (check_pair_status(p))
3143 diff_flush_stat(p, options, &diffstat);
3144 }
3108 - if (output_format & DIFF_FORMAT_DIRSTAT)
3109 - show_dirstat(&diffstat, options);
3145 if (output_format & DIFF_FORMAT_NUMSTAT)
3146 show_numstat(&diffstat, options);
3147 if (output_format & DIFF_FORMAT_DIFFSTAT)
@@ -3116,6 +3151,8 @@ void diff_flush(struct diff_options *options)
3151 free_diffstat_info(&diffstat);
3152 separator++;
3153 }
3154 + if (output_format & DIFF_FORMAT_DIRSTAT)
3155 + show_dirstat(options);
3156
3157 if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
3158 for (i = 0; i < q->nr; i++)