Merge branch 'zj/diff-stat-dyncol'
By Zbigniew Jędrzejewski-Szmek (8) and Junio C Hamano (1) * zj/diff-stat-dyncol: : This breaks tests. Perhaps it is not worth using the decimal-width stuff : for this series, at least initially. diff --stat: add config option to limit graph width diff --stat: enable limiting of the graph part diff --stat: add a test for output with COLUMNS=40 diff --stat: use a maximum of 5/8 for the filename part merge --stat: use the full terminal width log --stat: use the full terminal width show --stat: use the full terminal width diff --stat: use the full terminal width diff --stat: tests for long filenames and big change counts
This commit is contained in:
commit
af050219e4
@ -52,6 +52,10 @@ 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.statGraphWidth::
|
||||
Limit the width of the graph part in --stat output. If set, applies
|
||||
to all commands generating --stat outuput except format-patch.
|
||||
|
||||
diff.external::
|
||||
If this config variable is set, diff generation is not
|
||||
performed using the internal diff machinery, but using the
|
||||
|
@ -56,13 +56,19 @@ endif::git-format-patch[]
|
||||
Generate a diff using the "histogram diff" algorithm.
|
||||
|
||||
--stat[=<width>[,<name-width>[,<count>]]]::
|
||||
Generate a diffstat. You can override the default
|
||||
output width for 80-column terminal by `--stat=<width>`.
|
||||
The width of the filename part can be controlled by
|
||||
giving another width to it separated by a comma.
|
||||
Generate a diffstat. By default, as much space as necessary
|
||||
will be used for the filename part, and the rest for the graph
|
||||
part. Maximum width defaults to terminal width, or 80 columns
|
||||
if not connected to a terminal, and can be overriden by
|
||||
`<width>`. The width of the filename part can be limited by
|
||||
giving another width `<name-width>` after a comma. The width
|
||||
of the graph part can be limited by using
|
||||
`--stat-graph-width=<width>` (affects all commands generating
|
||||
a stat graph) or by setting `diff.statGraphWidth=<width>`
|
||||
(does not affect `git format-patch`).
|
||||
By giving a third parameter `<count>`, you can limit the
|
||||
output to the first `<count>` lines, followed by
|
||||
`...` if there are more.
|
||||
output to the first `<count>` lines, followed by `...` if
|
||||
there are more.
|
||||
+
|
||||
These parameters can also be set individually with `--stat-width=<width>`,
|
||||
`--stat-name-width=<name-width>` and `--stat-count=<count>`.
|
||||
|
@ -285,6 +285,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
|
||||
/* Otherwise, we are doing the usual "git" diff */
|
||||
rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
|
||||
|
||||
/* Scale to real terminal size and respect statGraphWidth config */
|
||||
rev.diffopt.stat_width = -1;
|
||||
rev.diffopt.stat_graph_width = -1;
|
||||
|
||||
/* Default to let external and textconv be used */
|
||||
DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
|
||||
DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
|
||||
|
@ -77,6 +77,8 @@ static void cmd_log_init_defaults(struct rev_info *rev)
|
||||
get_commit_format(fmt_pretty, rev);
|
||||
rev->verbose_header = 1;
|
||||
DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
|
||||
rev->diffopt.stat_width = -1; /* use full terminal width */
|
||||
rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
|
||||
rev->abbrev_commit = default_abbrev_commit;
|
||||
rev->show_root_diff = default_show_root;
|
||||
rev->subject_prefix = fmt_patch_subject_prefix;
|
||||
@ -447,6 +449,8 @@ int cmd_show(int argc, const char **argv, const char *prefix)
|
||||
rev.diff = 1;
|
||||
rev.always_show_header = 1;
|
||||
rev.no_walk = 1;
|
||||
rev.diffopt.stat_width = -1; /* Scale to real terminal size */
|
||||
|
||||
memset(&opt, 0, sizeof(opt));
|
||||
opt.def = "HEAD";
|
||||
opt.tweak = show_rev_tweak_rev;
|
||||
|
@ -399,6 +399,8 @@ static void finish(struct commit *head_commit,
|
||||
if (new_head && show_diffstat) {
|
||||
struct diff_options opts;
|
||||
diff_setup(&opts);
|
||||
opts.stat_width = -1; /* use full terminal width */
|
||||
opts.stat_graph_width = -1; /* respect statGraphWidth config */
|
||||
opts.output_format |=
|
||||
DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
|
||||
opts.detect_rename = DIFF_DETECT_RENAME;
|
||||
|
@ -2092,6 +2092,7 @@ _git_config ()
|
||||
core.whitespace
|
||||
core.worktree
|
||||
diff.autorefreshindex
|
||||
diff.statGraphWidth
|
||||
diff.external
|
||||
diff.ignoreSubmodules
|
||||
diff.mnemonicprefix
|
||||
|
116
diff.c
116
diff.c
@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg;
|
||||
int diff_auto_refresh_index = 1;
|
||||
static int diff_mnemonic_prefix;
|
||||
static int diff_no_prefix;
|
||||
static int diff_stat_graph_width;
|
||||
static int diff_dirstat_permille_default = 30;
|
||||
static struct diff_options default_diff_options;
|
||||
|
||||
@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
|
||||
diff_no_prefix = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "diff.statgraphwidth")) {
|
||||
diff_stat_graph_width = git_config_int(var, value);
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(var, "diff.external"))
|
||||
return git_config_string(&external_diff_cmd_cfg, var, value);
|
||||
if (!strcmp(var, "diff.wordregex"))
|
||||
@ -1375,7 +1380,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
|
||||
int i, len, add, del, adds = 0, dels = 0;
|
||||
uintmax_t max_change = 0, max_len = 0;
|
||||
int total_files = data->nr;
|
||||
int width, name_width, count;
|
||||
int width, name_width, graph_width, number_width = 4, count;
|
||||
const char *reset, *add_c, *del_c;
|
||||
const char *line_prefix = "";
|
||||
int extra_shown = 0;
|
||||
@ -1389,25 +1394,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
|
||||
line_prefix = msg->buf;
|
||||
}
|
||||
|
||||
width = options->stat_width ? options->stat_width : 80;
|
||||
name_width = options->stat_name_width ? options->stat_name_width : 50;
|
||||
count = options->stat_count ? options->stat_count : data->nr;
|
||||
|
||||
/* Sanity: give at least 5 columns to the graph,
|
||||
* but leave at least 10 columns for the name.
|
||||
*/
|
||||
if (width < 25)
|
||||
width = 25;
|
||||
if (name_width < 10)
|
||||
name_width = 10;
|
||||
else if (width < name_width + 15)
|
||||
name_width = width - 15;
|
||||
|
||||
/* Find the longest filename and max number of changes */
|
||||
reset = diff_get_color_opt(options, DIFF_RESET);
|
||||
add_c = diff_get_color_opt(options, DIFF_FILE_NEW);
|
||||
del_c = diff_get_color_opt(options, DIFF_FILE_OLD);
|
||||
|
||||
/*
|
||||
* Find the longest filename and max number of changes
|
||||
*/
|
||||
for (i = 0; (i < count) && (i < data->nr); i++) {
|
||||
struct diffstat_file *file = data->files[i];
|
||||
uintmax_t change = file->added + file->deleted;
|
||||
@ -1428,19 +1423,72 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
|
||||
}
|
||||
count = i; /* min(count, data->nr) */
|
||||
|
||||
/* Compute the width of the graph part;
|
||||
* 10 is for one blank at the beginning of the line plus
|
||||
* " | count " between the name and the graph.
|
||||
/*
|
||||
* We have width = stat_width or term_columns() columns total.
|
||||
* We want a maximum of min(max_len, stat_name_width) for the name part.
|
||||
* We want a maximum of min(max_change, stat_graph_width) for the +- part.
|
||||
* We also need 1 for " " and 4 + decimal_width(max_change)
|
||||
* for " | NNNN " and one the empty column at the end, altogether
|
||||
* 6 + decimal_width(max_change).
|
||||
*
|
||||
* From here on, name_width is the width of the name area,
|
||||
* and width is the width of the graph area.
|
||||
* If there's not enough space, we will use the smaller of
|
||||
* stat_name_width (if set) and 5/8*width for the filename,
|
||||
* and the rest for constant elements + graph part, but no more
|
||||
* than stat_graph_width for the graph part.
|
||||
* (5/8 gives 50 for filename and 30 for the constant parts + graph
|
||||
* for the standard terminal size).
|
||||
*
|
||||
* In other words: stat_width limits the maximum width, and
|
||||
* stat_name_width fixes the maximum width of the filename,
|
||||
* and is also used to divide available columns if there
|
||||
* aren't enough.
|
||||
*/
|
||||
name_width = (name_width < max_len) ? name_width : max_len;
|
||||
if (width < (name_width + 10) + max_change)
|
||||
width = width - (name_width + 10);
|
||||
else
|
||||
width = max_change;
|
||||
|
||||
if (options->stat_width == -1)
|
||||
width = term_columns();
|
||||
else
|
||||
width = options->stat_width ? options->stat_width : 80;
|
||||
|
||||
if (options->stat_graph_width == -1)
|
||||
options->stat_graph_width = diff_stat_graph_width;
|
||||
|
||||
/*
|
||||
* Guarantee 3/8*16==6 for the graph part
|
||||
* and 5/8*16==10 for the filename part
|
||||
*/
|
||||
if (width < 16 + 6 + number_width)
|
||||
width = 16 + 6 + number_width;
|
||||
|
||||
/*
|
||||
* First assign sizes that are wanted, ignoring available width.
|
||||
*/
|
||||
graph_width = (options->stat_graph_width &&
|
||||
options->stat_graph_width < max_change) ?
|
||||
options->stat_graph_width : max_change;
|
||||
name_width = (options->stat_name_width > 0 &&
|
||||
options->stat_name_width < max_len) ?
|
||||
options->stat_name_width : max_len;
|
||||
|
||||
/*
|
||||
* Adjust adjustable widths not to exceed maximum width
|
||||
*/
|
||||
if (name_width + number_width + 6 + graph_width > width) {
|
||||
if (graph_width > width * 3/8 - number_width - 6)
|
||||
graph_width = width * 3/8 - number_width - 6;
|
||||
if (options->stat_graph_width &&
|
||||
graph_width > options->stat_graph_width)
|
||||
graph_width = options->stat_graph_width;
|
||||
if (name_width > width - number_width - 6 - graph_width)
|
||||
name_width = width - number_width - 6 - graph_width;
|
||||
else
|
||||
graph_width = width - number_width - 6 - name_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* From here name_width is the width of the name area,
|
||||
* and graph_width is the width of the graph area.
|
||||
* max_change is used to scale graph properly.
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
const char *prefix = "";
|
||||
char *name = data->files[i]->print_name;
|
||||
@ -1496,18 +1544,18 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
|
||||
adds += add;
|
||||
dels += del;
|
||||
|
||||
if (width <= max_change) {
|
||||
if (graph_width <= max_change) {
|
||||
int total = add + del;
|
||||
|
||||
total = scale_linear(add + del, width, max_change);
|
||||
total = scale_linear(add + del, graph_width, max_change);
|
||||
if (total < 2 && add && del)
|
||||
/* width >= 2 due to the sanity check */
|
||||
total = 2;
|
||||
if (add < del) {
|
||||
add = scale_linear(add, width, max_change);
|
||||
add = scale_linear(add, graph_width, max_change);
|
||||
del = total - add;
|
||||
} else {
|
||||
del = scale_linear(del, width, max_change);
|
||||
del = scale_linear(del, graph_width, max_change);
|
||||
add = total - del;
|
||||
}
|
||||
}
|
||||
@ -3299,6 +3347,7 @@ static int stat_opt(struct diff_options *options, const char **av)
|
||||
char *end;
|
||||
int width = options->stat_width;
|
||||
int name_width = options->stat_name_width;
|
||||
int graph_width = options->stat_graph_width;
|
||||
int count = options->stat_count;
|
||||
int argcount = 1;
|
||||
|
||||
@ -3327,6 +3376,16 @@ static int stat_opt(struct diff_options *options, const char **av)
|
||||
name_width = strtoul(av[1], &end, 10);
|
||||
argcount = 2;
|
||||
}
|
||||
} else if (!prefixcmp(arg, "-graph-width")) {
|
||||
arg += strlen("-graph-width");
|
||||
if (*arg == '=')
|
||||
graph_width = strtoul(arg + 1, &end, 10);
|
||||
else if (!*arg && !av[1])
|
||||
die("Option '--stat-graph-width' requires a value");
|
||||
else if (!*arg) {
|
||||
graph_width = strtoul(av[1], &end, 10);
|
||||
argcount = 2;
|
||||
}
|
||||
} else if (!prefixcmp(arg, "-count")) {
|
||||
arg += strlen("-count");
|
||||
if (*arg == '=')
|
||||
@ -3352,6 +3411,7 @@ static int stat_opt(struct diff_options *options, const char **av)
|
||||
return 0;
|
||||
options->output_format |= DIFF_FORMAT_DIFFSTAT;
|
||||
options->stat_name_width = name_width;
|
||||
options->stat_graph_width = graph_width;
|
||||
options->stat_width = width;
|
||||
options->stat_count = count;
|
||||
return argcount;
|
||||
|
1
diff.h
1
diff.h
@ -129,6 +129,7 @@ struct diff_options {
|
||||
|
||||
int stat_width;
|
||||
int stat_name_width;
|
||||
int stat_graph_width;
|
||||
int stat_count;
|
||||
const char *word_regex;
|
||||
enum diff_words_type word_diff;
|
||||
|
220
t/t4052-stat-output.sh
Executable file
220
t/t4052-stat-output.sh
Executable file
@ -0,0 +1,220 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek
|
||||
#
|
||||
|
||||
test_description='test --stat output of various commands'
|
||||
|
||||
. ./test-lib.sh
|
||||
. "$TEST_DIRECTORY"/lib-terminal.sh
|
||||
|
||||
# 120 character name
|
||||
name=aaaaaaaaaa
|
||||
name=$name$name$name$name$name$name$name$name$name$name$name$name
|
||||
test_expect_success 'preparation' '
|
||||
>"$name" &&
|
||||
git add "$name" &&
|
||||
git commit -m message &&
|
||||
echo a >"$name" &&
|
||||
git commit -m message "$name"
|
||||
'
|
||||
|
||||
while read cmd args
|
||||
do
|
||||
cat >expect <<-'EOF'
|
||||
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
|
||||
EOF
|
||||
test_expect_success "$cmd: small change with long name gives more space to the name" '
|
||||
git $cmd $args >output &&
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
cat >expect <<-'EOF'
|
||||
...aaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
|
||||
EOF
|
||||
test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" '
|
||||
git $cmd $args --stat=40 >output &&
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --stat-width=width with long name" '
|
||||
git $cmd $args --stat-width=40 >output &&
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
cat >expect <<-'EOF'
|
||||
...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 +
|
||||
EOF
|
||||
test_expect_success "$cmd --stat=...,name-width with long name" '
|
||||
git $cmd $args --stat=60,30 >output &&
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --stat-name-width with long name" '
|
||||
git $cmd $args --stat-name-width=30 >output &&
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
done <<\EOF
|
||||
format-patch -1 --stdout
|
||||
diff HEAD^ HEAD --stat
|
||||
show --stat
|
||||
log -1 --stat
|
||||
EOF
|
||||
|
||||
|
||||
test_expect_success 'preparation for big change tests' '
|
||||
>abcd &&
|
||||
git add abcd &&
|
||||
git commit -m message &&
|
||||
i=0 &&
|
||||
while test $i -lt 1000
|
||||
do
|
||||
echo $i && i=$(($i + 1))
|
||||
done >abcd &&
|
||||
git commit -m message abcd
|
||||
'
|
||||
|
||||
cat >expect80 <<'EOF'
|
||||
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
EOF
|
||||
|
||||
cat >expect200 <<'EOF'
|
||||
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
EOF
|
||||
|
||||
while read verb expect cmd args
|
||||
do
|
||||
test_expect_success "$cmd $verb COLUMNS (big change)" '
|
||||
COLUMNS=200 git $cmd $args >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp "$expect" actual
|
||||
'
|
||||
done <<\EOF
|
||||
ignores expect80 format-patch -1 --stdout
|
||||
respects expect200 diff HEAD^ HEAD --stat
|
||||
respects expect200 show --stat
|
||||
respects expect200 log -1 --stat
|
||||
EOF
|
||||
|
||||
cat >expect40 <<'EOF'
|
||||
abcd | 1000 ++++++++++++++++++++++++++
|
||||
EOF
|
||||
|
||||
while read verb expect cmd args
|
||||
do
|
||||
test_expect_success "$cmd $verb not enough COLUMNS (big change)" '
|
||||
COLUMNS=40 git $cmd $args >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp "$expect" actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd $verb statGraphWidth config" '
|
||||
git -c diff.statGraphWidth=26 $cmd $args >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp "$expect" actual
|
||||
'
|
||||
done <<\EOF
|
||||
ignores expect80 format-patch -1 --stdout
|
||||
respects expect40 diff HEAD^ HEAD --stat
|
||||
respects expect40 show --stat
|
||||
respects expect40 log -1 --stat
|
||||
EOF
|
||||
|
||||
|
||||
cat >expect <<'EOF'
|
||||
abcd | 1000 ++++++++++++++++++++++++++
|
||||
EOF
|
||||
while read cmd args
|
||||
do
|
||||
test_expect_success "$cmd --stat=width with big change" '
|
||||
git $cmd $args --stat=40 >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --stat-width=width with big change" '
|
||||
git $cmd $args --stat-width=40 >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success "$cmd --stat-graph--width with big change" '
|
||||
git $cmd $args --stat-graph-width=26 >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
done <<\EOF
|
||||
format-patch -1 --stdout
|
||||
diff HEAD^ HEAD --stat
|
||||
show --stat
|
||||
log -1 --stat
|
||||
EOF
|
||||
|
||||
test_expect_success 'preparation for long filename tests' '
|
||||
cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
|
||||
git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
|
||||
git commit -m message
|
||||
'
|
||||
|
||||
cat >expect <<'EOF'
|
||||
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++
|
||||
EOF
|
||||
while read cmd args
|
||||
do
|
||||
test_expect_success "$cmd --stat=width with big change is more balanced" '
|
||||
git $cmd $args --stat-width=60 >output &&
|
||||
grep " | " output >actual &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
done <<\EOF
|
||||
format-patch -1 --stdout
|
||||
diff HEAD^ HEAD --stat
|
||||
show --stat
|
||||
log -1 --stat
|
||||
EOF
|
||||
|
||||
cat >expect80 <<'EOF'
|
||||
...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++
|
||||
EOF
|
||||
cat >expect200 <<'EOF'
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
EOF
|
||||
while read verb expect cmd args
|
||||
do
|
||||
test_expect_success "$cmd $verb COLUMNS (long filename)" '
|
||||
COLUMNS=200 git $cmd $args >output
|
||||
grep " | " output >actual &&
|
||||
test_cmp "$expect" actual
|
||||
'
|
||||
done <<\EOF
|
||||
ignores expect80 format-patch -1 --stdout
|
||||
respects expect200 diff HEAD^ HEAD --stat
|
||||
respects expect200 show --stat
|
||||
respects expect200 log -1 --stat
|
||||
EOF
|
||||
|
||||
cat >expect <<'EOF'
|
||||
abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
EOF
|
||||
test_expect_success 'merge --stat respects COLUMNS (big change)' '
|
||||
git checkout -b branch HEAD^^ &&
|
||||
COLUMNS=100 git merge --stat --no-ff master^ >output &&
|
||||
grep " | " output >actual
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
cat >expect <<'EOF'
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++
|
||||
EOF
|
||||
test_expect_success 'merge --stat respects COLUMNS (long filename)' '
|
||||
COLUMNS=100 git merge --stat --no-ff master >output &&
|
||||
grep " | " output >actual
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_done
|
Loading…
Reference in New Issue
Block a user