Skip to content

Commit 333f3fb

Browse files
jherlandgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Johan Herland <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 58a8756 commit 333f3fb

File tree

3 files changed

+214
-22
lines changed

3 files changed

+214
-22
lines changed

Documentation/diff-options.txt

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,39 @@ endif::git-format-patch[]
6666
number of modified files, as well as number of added and deleted
6767
lines.
6868

69-
--dirstat[=<limit>]::
70-
Output the distribution of relative amount of changes (number of lines added or
71-
removed) for each sub-directory. Directories with changes below
72-
a cut-off percent (3% by default) are not shown. The cut-off percent
73-
can be set with `--dirstat=<limit>`. Changes in a child directory are not
74-
counted for the parent directory, unless `--cumulative` is used.
69+
--dirstat[=<param1,param2,...>]::
70+
Output the distribution of relative amount of changes for each
71+
sub-directory. The behavior of `--dirstat` can be customized by
72+
passing it a comma separated list of parameters.
73+
The following parameters are available:
7574
+
76-
Note that the `--dirstat` option computes the changes while ignoring
77-
the amount of pure code movements within a file. In other words,
78-
rearranging lines in a file is not counted as much as other changes.
79-
80-
--dirstat-by-file[=<limit>]::
81-
Same as `--dirstat`, but counts changed files instead of lines.
75+
--
76+
`changes`;;
77+
Compute the dirstat numbers by counting the lines that have been
78+
removed from the source, or added to the destination. This ignores
79+
the amount of pure code movements within a file. In other words,
80+
rearranging lines in a file is not counted as much as other changes.
81+
This is the default behavior when no parameter is given.
82+
`files`;;
83+
Compute the dirstat numbers by counting the number of files changed.
84+
Each changed file counts equally in the dirstat analysis. This is
85+
the computationally cheapest `--dirstat` behavior, since it does
86+
not have to look at the file contents at all.
87+
`cumulative`;;
88+
Count changes in a child directory for the parent directory as well.
89+
Note that when using `cumulative`, the sum of the percentages
90+
reported may exceed 100%. The default (non-cumulative) behavior can
91+
be specified with the `noncumulative` parameter.
92+
<limit>;;
93+
An integer parameter specifies a cut-off percent (3% by default).
94+
Directories contributing less than this percentage of the changes
95+
are not shown in the output.
96+
--
97+
+
98+
Example: The following will count changed files, while ignoring
99+
directories with less than 10% of the total amount of changed files,
100+
and accumulating child directory counts in the parent directories:
101+
`--dirstat=files,10,cumulative`.
82102

83103
--summary::
84104
Output a condensed summary of extended header information

diff.c

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,41 @@ static int parse_diff_color_slot(const char *var, int ofs)
6666
return -1;
6767
}
6868

69+
static int parse_dirstat_params(struct diff_options *options, const char *params)
70+
{
71+
const char *p = params;
72+
while (*p) {
73+
if (!prefixcmp(p, "changes")) {
74+
p += 7;
75+
DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
76+
} else if (!prefixcmp(p, "files")) {
77+
p += 5;
78+
DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
79+
} else if (!prefixcmp(p, "noncumulative")) {
80+
p += 13;
81+
DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
82+
} else if (!prefixcmp(p, "cumulative")) {
83+
p += 10;
84+
DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
85+
} else if (isdigit(*p)) {
86+
char *end;
87+
options->dirstat_percent = strtoul(p, &end, 10);
88+
p = end;
89+
} else
90+
return error("Unknown --dirstat parameter '%s'", p);
91+
92+
if (*p) {
93+
/* more parameters, swallow separator */
94+
if (*p != ',')
95+
return error("Missing comma separator at char "
96+
"%"PRIuMAX" of '%s'",
97+
(uintmax_t) (p - params), params);
98+
p++;
99+
}
100+
}
101+
return 0;
102+
}
103+
69104
static int git_config_rename(const char *var, const char *value)
70105
{
71106
if (!value)
@@ -3149,6 +3184,18 @@ static int stat_opt(struct diff_options *options, const char **av)
31493184
return argcount;
31503185
}
31513186

3187+
static int parse_dirstat_opt(struct diff_options *options, const char *params)
3188+
{
3189+
if (parse_dirstat_params(options, params))
3190+
die("Failed to parse --dirstat/-X option parameter");
3191+
/*
3192+
* The caller knows a dirstat-related option is given from the command
3193+
* line; allow it to say "return this_function();"
3194+
*/
3195+
options->output_format |= DIFF_FORMAT_DIRSTAT;
3196+
return 1;
3197+
}
3198+
31523199
int diff_opt_parse(struct diff_options *options, const char **av, int ac)
31533200
{
31543201
const char *arg = av[0];
@@ -3168,15 +3215,19 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
31683215
options->output_format |= DIFF_FORMAT_NUMSTAT;
31693216
else if (!strcmp(arg, "--shortstat"))
31703217
options->output_format |= DIFF_FORMAT_SHORTSTAT;
3171-
else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent))
3172-
options->output_format |= DIFF_FORMAT_DIRSTAT;
3173-
else if (!strcmp(arg, "--cumulative")) {
3174-
options->output_format |= DIFF_FORMAT_DIRSTAT;
3175-
DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
3176-
} else if (opt_arg(arg, 0, "dirstat-by-file",
3177-
&options->dirstat_percent)) {
3178-
options->output_format |= DIFF_FORMAT_DIRSTAT;
3179-
DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
3218+
else if (!strcmp(arg, "-X") || !strcmp(arg, "--dirstat"))
3219+
return parse_dirstat_opt(options, "");
3220+
else if (!prefixcmp(arg, "-X"))
3221+
return parse_dirstat_opt(options, arg + 2);
3222+
else if (!prefixcmp(arg, "--dirstat="))
3223+
return parse_dirstat_opt(options, arg + 10);
3224+
else if (!strcmp(arg, "--cumulative"))
3225+
return parse_dirstat_opt(options, "cumulative");
3226+
else if (!strcmp(arg, "--dirstat-by-file"))
3227+
return parse_dirstat_opt(options, "files");
3228+
else if (!prefixcmp(arg, "--dirstat-by-file=")) {
3229+
parse_dirstat_opt(options, "files");
3230+
return parse_dirstat_opt(options, arg + 18);
31803231
}
31813232
else if (!strcmp(arg, "--check"))
31823233
options->output_format |= DIFF_FORMAT_CHECKDIFF;

t/t4047-diff-dirstat.sh

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,9 @@ EOF
330330

331331
test_expect_success 'various ways to misspell --dirstat' '
332332
test_must_fail git show --dirstat10 &&
333-
test_must_fail git show -X=20
333+
test_must_fail git show --dirstat10,files &&
334+
test_must_fail git show -X=20 &&
335+
test_must_fail git show -X=20,cumulative
334336
'
335337

336338
test_expect_success 'vanilla --dirstat' '
@@ -351,6 +353,39 @@ test_expect_success 'vanilla -X' '
351353
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
352354
'
353355

356+
test_expect_success 'explicit defaults: --dirstat=changes,noncumulative,3' '
357+
git diff --dirstat=changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
358+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
359+
git diff --dirstat=changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
360+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
361+
git diff --dirstat=changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
362+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
363+
'
364+
365+
test_expect_success 'explicit defaults: -Xchanges,noncumulative,3' '
366+
git diff -Xchanges,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
367+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
368+
git diff -Xchanges,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
369+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
370+
git diff -Xchanges,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
371+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
372+
'
373+
374+
test_expect_success 'later options override earlier options:' '
375+
git diff --dirstat=files,10,cumulative,changes,noncumulative,3 HEAD^..HEAD >actual_diff_dirstat &&
376+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
377+
git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
378+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
379+
git diff --dirstat=files,10,cumulative,changes,noncumulative,3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
380+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
381+
git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 HEAD^..HEAD >actual_diff_dirstat &&
382+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
383+
git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -M HEAD^..HEAD >actual_diff_dirstat_M &&
384+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
385+
git diff --dirstat=files --dirstat=10 --dirstat=cumulative --dirstat=changes --dirstat=noncumulative -X3 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
386+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
387+
'
388+
354389
cat <<EOF >expect_diff_dirstat
355390
2.1% changed/
356391
10.8% dst/copy/changed/
@@ -454,6 +489,24 @@ test_expect_success '--dirstat=0 --cumulative' '
454489
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
455490
'
456491

492+
test_expect_success '--dirstat=0,cumulative' '
493+
git diff --dirstat=0,cumulative HEAD^..HEAD >actual_diff_dirstat &&
494+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
495+
git diff --dirstat=0,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
496+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
497+
git diff --dirstat=0,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
498+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
499+
'
500+
501+
test_expect_success '-X0,cumulative' '
502+
git diff -X0,cumulative HEAD^..HEAD >actual_diff_dirstat &&
503+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
504+
git diff -X0,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
505+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
506+
git diff -X0,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
507+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
508+
'
509+
457510
cat <<EOF >expect_diff_dirstat
458511
9.0% changed/
459512
9.0% dst/copy/changed/
@@ -496,6 +549,15 @@ test_expect_success '--dirstat-by-file' '
496549
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
497550
'
498551

552+
test_expect_success '--dirstat=files' '
553+
git diff --dirstat=files HEAD^..HEAD >actual_diff_dirstat &&
554+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
555+
git diff --dirstat=files -M HEAD^..HEAD >actual_diff_dirstat_M &&
556+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
557+
git diff --dirstat=files -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
558+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
559+
'
560+
499561
cat <<EOF >expect_diff_dirstat
500562
27.2% dst/copy/
501563
27.2% dst/move/
@@ -530,6 +592,15 @@ test_expect_success '--dirstat-by-file=10' '
530592
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
531593
'
532594

595+
test_expect_success '--dirstat=files,10' '
596+
git diff --dirstat=files,10 HEAD^..HEAD >actual_diff_dirstat &&
597+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
598+
git diff --dirstat=files,10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
599+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
600+
git diff --dirstat=files,10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
601+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
602+
'
603+
533604
cat <<EOF >expect_diff_dirstat
534605
9.0% changed/
535606
9.0% dst/copy/changed/
@@ -582,4 +653,54 @@ test_expect_success '--dirstat-by-file --cumulative' '
582653
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
583654
'
584655

656+
test_expect_success '--dirstat=files,cumulative' '
657+
git diff --dirstat=files,cumulative HEAD^..HEAD >actual_diff_dirstat &&
658+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
659+
git diff --dirstat=files,cumulative -M HEAD^..HEAD >actual_diff_dirstat_M &&
660+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
661+
git diff --dirstat=files,cumulative -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
662+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
663+
'
664+
665+
cat <<EOF >expect_diff_dirstat
666+
27.2% dst/copy/
667+
27.2% dst/move/
668+
54.5% dst/
669+
27.2% src/move/
670+
EOF
671+
672+
cat <<EOF >expect_diff_dirstat_M
673+
14.2% changed/
674+
14.2% dst/copy/changed/
675+
14.2% dst/copy/rearranged/
676+
14.2% dst/copy/unchanged/
677+
42.8% dst/copy/
678+
14.2% dst/move/changed/
679+
14.2% dst/move/rearranged/
680+
28.5% dst/move/
681+
71.4% dst/
682+
14.2% rearranged/
683+
EOF
684+
685+
cat <<EOF >expect_diff_dirstat_CC
686+
16.6% changed/
687+
16.6% dst/copy/changed/
688+
16.6% dst/copy/rearranged/
689+
33.3% dst/copy/
690+
16.6% dst/move/changed/
691+
16.6% dst/move/rearranged/
692+
33.3% dst/move/
693+
66.6% dst/
694+
16.6% rearranged/
695+
EOF
696+
697+
test_expect_success '--dirstat=files,cumulative,10' '
698+
git diff --dirstat=files,cumulative,10 HEAD^..HEAD >actual_diff_dirstat &&
699+
test_cmp expect_diff_dirstat actual_diff_dirstat &&
700+
git diff --dirstat=files,cumulative,10 -M HEAD^..HEAD >actual_diff_dirstat_M &&
701+
test_cmp expect_diff_dirstat_M actual_diff_dirstat_M &&
702+
git diff --dirstat=files,cumulative,10 -C -C HEAD^..HEAD >actual_diff_dirstat_CC &&
703+
test_cmp expect_diff_dirstat_CC actual_diff_dirstat_CC
704+
'
705+
585706
test_done

0 commit comments

Comments
 (0)