Skip to content

Commit 4581f40

Browse files
committed
Merge branch 'jc/dirstat'
* jc/dirstat: diff: make --dirstat binary-file safe
2 parents a2fa254 + c04a715 commit 4581f40

File tree

1 file changed

+60
-23
lines changed

1 file changed

+60
-23
lines changed

diff.c

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -991,18 +991,23 @@ static void show_numstat(struct diffstat_t* data, struct diff_options *options)
991991
}
992992
}
993993

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;
997997
};
998998

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)
10001005
{
10011006
unsigned long this_dir = 0;
10021007
unsigned int sources = 0;
10031008

10041009
while (dir->nr) {
1005-
struct diffstat_file *f = *dir->files;
1010+
struct dirstat_file *f = dir->files;
10061011
int namelen = strlen(f->name);
10071012
unsigned long this;
10081013
char *slash;
@@ -1017,10 +1022,7 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
10171022
this = gather_dirstat(file, dir, changed, f->name, newbaselen);
10181023
sources++;
10191024
} else {
1020-
if (f->is_unmerged || f->is_binary)
1021-
this = 0;
1022-
else
1023-
this = f->added + f->deleted;
1025+
this = f->changed;
10241026
dir->files++;
10251027
dir->nr--;
10261028
sources += 2;
@@ -1048,30 +1050,65 @@ static long gather_dirstat(FILE *file, struct diffstat_dir *dir, unsigned long c
10481050
return this_dir;
10491051
}
10501052

1051-
static void show_dirstat(struct diffstat_t *data, struct diff_options *options)
1053+
static void show_dirstat(struct diff_options *options)
10521054
{
10531055
int i;
10541056
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;
10561065

1057-
/* Calculate total changes */
10581066
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
10611091
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++;
10641105
}
10651106

10661107
/* This can happen even with many files, if everything was renames */
10671108
if (!changed)
10681109
return;
10691110

10701111
/* 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;
10751112
gather_dirstat(options->file, &dir, changed, "", 0);
10761113
}
10771114

@@ -3095,7 +3132,7 @@ void diff_flush(struct diff_options *options)
30953132
separator++;
30963133
}
30973134

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)) {
30993136
struct diffstat_t diffstat;
31003137

31013138
memset(&diffstat, 0, sizeof(struct diffstat_t));
@@ -3105,8 +3142,6 @@ void diff_flush(struct diff_options *options)
31053142
if (check_pair_status(p))
31063143
diff_flush_stat(p, options, &diffstat);
31073144
}
3108-
if (output_format & DIFF_FORMAT_DIRSTAT)
3109-
show_dirstat(&diffstat, options);
31103145
if (output_format & DIFF_FORMAT_NUMSTAT)
31113146
show_numstat(&diffstat, options);
31123147
if (output_format & DIFF_FORMAT_DIFFSTAT)
@@ -3116,6 +3151,8 @@ void diff_flush(struct diff_options *options)
31163151
free_diffstat_info(&diffstat);
31173152
separator++;
31183153
}
3154+
if (output_format & DIFF_FORMAT_DIRSTAT)
3155+
show_dirstat(options);
31193156

31203157
if (output_format & DIFF_FORMAT_SUMMARY && !is_summary_empty(q)) {
31213158
for (i = 0; i < q->nr; i++)

0 commit comments

Comments
 (0)