diff.c | 26 +++++++++++++++++--------- diff.h | 1 + 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/diff.c b/diff.c index 9fa841010cc2..c93fdaaa541f 100644 --- a/diff.c +++ b/diff.c @@ -1447,7 +1447,7 @@ static void show_numstat(struct diffstat_t *data, struct diff_options *options) struct dirstat_file { const char *name; - unsigned long changed; + long changed; }; struct dirstat_dir { @@ -1458,7 +1458,7 @@ struct dirstat_dir { static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir, unsigned long changed, const char *base, int baselen) { - unsigned long this_dir = 0; + long this_dir = 0; unsigned int sources = 0; const char *line_prefix = ""; struct strbuf *msg = NULL; @@ -1499,12 +1499,14 @@ static long gather_dirstat(struct diff_options *opt, struct dirstat_dir *dir, * under this directory (sources == 1). */ if (baselen && sources != 1) { - int permille = this_dir * 1000 / changed; + int permille = labs(this_dir) * 1000 / changed; if (permille) { - int percent = permille / 10; + double percent = permille / 10.0; if (percent >= dir->percent) { - fprintf(opt->file, "%s%4d.%01d%% %.*s\n", line_prefix, - percent, permille % 10, baselen, base); + if (this_dir < 0) + percent = -percent; + fprintf(opt->file, "%s%6.1f%% %.*s\n", line_prefix, + percent, baselen, base); if (!dir->cumulative) return 0; } @@ -1537,7 +1539,8 @@ static void show_dirstat(struct diff_options *options) for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; const char *name; - unsigned long copied, added, damage; + unsigned long copied, added, deleted; + long damage; name = p->one->path ? p->one->path : p->two->path; @@ -1567,7 +1570,11 @@ static void show_dirstat(struct diff_options *options) * damaged files, not damaged lines. This is done by * counting only a single damaged line per file. */ - damage = (p->one->size - copied) + added; + deleted = p->one->size - copied; + if (DIFF_OPT_TST(options, DIFFSTAT_NEGATIVE)) + damage = added - deleted; + else + damage = added + deleted; if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE) && damage > 0) damage = 1; @@ -3139,7 +3146,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) &options->dirstat_percent)) { options->output_format |= DIFF_FORMAT_DIRSTAT; DIFF_OPT_SET(options, DIRSTAT_BY_FILE); - } + } else if (!strcmp(arg, "--negative")) + DIFF_OPT_SET(options, DIFFSTAT_NEGATIVE); else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) diff --git a/diff.h b/diff.h index 007a0554d4b2..95d6e65247ae 100644 --- a/diff.h +++ b/diff.h @@ -78,6 +78,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25) #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26) #define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27) +#define DIFF_OPT_DIFFSTAT_NEGATIVE (1 << 28) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)