The new diff.dirstat config variable takes the same arguments as '--dirstat=<args>', and specifies the default arguments for --dirstat. The config is obviously overridden by --dirstat arguments passed on the command line. When not specified, the --dirstat defaults are 'changes,noncumulative,3'. The parsing of the config variable is done by the new function - dirstat_opt_args() - which has been refactored out of dirstat_opt(). The patch also adds several tests verifying the interaction between the diff.dirstat config variable, and the --dirstat command line option. Signed-off-by: Johan Herland <johan@xxxxxxxxxxx> --- Documentation/config.txt | 36 +++++++++++++++ diff.c | 110 ++++++++++++++++++++++++++++----------------- t/t4046-diff-dirstat.sh | 72 ++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 42 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 6babbc7..10fa89a 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -822,6 +822,42 @@ diff.autorefreshindex:: affects only 'git diff' Porcelain, and not lower level 'diff' commands such as 'git diff-files'. +diff.dirstat:: + A comma separated list of `--dirstat` arguments specifying the + default behavior of the `--dirstat` option to linkgit:git-diff[1]` + and friends. The defaults can be overridden on the command line + (using `--dirstat=<arg1,arg2,...>`). The fallback defaults (when + not changed by `diff.dirstat`) are `changes,noncumulative,3`. + The following arguments are available: ++ +-- +`changes`;; + Compute the dirstat numbers by counting the lines that have been + removed from the source, or added to the destination. This ignores + the amount of pure code movements within a file. In other words, + rearranging lines in a file is not counted as much as other changes. + This is the default `--dirstat` behavior. +`files`;; + Compute the dirstat numbers by counting the number of files changed. + Each changed file counts equally in the dirstat analysis. This is + the computationally cheapest `--dirstat` behavior, since it does + not look at the file contents at all. +`cumulative`;; + Count changes in a child directory for the parent directory as well. + Note that when using `cumulative`, the sum of the percentages + reported may exceed 100%. The default (non-cumulative) behavior can + be specified with the `noncumulative` argument. +<limit>;; + An integer argument specifies a cut-off percent (3% by default). + Directories contributing less than this percentage of the changes + are not shown in the output. +-- ++ +Example: The following will count changed files, while ignoring +directories with less than 10% of the total amount of changed files, +and accumulating child directory counts in the parent directories: +`files,10,cumulative`. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the diff --git a/diff.c b/diff.c index 08aaa47..20fe02c 100644 --- a/diff.c +++ b/diff.c @@ -45,6 +45,17 @@ static char diff_colors[][COLOR_MAXLEN] = { GIT_COLOR_NORMAL, /* FUNCINFO */ }; +static void init_default_diff_options() +{ + static int initialized = 0; + if (initialized) + return; + + default_diff_options.dirstat_percent = 3; + + initialized = 1; +} + static int parse_diff_color_slot(const char *var, int ofs) { if (!strcasecmp(var+ofs, "plain")) @@ -114,6 +125,44 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) return git_diff_basic_config(var, value, cb); } +static void dirstat_opt_args(struct diff_options *options, const char *args) +{ + const char *p = args; + while (*p) { + if (!prefixcmp(p, "changes")) { + p += 7; + DIFF_OPT_CLR(options, DIRSTAT_BY_FILE); + } + else if (!prefixcmp(p, "files")) { + p += 5; + DIFF_OPT_SET(options, DIRSTAT_BY_FILE); + } + else if (!prefixcmp(p, "noncumulative")) { + p += 13; + DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE); + } + else if (!prefixcmp(p, "cumulative")) { + p += 10; + DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); + } + else if (isdigit(*p)) { + char *end; + options->dirstat_percent = strtoul(p, &end, 10); + assert(end > p); + p = end; + } + else + die("Unknown --dirstat argument '%s'", p); + + if (*p) { /* more arguments, swallow separator */ + if (*p != ',') + die("Missing comma separator, at index %lu of '%s'", + p - args, args); + ++p; + } + } +} + int git_diff_basic_config(const char *var, const char *value, void *cb) { if (!strcmp(var, "diff.renamelimit")) { @@ -145,6 +194,12 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + if (!strcmp(var, "diff.dirstat")) { + init_default_diff_options(); + dirstat_opt_args(&default_diff_options, value); + return 0; + } + if (!prefixcmp(var, "submodule.")) return parse_submodule_config_option(var, value); @@ -2879,6 +2934,8 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o) void diff_setup(struct diff_options *options) { + init_default_diff_options(); + memcpy(options, &default_diff_options, sizeof(*options)); options->file = stdout; @@ -2886,7 +2943,6 @@ void diff_setup(struct diff_options *options) options->line_termination = '\n'; options->break_opt = -1; options->rename_limit = -1; - options->dirstat_percent = 3; options->context = 3; options->change = diff_change; @@ -3148,7 +3204,6 @@ static int dirstat_opt(struct diff_options *options, const char **av) { const char *p, *arg = av[0]; char *mangled = NULL; - char sep = '='; if (!strcmp(arg, "--cumulative")) /* deprecated */ /* handle '--cumulative' like '--dirstat=cumulative' */ @@ -3156,14 +3211,13 @@ static int dirstat_opt(struct diff_options *options, const char **av) else if (!strcmp(arg, "--dirstat-by-file") || !prefixcmp(arg, "--dirstat-by-file=")) { /* deprecated */ /* handle '--dirstat-by-file=*' like '--dirstat=files,*' */ - mangled = xstrdup(arg + 2); - memcpy(mangled, "--dirstat=files", 15); - if (mangled[15]) { - assert(mangled[15] == '='); - mangled[15] = ','; + mangled = xstrdup(arg + 11); + memcpy(mangled, "=files", 6); + if (mangled[6]) { + assert(mangled[6] == '='); + mangled[6] = ','; } - arg = mangled; - p = mangled + 9; + p = mangled; } else if (!prefixcmp(arg, "-X")) p = arg + 2; @@ -3172,40 +3226,12 @@ static int dirstat_opt(struct diff_options *options, const char **av) else return 0; - options->output_format |= DIFF_FORMAT_DIRSTAT; - - while (*p) { - if (*p != sep) - die("Missing argument separator ('%c'), at index %lu of '%s'", - sep, p - arg, arg); - sep = ','; - ++p; - if (!prefixcmp(p, "changes")) { - p += 7; - DIFF_OPT_CLR(options, DIRSTAT_BY_FILE); - } - else if (!prefixcmp(p, "files")) { - p += 5; - DIFF_OPT_SET(options, DIRSTAT_BY_FILE); - } - else if (!prefixcmp(p, "noncumulative")) { - p += 13; - DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE); - } - else if (!prefixcmp(p, "cumulative")) { - p += 10; - DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); - } - else if (isdigit(*p)) { - char *end; - options->dirstat_percent = strtoul(p, &end, 10); - assert(end > p); - p = end; - } - else - die("Unknown --dirstat argument '%s'", p); - } + if (*p == '=') + dirstat_opt_args(options, ++p); + else if (*p) + return 0; + options->output_format |= DIFF_FORMAT_DIRSTAT; free(mangled); return 1; } diff --git a/t/t4046-diff-dirstat.sh b/t/t4046-diff-dirstat.sh index bd1494c..021c9c4 100755 --- a/t/t4046-diff-dirstat.sh +++ b/t/t4046-diff-dirstat.sh @@ -362,6 +362,15 @@ test_expect_success 'later options override earlier options:' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'non-defaults in config overridden by explicit defaults on command line' ' + git -c diff.dirstat=files,cumulative,50 diff --dirstat=changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=files,cumulative,50 diff --dirstat=changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=files,cumulative,50 diff --dirstat=changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + cat <<EOF >expect_diff_dirstat 2.1% changed/ 10.8% dst/copy/changed/ @@ -404,6 +413,15 @@ test_expect_success '--dirstat=0' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'diff.dirstat=0' ' + git -c diff.dirstat=0 diff --dirstat HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=0 diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=0 diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + cat <<EOF >expect_diff_dirstat 2.1% changed/ 10.8% dst/copy/changed/ @@ -465,6 +483,24 @@ test_expect_success '--dirstat=0,cumulative' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'diff.dirstat=0,cumulative' ' + git -c diff.dirstat=0,cumulative diff --dirstat HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=0,cumulative diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=0,cumulative diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + +test_expect_success 'diff.dirstat=0 & --dirstat=cumulative' ' + git -c diff.dirstat=0 diff --dirstat=cumulative HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=0 diff --dirstat=cumulative -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=0 diff --dirstat=cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + cat <<EOF >expect_diff_dirstat 9.0% changed/ 9.0% dst/copy/changed/ @@ -516,6 +552,15 @@ test_expect_success '--dirstat=files' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'diff.dirstat=files' ' + git -c diff.dirstat=files diff --dirstat HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + cat <<EOF >expect_diff_dirstat 27.2% dst/copy/ 27.2% dst/move/ @@ -559,6 +604,15 @@ test_expect_success '--dirstat=files,10' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'diff.dirstat=10,files' ' + git -c diff.dirstat=10,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=10,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=10,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + cat <<EOF >expect_diff_dirstat 9.0% changed/ 9.0% dst/copy/changed/ @@ -620,6 +674,15 @@ test_expect_success '--dirstat=files,cumulative' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'diff.dirstat=cumulative,files' ' + git -c diff.dirstat=cumulative,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=cumulative,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=cumulative,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + cat <<EOF >expect_diff_dirstat 27.2% dst/copy/ 27.2% dst/move/ @@ -661,4 +724,13 @@ test_expect_success '--dirstat=files,cumulative,10' ' test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC ' +test_expect_success 'diff.dirstat=10,cumulative,files' ' + git -c diff.dirstat=10,cumulative,files diff --dirstat HEAD^..HEAD >actual_diff_dirstat && + test_cmp expect_diff_dirstat actual_diff_dirstat && + git -c diff.dirstat=10,cumulative,files diff --dirstat -M HEAD^..HEAD >actual_diff_dirstat_M && + test_cmp expect_diff_dirstat_M actual_diff_dirstat_M && + git -c diff.dirstat=10,cumulative,files diff --dirstat -C -C HEAD^..HEAD >actual_diff_dirstat_CC && + test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC +' + test_done -- 1.7.5.rc1.3.g4d7b -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html