Refactor --dirstat parsing; deprecate --cumulative and --dirstat-by-file

Instead of having multiple interconnected dirstat-related options, teach
the --dirstat option itself to accept all behavior modifiers as parameters.

 - Preserve the current --dirstat=<limit> (where <limit> is an integer
   specifying a cut-off percentage)
 - Add --dirstat=cumulative, replacing --cumulative
 - Add --dirstat=files, replacing --dirstat-by-file
 - Also add --dirstat=changes and --dirstat=noncumulative for specifying the
   current default behavior. These allow the user to reset other --dirstat
   parameters (e.g. 'cumulative' and 'files') occuring earlier on the
   command line.

The deprecated options (--cumulative and --dirstat-by-file) are still
functional, although they have been removed from the documentation.

Allow multiple parameters to be separated by commas, e.g.:
  --dirstat=files,10,cumulative

Update the documentation accordingly, and add testcases verifying the
behavior of the new syntax.

Improved-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Johan Herland 2011-04-29 11:36:18 +02:00 committed by Junio C Hamano
parent 58a8756a98
commit 333f3fb0c5
3 changed files with 214 additions and 22 deletions

View File

@ -66,19 +66,39 @@ endif::git-format-patch[]
number of modified files, as well as number of added and deleted number of modified files, as well as number of added and deleted
lines. lines.
--dirstat[=<limit>]:: --dirstat[=<param1,param2,...>]::
Output the distribution of relative amount of changes (number of lines added or Output the distribution of relative amount of changes for each
removed) for each sub-directory. Directories with changes below sub-directory. The behavior of `--dirstat` can be customized by
a cut-off percent (3% by default) are not shown. The cut-off percent passing it a comma separated list of parameters.
can be set with `--dirstat=<limit>`. Changes in a child directory are not The following parameters are available:
counted for the parent directory, unless `--cumulative` is used.
+ +
Note that the `--dirstat` option computes the changes while ignoring --
the amount of pure code movements within a file. In other words, `changes`;;
rearranging lines in a file is not counted as much as other changes. Compute the dirstat numbers by counting the lines that have been
removed from the source, or added to the destination. This ignores
--dirstat-by-file[=<limit>]:: the amount of pure code movements within a file. In other words,
Same as `--dirstat`, but counts changed files instead of lines. rearranging lines in a file is not counted as much as other changes.
This is the default behavior when no parameter is given.
`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 have to 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` parameter.
<limit>;;
An integer parameter 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:
`--dirstat=files,10,cumulative`.
--summary:: --summary::
Output a condensed summary of extended header information Output a condensed summary of extended header information

69
diff.c
View File

@ -66,6 +66,41 @@ static int parse_diff_color_slot(const char *var, int ofs)
return -1; return -1;
} }
static int parse_dirstat_params(struct diff_options *options, const char *params)
{
const char *p = params;
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);
p = end;
} else
return error("Unknown --dirstat parameter '%s'", p);
if (*p) {
/* more parameters, swallow separator */
if (*p != ',')
return error("Missing comma separator at char "
"%"PRIuMAX" of '%s'",
(uintmax_t) (p - params), params);
p++;
}
}
return 0;
}
static int git_config_rename(const char *var, const char *value) static int git_config_rename(const char *var, const char *value)
{ {
if (!value) if (!value)
@ -3149,6 +3184,18 @@ static int stat_opt(struct diff_options *options, const char **av)
return argcount; return argcount;
} }
static int parse_dirstat_opt(struct diff_options *options, const char *params)
{
if (parse_dirstat_params(options, params))
die("Failed to parse --dirstat/-X option parameter");
/*
* The caller knows a dirstat-related option is given from the command
* line; allow it to say "return this_function();"
*/
options->output_format |= DIFF_FORMAT_DIRSTAT;
return 1;
}
int diff_opt_parse(struct diff_options *options, const char **av, int ac) int diff_opt_parse(struct diff_options *options, const char **av, int ac)
{ {
const char *arg = av[0]; const char *arg = av[0];
@ -3168,15 +3215,19 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
options->output_format |= DIFF_FORMAT_NUMSTAT; options->output_format |= DIFF_FORMAT_NUMSTAT;
else if (!strcmp(arg, "--shortstat")) else if (!strcmp(arg, "--shortstat"))
options->output_format |= DIFF_FORMAT_SHORTSTAT; options->output_format |= DIFF_FORMAT_SHORTSTAT;
else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent)) else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat"))
options->output_format |= DIFF_FORMAT_DIRSTAT; return parse_dirstat_opt(options, "");
else if (!strcmp(arg, "--cumulative")) { else if (!prefixcmp(arg, "-X"))
options->output_format |= DIFF_FORMAT_DIRSTAT; return parse_dirstat_opt(options, arg + 2);
DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); else if (!prefixcmp(arg, "--dirstat="))
} else if (opt_arg(arg, 0, "dirstat-by-file", return parse_dirstat_opt(options, arg + 10);
&options->dirstat_percent)) { else if (!strcmp(arg, "--cumulative"))
options->output_format |= DIFF_FORMAT_DIRSTAT; return parse_dirstat_opt(options, "cumulative");
DIFF_OPT_SET(options, DIRSTAT_BY_FILE); else if (!strcmp(arg, "--dirstat-by-file"))
return parse_dirstat_opt(options, "files");
else if (!prefixcmp(arg, "--dirstat-by-file=")) {
parse_dirstat_opt(options, "files");
return parse_dirstat_opt(options, arg + 18);
} }
else if (!strcmp(arg, "--check")) else if (!strcmp(arg, "--check"))
options->output_format |= DIFF_FORMAT_CHECKDIFF; options->output_format |= DIFF_FORMAT_CHECKDIFF;

View File

@ -330,7 +330,9 @@ EOF
test_expect_success 'various ways to misspell --dirstat' ' test_expect_success 'various ways to misspell --dirstat' '
test_must_fail git show --dirstat10 && test_must_fail git show --dirstat10 &&
test_must_fail git show -X=20 test_must_fail git show --dirstat10,files &&
test_must_fail git show -X=20 &&
test_must_fail git show -X=20,cumulative
' '
test_expect_success 'vanilla --dirstat' ' test_expect_success 'vanilla --dirstat' '
@ -351,6 +353,39 @@ test_expect_success 'vanilla -X' '
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
' '
test_expect_success 'explicit defaults: --dirstat=changes,noncumulative,3' '
git diff --dirstat=changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
test_expect_success 'explicit defaults: -Xchanges,noncumulative,3' '
git diff -Xchanges,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff -Xchanges,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff -Xchanges,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
test_expect_success 'later options override earlier options:' '
git diff --dirstat=files,10,cumulative,changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
cat <<EOF >expect_diff_dirstat cat <<EOF >expect_diff_dirstat
2.1% changed/ 2.1% changed/
10.8% dst/copy/changed/ 10.8% dst/copy/changed/
@ -454,6 +489,24 @@ test_expect_success '--dirstat=0 --cumulative' '
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
' '
test_expect_success '--dirstat=0,cumulative' '
git diff --dirstat=0,cumulative HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=0,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=0,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
test_expect_success '-X0,cumulative' '
git diff -X0,cumulative HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff -X0,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff -X0,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
cat <<EOF >expect_diff_dirstat cat <<EOF >expect_diff_dirstat
9.0% changed/ 9.0% changed/
9.0% dst/copy/changed/ 9.0% dst/copy/changed/
@ -496,6 +549,15 @@ test_expect_success '--dirstat-by-file' '
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
' '
test_expect_success '--dirstat=files' '
git diff --dirstat=files HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=files -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=files -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
cat <<EOF >expect_diff_dirstat cat <<EOF >expect_diff_dirstat
27.2% dst/copy/ 27.2% dst/copy/
27.2% dst/move/ 27.2% dst/move/
@ -530,6 +592,15 @@ test_expect_success '--dirstat-by-file=10' '
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
' '
test_expect_success '--dirstat=files,10' '
git diff --dirstat=files,10 HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=files,10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=files,10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
cat <<EOF >expect_diff_dirstat cat <<EOF >expect_diff_dirstat
9.0% changed/ 9.0% changed/
9.0% dst/copy/changed/ 9.0% dst/copy/changed/
@ -582,4 +653,54 @@ test_expect_success '--dirstat-by-file --cumulative' '
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
' '
test_expect_success '--dirstat=files,cumulative' '
git diff --dirstat=files,cumulative HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=files,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=files,cumulative -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/
54.5% dst/
27.2% src/move/
EOF
cat <<EOF >expect_diff_dirstat_M
14.2% changed/
14.2% dst/copy/changed/
14.2% dst/copy/rearranged/
14.2% dst/copy/unchanged/
42.8% dst/copy/
14.2% dst/move/changed/
14.2% dst/move/rearranged/
28.5% dst/move/
71.4% dst/
14.2% rearranged/
EOF
cat <<EOF >expect_diff_dirstat_CC
16.6% changed/
16.6% dst/copy/changed/
16.6% dst/copy/rearranged/
33.3% dst/copy/
16.6% dst/move/changed/
16.6% dst/move/rearranged/
33.3% dst/move/
66.6% dst/
16.6% rearranged/
EOF
test_expect_success '--dirstat=files,cumulative,10' '
git diff --dirstat=files,cumulative,10 HEAD^..HEAD >actual_diff_dirstat &&
test_cmp expect_diff_dirstat actual_diff_dirstat &&
git diff --dirstat=files,cumulative,10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
git diff --dirstat=files,cumulative,10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
'
test_done test_done