From: Junio C Hamano Date: Mon, 25 Feb 2008 02:14:53 +0000 (-0800) Subject: Merge branch 'lt/dirstat' X-Git-Tag: v1.5.5-rc0~155 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/a2de3a17faed90c0a7d35e3f48470549b284c4ec?ds=inline;hp=-c Merge branch 'lt/dirstat' * lt/dirstat: diff --dirstat: saner handling of binary and unmerged files Add "--dirstat" for some directory statistics --- a2de3a17faed90c0a7d35e3f48470549b284c4ec diff --combined diff.c index 699b21f4e3,bcc323f19f..99daca6103 --- a/diff.c +++ b/diff.c @@@ -20,7 -20,7 +20,7 @@@ static int diff_detect_rename_default; static int diff_rename_limit_default = 100; -static int diff_use_color_default; +int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; @@@ -57,7 -57,7 +57,7 @@@ static int parse_diff_color_slot(const static struct ll_diff_driver { const char *name; struct ll_diff_driver *next; - char *cmd; + const char *cmd; } *user_diff, **user_diff_tail; /* @@@ -86,7 -86,10 +86,7 @@@ static int parse_lldiff_command(const c user_diff_tail = &(drv->next); } - if (!value) - return error("%s: lacks value", var); - drv->cmd = strdup(value); - return 0; + return git_config_string(&(drv->cmd), var, value); } /* @@@ -163,8 -166,13 +163,8 @@@ int git_diff_ui_config(const char *var if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); - if (ep != var + 4) { - if (!strcmp(ep, ".command")) { - if (!value) - return config_error_nonbool(var); - return parse_lldiff_command(var, ep, value); - } - } + if (ep != var + 4 && !strcmp(ep, ".command")) + return parse_lldiff_command(var, ep, value); } return git_diff_basic_config(var, value); @@@ -191,7 -199,7 +191,7 @@@ int git_diff_basic_config(const char *v } } - return git_default_config(var, value); + return git_color_default_config(var, value); } static char *quote_two(const char *one, const char *two) @@@ -982,6 -990,90 +982,90 @@@ static void show_numstat(struct diffsta } } + struct diffstat_dir { + struct diffstat_file **files; + int nr, percent, cumulative; + }; + + static long gather_dirstat(struct diffstat_dir *dir, unsigned long changed, const char *base, int baselen) + { + unsigned long this_dir = 0; + unsigned int sources = 0; + + while (dir->nr) { + struct diffstat_file *f = *dir->files; + int namelen = strlen(f->name); + unsigned long this; + char *slash; + + if (namelen < baselen) + break; + if (memcmp(f->name, base, baselen)) + break; + slash = strchr(f->name + baselen, '/'); + if (slash) { + int newbaselen = slash + 1 - f->name; + this = gather_dirstat(dir, changed, f->name, newbaselen); + sources++; + } else { + if (f->is_unmerged || f->is_binary) + this = 0; + else + this = f->added + f->deleted; + dir->files++; + dir->nr--; + sources += 2; + } + this_dir += this; + } + + /* + * We don't report dirstat's for + * - the top level + * - or cases where everything came from a single directory + * under this directory (sources == 1). + */ + if (baselen && sources != 1) { + int permille = this_dir * 1000 / changed; + if (permille) { + int percent = permille / 10; + if (percent >= dir->percent) { + printf("%4d.%01d%% %.*s\n", percent, permille % 10, baselen, base); + if (!dir->cumulative) + return 0; + } + } + } + return this_dir; + } + + static void show_dirstat(struct diffstat_t *data, struct diff_options *options) + { + int i; + unsigned long changed; + struct diffstat_dir dir; + + /* Calculate total changes */ + changed = 0; + for (i = 0; i < data->nr; i++) { + if (data->files[i]->is_binary || data->files[i]->is_unmerged) + continue; + changed += data->files[i]->added; + changed += data->files[i]->deleted; + } + + /* This can happen even with many files, if everything was renames */ + if (!changed) + return; + + /* Show all directories with more than x% of the changes */ + dir.files = data->files; + dir.nr = data->nr; + dir.percent = options->dirstat_percent; + dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE; + gather_dirstat(&dir, changed, "", 0); + } + static void free_diffstat_info(struct diffstat_t *diffstat) { int i; @@@ -1013,7 -1105,6 +1097,7 @@@ static void checkdiff_consume(void *pri char *err; if (line[0] == '+') { + data->lineno++; data->status = check_and_emit_line(line + 1, len - 1, data->ws_rule, NULL, NULL, NULL, NULL); if (!data->status) @@@ -1024,12 -1115,13 +1108,12 @@@ emit_line(set, reset, line, 1); (void)check_and_emit_line(line + 1, len - 1, data->ws_rule, stdout, set, reset, ws); - data->lineno++; } else if (line[0] == ' ') data->lineno++; else if (line[0] == '@') { char *plus = strchr(line, '+'); if (plus) - data->lineno = strtol(plus, NULL, 10); + data->lineno = strtol(plus, NULL, 10) - 1; else die("invalid diff"); } @@@ -1199,7 -1291,7 +1283,7 @@@ static struct builtin_funcname_pattern "new\\|return\\|switch\\|throw\\|while\\)\n" "^[ ]*\\(\\([ ]*" "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}" - "[ ]*([^;]*$\\)" }, + "[ ]*([^;]*\\)$" }, { "tex", "^\\(\\\\\\(sub\\)*section{.*\\)$" }, }; @@@ -1631,7 -1723,7 +1715,7 @@@ int diff_populate_filespec(struct diff_ * Convert from working tree format to canonical git format */ strbuf_init(&buf, 0); - if (convert_to_git(s->path, s->data, s->size, &buf)) { + if (convert_to_git(s->path, s->data, s->size, &buf, safe_crlf)) { size_t size = 0; munmap(s->data, s->size); s->should_munmap = 0; @@@ -2050,12 -2142,13 +2134,13 @@@ void diff_setup(struct diff_options *op options->line_termination = '\n'; options->break_opt = -1; options->rename_limit = -1; + options->dirstat_percent = 3; options->context = 3; options->msg_sep = ""; options->change = diff_change; options->add_remove = diff_addremove; - if (diff_use_color_default) + if (diff_use_color_default > 0) DIFF_OPT_SET(options, COLOR_DIFF); else DIFF_OPT_CLR(options, COLOR_DIFF); @@@ -2091,6 -2184,7 +2176,7 @@@ int diff_setup_done(struct diff_option DIFF_FORMAT_NUMSTAT | DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SHORTSTAT | + DIFF_FORMAT_DIRSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH); @@@ -2102,6 -2196,7 +2188,7 @@@ DIFF_FORMAT_NUMSTAT | DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SHORTSTAT | + DIFF_FORMAT_DIRSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_CHECKDIFF)) DIFF_OPT_SET(options, RECURSIVE); @@@ -2212,6 -2307,10 +2299,10 @@@ int diff_opt_parse(struct diff_options options->output_format |= DIFF_FORMAT_NUMSTAT; else if (!strcmp(arg, "--shortstat")) options->output_format |= DIFF_FORMAT_SHORTSTAT; + else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent)) + options->output_format |= DIFF_FORMAT_DIRSTAT; + else if (!strcmp(arg, "--cumulative")) + options->output_format |= DIFF_FORMAT_CUMULATIVE; else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) @@@ -2930,7 -3029,7 +3021,7 @@@ void diff_flush(struct diff_options *op separator++; } - if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT)) { + if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT|DIFF_FORMAT_DIRSTAT)) { struct diffstat_t diffstat; memset(&diffstat, 0, sizeof(struct diffstat_t)); @@@ -2940,6 -3039,8 +3031,8 @@@ if (check_pair_status(p)) diff_flush_stat(p, options, &diffstat); } + if (output_format & DIFF_FORMAT_DIRSTAT) + show_dirstat(&diffstat, options); if (output_format & DIFF_FORMAT_NUMSTAT) show_numstat(&diffstat, options); if (output_format & DIFF_FORMAT_DIFFSTAT) diff --combined diff.h index 8e73f07d7e,8c6bb54119..c5d3a4f965 --- a/diff.h +++ b/diff.h @@@ -30,6 -30,8 +30,8 @@@ typedef void (*diff_format_fn_t)(struc #define DIFF_FORMAT_SUMMARY 0x0008 #define DIFF_FORMAT_PATCH 0x0010 #define DIFF_FORMAT_SHORTSTAT 0x0020 + #define DIFF_FORMAT_DIRSTAT 0x0040 + #define DIFF_FORMAT_CUMULATIVE 0x0080 /* These override all above */ #define DIFF_FORMAT_NAME 0x0100 @@@ -80,6 -82,7 +82,7 @@@ struct diff_options int pickaxe_opts; int rename_score; int rename_limit; + int dirstat_percent; int setup; int abbrev; const char *msg_sep; @@@ -174,7 -177,6 +177,7 @@@ extern void diff_unmerge(struct diff_op extern int git_diff_basic_config(const char *var, const char *value); extern int git_diff_ui_config(const char *var, const char *value); +extern int diff_use_color_default; extern void diff_setup(struct diff_options *); extern int diff_opt_parse(struct diff_options *, const char **, int); extern int diff_setup_done(struct diff_options *);