diff --stat: move the "total count" logic to the last loop

The diffstat generation logic, with --stat-count limit, is implemented as three loops. - The first counts the width necessary to show stats up to specified number of entries, and notes up to how many entries in the data we need to iterate to show the graph; - The second iterates that many times to draw the graph, adjusts the number of "total modified files", and counts the total added/deleted lines for the part that was shown in the graph; - The third iterates over the remainder and only does the part to count "total added/deleted lines" and to adjust "total modified files" without drawing anything. Move the logic to count added/deleted lines and modified files from the second loop to the third loop. This incidentally fixes a bug. The third loop was not filtering binary changes (counted in bytes) from the total added/deleted as it should. The second loop implemented this correctly, so if a binary change appeared earlier than the --stat-count cutoff, the code counted number of added/deleted lines correctly, but if it appeared beyond the cutoff, the number of lines would have mixed with the byte count in the buggy third loop. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Nov 27, 2012 at 11:47 UTC a20d3c0de1f107ddd719a4a9cec3addd56e8444f
2 files changed +13 -10
diff.c
+12 -9
@@ -1498,7 +1498,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
1498 if (max_change < change)
1499 max_change = change;
1500 }
1501 - count = i; /* min(count, data->nr) */
1501 + count = i; /* where we can stop scanning in data->files[] */
1502
1503 /*
1504 * We have width = stat_width or term_columns() columns total.
@@ -1592,10 +1592,9 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
1592 uintmax_t deleted = file->deleted;
1593 int name_len;
1594
1595 - if (!file->is_interesting && (added + deleted == 0)) {
1596 - total_files--;
1595 + if (!file->is_interesting && (added + deleted == 0))
1596 continue;
1598 - }
1597 +
1598 /*
1599 * "scale" the filename
1600 */
@@ -1640,8 +1639,6 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
1639 */
1640 add = added;
1641 del = deleted;
1643 - adds += add;
1644 - dels += del;
1642
1643 if (graph_width <= max_change) {
1644 int total = add + del;
@@ -1667,7 +1664,8 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
1664 show_graph(options->file, '-', del, del_c, reset);
1665 fprintf(options->file, "\n");
1666 }
1670 - for (i = count; i < data->nr; i++) {
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;
@@ -1675,8 +1673,13 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
1673 total_files--;
1674 continue;
1675 }
1678 - adds += added;
1679 - dels += deleted;
1676 +
1677 + if (!file->is_binary && !file->is_unmerged) {
1678 + adds += added;
1679 + dels += deleted;
1680 + }
1681 + if (i < count)
1682 + continue;
1683 if (!extra_shown)
1684 fprintf(options->file, "%s ...\n", line_prefix);
1685 extra_shown = 1;
t/t4049-diff-stat-count.sh
+1 -1
@@ -28,7 +28,7 @@ test_expect_success 'limit output to 2 (simple)' '
28 test_i18ncmp expect actual
29 '
30
31 -test_expect_failure 'binary changes do not count in lines' '
31 +test_expect_success 'binary changes do not count in lines' '
32 git reset --hard &&
33 chmod +x c d &&
34 echo a >a &&