Skip to content

Commit 6a40284

Browse files
committed
Merge branch 'lt/diff-stat-show-0-lines' into maint
"git diff --stat" miscounted the total number of changed lines when binary files were involved and hidden beyond --stat-count. It also miscounted the total number of changed files when there were unmerged paths. * lt/diff-stat-show-0-lines: t4049: refocus tests diff --shortstat: do not count "unmerged" entries diff --stat: do not count "unmerged" entries diff --stat: move the "total count" logic to the last loop diff --stat: use "file" temporary variable to refer to data->files[i] diff --stat: status of unmodified pair in diff-q is not zero test: add failing tests for "diff --stat" to t4049 Fix "git diff --stat" for interesting - but empty - file changes
2 parents 7c65b2e + de90959 commit 6a40284

File tree

4 files changed

+110
-58
lines changed

4 files changed

+110
-58
lines changed

diff.c

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,7 @@ struct diffstat_t {
13001300
unsigned is_unmerged:1;
13011301
unsigned is_binary:1;
13021302
unsigned is_renamed:1;
1303+
unsigned is_interesting:1;
13031304
uintmax_t added, deleted;
13041305
} **files;
13051306
};
@@ -1469,8 +1470,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
14691470
for (i = 0; (i < count) && (i < data->nr); i++) {
14701471
struct diffstat_file *file = data->files[i];
14711472
uintmax_t change = file->added + file->deleted;
1472-
if (!data->files[i]->is_renamed &&
1473-
(change == 0)) {
1473+
1474+
if (!file->is_interesting && (change == 0)) {
14741475
count++; /* not shown == room for one more */
14751476
continue;
14761477
}
@@ -1497,7 +1498,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
14971498
if (max_change < change)
14981499
max_change = change;
14991500
}
1500-
count = i; /* min(count, data->nr) */
1501+
count = i; /* where we can stop scanning in data->files[] */
15011502

15021503
/*
15031504
* We have width = stat_width or term_columns() columns total.
@@ -1585,16 +1586,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
15851586
*/
15861587
for (i = 0; i < count; i++) {
15871588
const char *prefix = "";
1588-
char *name = data->files[i]->print_name;
1589-
uintmax_t added = data->files[i]->added;
1590-
uintmax_t deleted = data->files[i]->deleted;
1589+
struct diffstat_file *file = data->files[i];
1590+
char *name = file->print_name;
1591+
uintmax_t added = file->added;
1592+
uintmax_t deleted = file->deleted;
15911593
int name_len;
15921594

1593-
if (!data->files[i]->is_renamed &&
1594-
(added + deleted == 0)) {
1595-
total_files--;
1595+
if (!file->is_interesting && (added + deleted == 0))
15961596
continue;
1597-
}
1597+
15981598
/*
15991599
* "scale" the filename
16001600
*/
@@ -1610,7 +1610,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
16101610
name = slash;
16111611
}
16121612

1613-
if (data->files[i]->is_binary) {
1613+
if (file->is_binary) {
16141614
fprintf(options->file, "%s", line_prefix);
16151615
show_name(options->file, prefix, name, len);
16161616
fprintf(options->file, " %*s", number_width, "Bin");
@@ -1627,7 +1627,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
16271627
fprintf(options->file, "\n");
16281628
continue;
16291629
}
1630-
else if (data->files[i]->is_unmerged) {
1630+
else if (file->is_unmerged) {
16311631
fprintf(options->file, "%s", line_prefix);
16321632
show_name(options->file, prefix, name, len);
16331633
fprintf(options->file, " Unmerged\n");
@@ -1639,8 +1639,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
16391639
*/
16401640
add = added;
16411641
del = deleted;
1642-
adds += add;
1643-
dels += del;
16441642

16451643
if (graph_width <= max_change) {
16461644
int total = add + del;
@@ -1666,16 +1664,24 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
16661664
show_graph(options->file, '-', del, del_c, reset);
16671665
fprintf(options->file, "\n");
16681666
}
1669-
for (i = count; i < data->nr; i++) {
1670-
uintmax_t added = data->files[i]->added;
1671-
uintmax_t deleted = data->files[i]->deleted;
1672-
if (!data->files[i]->is_renamed &&
1673-
(added + deleted == 0)) {
1667+
1668+
for (i = 0; i < data->nr; i++) {
1669+
struct diffstat_file *file = data->files[i];
1670+
uintmax_t added = file->added;
1671+
uintmax_t deleted = file->deleted;
1672+
1673+
if (file->is_unmerged ||
1674+
(!file->is_interesting && (added + deleted == 0))) {
16741675
total_files--;
16751676
continue;
16761677
}
1677-
adds += added;
1678-
dels += deleted;
1678+
1679+
if (!file->is_binary) {
1680+
adds += added;
1681+
dels += deleted;
1682+
}
1683+
if (i < count)
1684+
continue;
16791685
if (!extra_shown)
16801686
fprintf(options->file, "%s ...\n", line_prefix);
16811687
extra_shown = 1;
@@ -1695,9 +1701,8 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option
16951701
int added = data->files[i]->added;
16961702
int deleted= data->files[i]->deleted;
16971703

1698-
if (data->files[i]->is_unmerged)
1699-
continue;
1700-
if (!data->files[i]->is_renamed && (added + deleted == 0)) {
1704+
if (data->files[i]->is_unmerged ||
1705+
(!data->files[i]->is_interesting && (added + deleted == 0))) {
17011706
total_files--;
17021707
} else if (!data->files[i]->is_binary) { /* don't count bytes */
17031708
adds += added;
@@ -2397,13 +2402,20 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
23972402
struct diff_filespec *two,
23982403
struct diffstat_t *diffstat,
23992404
struct diff_options *o,
2400-
int complete_rewrite)
2405+
struct diff_filepair *p)
24012406
{
24022407
mmfile_t mf1, mf2;
24032408
struct diffstat_file *data;
24042409
int same_contents;
2410+
int complete_rewrite = 0;
2411+
2412+
if (!DIFF_PAIR_UNMERGED(p)) {
2413+
if (p->status == DIFF_STATUS_MODIFIED && p->score)
2414+
complete_rewrite = 1;
2415+
}
24052416

24062417
data = diffstat_add(diffstat, name_a, name_b);
2418+
data->is_interesting = p->status != DIFF_STATUS_UNKNOWN;
24072419

24082420
if (!one || !two) {
24092421
data->is_unmerged = 1;
@@ -3114,11 +3126,10 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
31143126
{
31153127
const char *name;
31163128
const char *other;
3117-
int complete_rewrite = 0;
31183129

31193130
if (DIFF_PAIR_UNMERGED(p)) {
31203131
/* unmerged */
3121-
builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0);
3132+
builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p);
31223133
return;
31233134
}
31243135

@@ -3131,9 +3142,7 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
31313142
diff_fill_sha1_info(p->one);
31323143
diff_fill_sha1_info(p->two);
31333144

3134-
if (p->status == DIFF_STATUS_MODIFIED && p->score)
3135-
complete_rewrite = 1;
3136-
builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite);
3145+
builtin_diffstat(name, other, p->one, p->two, diffstat, o, p);
31373146
}
31383147

31393148
static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)

t/t4006-diff-mode.sh

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,28 +32,28 @@ test_expect_success 'prepare binary file' '
3232
git commit -m binbin
3333
'
3434

35-
test_expect_success '--stat output after text chmod' '
36-
test_chmod -x rezrov &&
37-
echo " 0 files changed" >expect &&
38-
git diff HEAD --stat >actual &&
39-
test_i18ncmp expect actual
40-
'
41-
42-
test_expect_success '--shortstat output after text chmod' '
43-
git diff HEAD --shortstat >actual &&
44-
test_i18ncmp expect actual
45-
'
46-
47-
test_expect_success '--stat output after binary chmod' '
48-
test_chmod +x binbin &&
49-
echo " 0 files changed" >expect &&
50-
git diff HEAD --stat >actual &&
51-
test_i18ncmp expect actual
52-
'
53-
54-
test_expect_success '--shortstat output after binary chmod' '
55-
git diff HEAD --shortstat >actual &&
56-
test_i18ncmp expect actual
57-
'
35+
# test_expect_success '--stat output after text chmod' '
36+
# test_chmod -x rezrov &&
37+
# echo " 0 files changed" >expect &&
38+
# git diff HEAD --stat >actual &&
39+
# test_i18ncmp expect actual
40+
# '
41+
#
42+
# test_expect_success '--shortstat output after text chmod' '
43+
# git diff HEAD --shortstat >actual &&
44+
# test_i18ncmp expect actual
45+
# '
46+
#
47+
# test_expect_success '--stat output after binary chmod' '
48+
# test_chmod +x binbin &&
49+
# echo " 0 files changed" >expect &&
50+
# git diff HEAD --stat >actual &&
51+
# test_i18ncmp expect actual
52+
# '
53+
#
54+
# test_expect_success '--shortstat output after binary chmod' '
55+
# git diff HEAD --shortstat >actual &&
56+
# test_i18ncmp expect actual
57+
# '
5858

5959
test_done

t/t4049-diff-stat-count.sh

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,62 @@
44
test_description='diff --stat-count'
55
. ./test-lib.sh
66

7-
test_expect_success setup '
7+
test_expect_success 'setup' '
88
>a &&
99
>b &&
1010
>c &&
1111
>d &&
1212
git add a b c d &&
13-
chmod +x c d &&
13+
git commit -m initial
14+
'
15+
16+
test_expect_success 'mode-only change show as a 0-line change' '
17+
git reset --hard &&
18+
test_chmod +x b d &&
19+
echo a >a &&
20+
echo c >c &&
21+
cat >expect <<-\EOF
22+
a | 1 +
23+
b | 0
24+
...
25+
4 files changed, 2 insertions(+)
26+
EOF
27+
git diff --stat --stat-count=2 HEAD >actual &&
28+
test_i18ncmp expect actual
29+
'
30+
31+
test_expect_success 'binary changes do not count in lines' '
32+
git reset --hard &&
33+
echo a >a &&
34+
echo c >c &&
35+
cat "$TEST_DIRECTORY"/test-binary-1.png >d &&
36+
cat >expect <<-\EOF
37+
a | 1 +
38+
c | 1 +
39+
...
40+
3 files changed, 2 insertions(+)
41+
EOF
42+
git diff --stat --stat-count=2 >actual &&
43+
test_i18ncmp expect actual
44+
'
45+
46+
test_expect_success 'exclude unmerged entries from total file count' '
47+
git reset --hard &&
1448
echo a >a &&
1549
echo b >b &&
50+
git ls-files -s a >x &&
51+
git rm -f d &&
52+
for stage in 1 2 3
53+
do
54+
sed -e "s/ 0 a/ $stage d/" x
55+
done |
56+
git update-index --index-info &&
57+
echo d >d &&
1658
cat >expect <<-\EOF
1759
a | 1 +
1860
b | 1 +
19-
2 files changed, 2 insertions(+)
61+
...
62+
3 files changed, 3 insertions(+)
2063
EOF
2164
git diff --stat --stat-count=2 >actual &&
2265
test_i18ncmp expect actual

t/t4205-log-pretty-formats.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ test_expect_success 'NUL termination' '
8585

8686
test_expect_success 'NUL separation with --stat' '
8787
stat0_part=$(git diff --stat HEAD^ HEAD) &&
88-
stat1_part=$(git diff --stat --root HEAD^) &&
88+
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
8989
printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n" >expected &&
9090
git log -z --stat --pretty="format:%s" >actual &&
9191
test_i18ncmp expected actual
9292
'
9393

9494
test_expect_failure 'NUL termination with --stat' '
9595
stat0_part=$(git diff --stat HEAD^ HEAD) &&
96-
stat1_part=$(git diff --stat --root HEAD^) &&
96+
stat1_part=$(git diff-tree --no-commit-id --stat --root HEAD^) &&
9797
printf "add bar\n$stat0_part\n\0initial\n$stat1_part\n\0" >expected &&
9898
git log -z --stat --pretty="tformat:%s" >actual &&
9999
test_i18ncmp expected actual

0 commit comments

Comments
 (0)