Commits

Anonymous committed 6a40284 Merge

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

Comments (0)

Files changed (4)

 		unsigned is_unmerged:1;
 		unsigned is_binary:1;
 		unsigned is_renamed:1;
+		unsigned is_interesting:1;
 		uintmax_t added, deleted;
 	} **files;
 };
 	for (i = 0; (i < count) && (i < data->nr); i++) {
 		struct diffstat_file *file = data->files[i];
 		uintmax_t change = file->added + file->deleted;
-		if (!data->files[i]->is_renamed &&
-			 (change == 0)) {
+
+		if (!file->is_interesting && (change == 0)) {
 			count++; /* not shown == room for one more */
 			continue;
 		}
 		if (max_change < change)
 			max_change = change;
 	}
-	count = i; /* min(count, data->nr) */
+	count = i; /* where we can stop scanning in data->files[] */
 
 	/*
 	 * We have width = stat_width or term_columns() columns total.
 	 */
 	for (i = 0; i < count; i++) {
 		const char *prefix = "";
-		char *name = data->files[i]->print_name;
-		uintmax_t added = data->files[i]->added;
-		uintmax_t deleted = data->files[i]->deleted;
+		struct diffstat_file *file = data->files[i];
+		char *name = file->print_name;
+		uintmax_t added = file->added;
+		uintmax_t deleted = file->deleted;
 		int name_len;
 
-		if (!data->files[i]->is_renamed &&
-			 (added + deleted == 0)) {
-			total_files--;
+		if (!file->is_interesting && (added + deleted == 0))
 			continue;
-		}
+
 		/*
 		 * "scale" the filename
 		 */
 				name = slash;
 		}
 
-		if (data->files[i]->is_binary) {
+		if (file->is_binary) {
 			fprintf(options->file, "%s", line_prefix);
 			show_name(options->file, prefix, name, len);
 			fprintf(options->file, " %*s", number_width, "Bin");
 			fprintf(options->file, "\n");
 			continue;
 		}
-		else if (data->files[i]->is_unmerged) {
+		else if (file->is_unmerged) {
 			fprintf(options->file, "%s", line_prefix);
 			show_name(options->file, prefix, name, len);
 			fprintf(options->file, " Unmerged\n");
 		 */
 		add = added;
 		del = deleted;
-		adds += add;
-		dels += del;
 
 		if (graph_width <= max_change) {
 			int total = add + del;
 		show_graph(options->file, '-', del, del_c, reset);
 		fprintf(options->file, "\n");
 	}
-	for (i = count; i < data->nr; i++) {
-		uintmax_t added = data->files[i]->added;
-		uintmax_t deleted = data->files[i]->deleted;
-		if (!data->files[i]->is_renamed &&
-			 (added + deleted == 0)) {
+
+	for (i = 0; i < data->nr; i++) {
+		struct diffstat_file *file = data->files[i];
+		uintmax_t added = file->added;
+		uintmax_t deleted = file->deleted;
+
+		if (file->is_unmerged ||
+		    (!file->is_interesting && (added + deleted == 0))) {
 			total_files--;
 			continue;
 		}
-		adds += added;
-		dels += deleted;
+
+		if (!file->is_binary) {
+			adds += added;
+			dels += deleted;
+		}
+		if (i < count)
+			continue;
 		if (!extra_shown)
 			fprintf(options->file, "%s ...\n", line_prefix);
 		extra_shown = 1;
 		int added = data->files[i]->added;
 		int deleted= data->files[i]->deleted;
 
-		if (data->files[i]->is_unmerged)
-			continue;
-		if (!data->files[i]->is_renamed && (added + deleted == 0)) {
+		if (data->files[i]->is_unmerged ||
+		    (!data->files[i]->is_interesting && (added + deleted == 0))) {
 			total_files--;
 		} else if (!data->files[i]->is_binary) { /* don't count bytes */
 			adds += added;
 			     struct diff_filespec *two,
 			     struct diffstat_t *diffstat,
 			     struct diff_options *o,
-			     int complete_rewrite)
+			     struct diff_filepair *p)
 {
 	mmfile_t mf1, mf2;
 	struct diffstat_file *data;
 	int same_contents;
+	int complete_rewrite = 0;
+
+	if (!DIFF_PAIR_UNMERGED(p)) {
+		if (p->status == DIFF_STATUS_MODIFIED && p->score)
+			complete_rewrite = 1;
+	}
 
 	data = diffstat_add(diffstat, name_a, name_b);
+	data->is_interesting = p->status != DIFF_STATUS_UNKNOWN;
 
 	if (!one || !two) {
 		data->is_unmerged = 1;
 {
 	const char *name;
 	const char *other;
-	int complete_rewrite = 0;
 
 	if (DIFF_PAIR_UNMERGED(p)) {
 		/* unmerged */
-		builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, 0);
+		builtin_diffstat(p->one->path, NULL, NULL, NULL, diffstat, o, p);
 		return;
 	}
 
 	diff_fill_sha1_info(p->one);
 	diff_fill_sha1_info(p->two);
 
-	if (p->status == DIFF_STATUS_MODIFIED && p->score)
-		complete_rewrite = 1;
-	builtin_diffstat(name, other, p->one, p->two, diffstat, o, complete_rewrite);
+	builtin_diffstat(name, other, p->one, p->two, diffstat, o, p);
 }
 
 static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)

t/t4006-diff-mode.sh

 	git commit -m binbin
 '
 
-test_expect_success '--stat output after text chmod' '
-	test_chmod -x rezrov &&
-	echo " 0 files changed" >expect &&
-	git diff HEAD --stat >actual &&
-	test_i18ncmp expect actual
-'
-
-test_expect_success '--shortstat output after text chmod' '
-	git diff HEAD --shortstat >actual &&
-	test_i18ncmp expect actual
-'
-
-test_expect_success '--stat output after binary chmod' '
-	test_chmod +x binbin &&
-	echo " 0 files changed" >expect &&
-	git diff HEAD --stat >actual &&
-	test_i18ncmp expect actual
-'
-
-test_expect_success '--shortstat output after binary chmod' '
-	git diff HEAD --shortstat >actual &&
-	test_i18ncmp expect actual
-'
+# test_expect_success '--stat output after text chmod' '
+# 	test_chmod -x rezrov &&
+# 	echo " 0 files changed" >expect &&
+# 	git diff HEAD --stat >actual &&
+#	test_i18ncmp expect actual
+# '
+#
+# test_expect_success '--shortstat output after text chmod' '
+# 	git diff HEAD --shortstat >actual &&
+# 	test_i18ncmp expect actual
+# '
+#
+# test_expect_success '--stat output after binary chmod' '
+# 	test_chmod +x binbin &&
+# 	echo " 0 files changed" >expect &&
+# 	git diff HEAD --stat >actual &&
+# 	test_i18ncmp expect actual
+# '
+#
+# test_expect_success '--shortstat output after binary chmod' '
+# 	git diff HEAD --shortstat >actual &&
+# 	test_i18ncmp expect actual
+# '
 
 test_done

t/t4049-diff-stat-count.sh

 test_description='diff --stat-count'
 . ./test-lib.sh
 
-test_expect_success setup '
+test_expect_success 'setup' '
 	>a &&
 	>b &&
 	>c &&
 	>d &&
 	git add a b c d &&
-	chmod +x c d &&
+	git commit -m initial
+'
+
+test_expect_success 'mode-only change show as a 0-line change' '
+	git reset --hard &&
+	test_chmod +x b d &&
+	echo a >a &&
+	echo c >c &&
+	cat >expect <<-\EOF
+	 a | 1 +
+	 b | 0
+	 ...
+	 4 files changed, 2 insertions(+)
+	EOF
+	git diff --stat --stat-count=2 HEAD >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'binary changes do not count in lines' '
+	git reset --hard &&
+	echo a >a &&
+	echo c >c &&
+	cat "$TEST_DIRECTORY"/test-binary-1.png >d &&
+	cat >expect <<-\EOF
+	 a | 1 +
+	 c | 1 +
+	 ...
+	 3 files changed, 2 insertions(+)
+	EOF
+	git diff --stat --stat-count=2 >actual &&
+	test_i18ncmp expect actual
+'
+
+test_expect_success 'exclude unmerged entries from total file count' '
+	git reset --hard &&
 	echo a >a &&
 	echo b >b &&
+	git ls-files -s a >x &&
+	git rm -f d &&
+	for stage in 1 2 3
+	do
+		sed -e "s/ 0	a/ $stage	d/" x
+	done |
+	git update-index --index-info &&
+	echo d >d &&
 	cat >expect <<-\EOF
 	 a | 1 +
 	 b | 1 +
-	 2 files changed, 2 insertions(+)
+	 ...
+	 3 files changed, 3 insertions(+)
 	EOF
 	git diff --stat --stat-count=2 >actual &&
 	test_i18ncmp expect actual

t/t4205-log-pretty-formats.sh

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