]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'jc/diff-exit-code-with-w-fixes'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 Aug 2023 20:50:41 +0000 (13:50 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 Aug 2023 20:50:41 +0000 (13:50 -0700)
"git diff -w --exit-code" with various options did not work
correctly, which is being addressed.

* jc/diff-exit-code-with-w-fixes:
  diff: the -w option breaks --exit-code for --raw and other output modes
  t4040: remove test that succeeded for a wrong reason
  diff: teach "--stat -w --exit-code" to notice differences
  diff: mode-only change should be noticed by "--patch -w --exit-code"
  diff: move the fallback "--exit-code" code down

diff.c
t/t4015-diff-whitespace.sh
t/t4040-whitespace-status.sh

diff --git a/diff.c b/diff.c
index ee3eb629e3dc5e3010342ed988678d9f0cedd0bd..28ba22947617d8ab23c2da7e65e6ed5c895484f4 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3563,18 +3563,21 @@ static void builtin_diff(const char *name_a,
                strbuf_addf(&header, "%s%snew file mode %06o%s\n", line_prefix, meta, two->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
+               o->found_changes = 1;
                must_show_header = 1;
        }
        else if (lbl[1][0] == '/') {
                strbuf_addf(&header, "%s%sdeleted file mode %06o%s\n", line_prefix, meta, one->mode, reset);
                if (xfrm_msg)
                        strbuf_addstr(&header, xfrm_msg);
+               o->found_changes = 1;
                must_show_header = 1;
        }
        else {
                if (one->mode != two->mode) {
                        strbuf_addf(&header, "%s%sold mode %06o%s\n", line_prefix, meta, one->mode, reset);
                        strbuf_addf(&header, "%s%snew mode %06o%s\n", line_prefix, meta, two->mode, reset);
+                       o->found_changes = 1;
                        must_show_header = 1;
                }
                if (xfrm_msg)
@@ -4832,6 +4835,10 @@ void diff_setup_done(struct diff_options *options)
        else
                options->prefix_length = 0;
 
+       /*
+        * --name-only, --name-status, --checkdiff, and -s
+        * turn other output format off.
+        */
        if (options->output_format & (DIFF_FORMAT_NAME |
                                      DIFF_FORMAT_NAME_STATUS |
                                      DIFF_FORMAT_CHECKDIFF |
@@ -6206,6 +6213,8 @@ static void flush_one_pair(struct diff_filepair *p, struct diff_options *opt)
                fprintf(opt->file, "%s", diff_line_prefix(opt));
                write_name_quoted(name_a, opt->file, opt->line_termination);
        }
+
+       opt->found_changes = 1;
 }
 
 static void show_file_mode_name(struct diff_options *opt, const char *newdelete, struct diff_filespec *fs)
@@ -6684,6 +6693,21 @@ void diff_flush(struct diff_options *options)
                separator++;
        }
 
+       if (output_format & DIFF_FORMAT_PATCH) {
+               if (separator) {
+                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0);
+                       if (options->stat_sep)
+                               /* attach patch instead of inline */
+                               emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP,
+                                                NULL, 0, 0);
+               }
+
+               diff_flush_patch_all_file_pairs(options);
+       }
+
+       if (output_format & DIFF_FORMAT_CALLBACK)
+               options->format_callback(q, options, options->format_callback_data);
+
        if (output_format & DIFF_FORMAT_NO_OUTPUT &&
            options->flags.exit_with_status &&
            options->flags.diff_from_contents) {
@@ -6705,21 +6729,6 @@ void diff_flush(struct diff_options *options)
                }
        }
 
-       if (output_format & DIFF_FORMAT_PATCH) {
-               if (separator) {
-                       emit_diff_symbol(options, DIFF_SYMBOL_SEPARATOR, NULL, 0, 0);
-                       if (options->stat_sep)
-                               /* attach patch instead of inline */
-                               emit_diff_symbol(options, DIFF_SYMBOL_STAT_SEP,
-                                                NULL, 0, 0);
-               }
-
-               diff_flush_patch_all_file_pairs(options);
-       }
-
-       if (output_format & DIFF_FORMAT_CALLBACK)
-               options->format_callback(q, options, options->format_callback_data);
-
 free_queue:
        diff_free_queue(q);
        DIFF_QUEUE_CLEAR(q);
@@ -7029,6 +7038,7 @@ void compute_diffstat(struct diff_options *options,
                if (check_pair_status(p))
                        diff_flush_stat(p, options, diffstat);
        }
+       options->found_changes = !!diffstat->nr;
 }
 
 void diff_addremove(struct diff_options *options,
index b298f220e01fe6de17a5dfe608550a5a57dcf9c6..fcd2473e5290dc5a25d643e6af139378fe7ebdc5 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # Copyright (c) 2006 Johannes E. Schindelin
-#
+# Copyright (c) 2023 Google LLC
 
 test_description='Test special whitespace in diff engine.
 
@@ -11,6 +11,43 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-diff.sh
 
+for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \
+              --raw! --name-only! --name-status!
+do
+       opts=${opt_res%!} expect_failure=
+       test "$opts" = "$opt_res" ||
+               expect_failure="test_expect_code 1"
+
+       test_expect_success "status with $opts (different)" '
+               echo foo >x &&
+               git add x &&
+               echo bar >x &&
+               test_expect_code 1 git diff -w $opts --exit-code x
+       '
+
+       test_expect_success POSIXPERM "status with $opts (mode differs)" '
+               test_when_finished "git update-index --chmod=-x x" &&
+               echo foo >x &&
+               git add x &&
+               git update-index --chmod=+x x &&
+               test_expect_code 1 git diff -w $opts --exit-code x
+       '
+
+       test_expect_success "status with $opts (removing an empty file)" '
+               : >x &&
+               git add x &&
+               rm x &&
+               test_expect_code 1 git diff -w $opts --exit-code -- x
+       '
+
+       test_expect_success "status with $opts (different but equivalent)" '
+               echo foo >x &&
+               git add x &&
+               echo " foo" >x &&
+               $expect_failure git diff -w $opts --exit-code x
+       '
+done
+
 test_expect_success "Ray Lehtiniemi's example" '
        cat <<-\EOF >x &&
        do {
index e70e020ae9349c378b4b922933668932e95acc8d..eec3d73dc2b475be7185d9d1dc8733bf391a868b 100755 (executable)
@@ -28,8 +28,7 @@ test_expect_success 'diff-tree --exit-code' '
 
 test_expect_success 'diff-tree -b --exit-code' '
        git diff -b --exit-code HEAD^ HEAD &&
-       git diff-tree -b -p --exit-code HEAD^ HEAD &&
-       git diff-tree -b --exit-code HEAD^ HEAD
+       git diff-tree -b -p --exit-code HEAD^ HEAD
 '
 
 test_expect_success 'diff-index --cached --exit-code' '