Git fork

Merge branch 'ly/diff-name-only-with-diff-from-content'

Various options to "git diff" that makes comparison ignore certain
aspects of the differences (like "space changes are ignored",
"differences in lines that match these regular expressions are
ignored") did not work well with "--name-only" and friends.

* ly/diff-name-only-with-diff-from-content:
diff: ensure consistent diff behavior with ignore options

+70 -23
+50 -14
diff.c
··· 2438 return 0; 2439 } 2440 2441 static void pprint_rename(struct strbuf *name, const char *a, const char *b) 2442 { 2443 const char *old_name = a; ··· 3753 3754 if (o->word_diff) 3755 init_diff_words_data(&ecbdata, o, one, two); 3756 - if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume, 3757 - &ecbdata, &xpp, &xecfg)) 3758 die("unable to generate diff for %s", one->path); 3759 if (o->word_diff) 3760 free_diff_words_data(&ecbdata); ··· 6144 run_diff(p, o); 6145 } 6146 6147 static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, 6148 struct diffstat_t *diffstat) 6149 { ··· 6772 DIFF_FORMAT_CHECKDIFF)) { 6773 for (i = 0; i < q->nr; i++) { 6774 struct diff_filepair *p = q->queue[i]; 6775 - if (check_pair_status(p)) 6776 - flush_one_pair(p, options); 6777 } 6778 separator++; 6779 } ··· 6825 if (output_format & DIFF_FORMAT_NO_OUTPUT && 6826 options->flags.exit_with_status && 6827 options->flags.diff_from_contents) { 6828 - /* 6829 - * run diff_flush_patch for the exit status. setting 6830 - * options->file to /dev/null should be safe, because we 6831 - * aren't supposed to produce any output anyway. 6832 - */ 6833 - diff_free_file(options); 6834 - options->file = xfopen("/dev/null", "w"); 6835 - options->close_file = 1; 6836 - options->color_moved = 0; 6837 for (i = 0; i < q->nr; i++) { 6838 struct diff_filepair *p = q->queue[i]; 6839 if (check_pair_status(p)) 6840 - diff_flush_patch(p, options); 6841 if (options->found_changes) 6842 break; 6843 }
··· 2438 return 0; 2439 } 2440 2441 + static int quick_consume(void *priv, char *line UNUSED, unsigned long len UNUSED) 2442 + { 2443 + struct emit_callback *ecbdata = priv; 2444 + struct diff_options *o = ecbdata->opt; 2445 + 2446 + o->found_changes = 1; 2447 + return 1; 2448 + } 2449 + 2450 static void pprint_rename(struct strbuf *name, const char *a, const char *b) 2451 { 2452 const char *old_name = a; ··· 3762 3763 if (o->word_diff) 3764 init_diff_words_data(&ecbdata, o, one, two); 3765 + if (o->dry_run) { 3766 + /* 3767 + * Unlike the !dry_run case, we need to ignore the 3768 + * return value from xdi_diff_outf() here, because 3769 + * xdi_diff_outf() takes non-zero return from its 3770 + * callback function as a sign of error and returns 3771 + * early (which is why we return non-zero from our 3772 + * callback, quick_consume()). Unfortunately, 3773 + * xdi_diff_outf() signals an error by returning 3774 + * non-zero. 3775 + */ 3776 + xdi_diff_outf(&mf1, &mf2, NULL, quick_consume, 3777 + &ecbdata, &xpp, &xecfg); 3778 + } else if (xdi_diff_outf(&mf1, &mf2, NULL, fn_out_consume, 3779 + &ecbdata, &xpp, &xecfg)) 3780 die("unable to generate diff for %s", one->path); 3781 if (o->word_diff) 3782 free_diff_words_data(&ecbdata); ··· 6166 run_diff(p, o); 6167 } 6168 6169 + /* return 1 if any change is found; otherwise, return 0 */ 6170 + static int diff_flush_patch_quietly(struct diff_filepair *p, struct diff_options *o) 6171 + { 6172 + int saved_dry_run = o->dry_run; 6173 + int saved_found_changes = o->found_changes; 6174 + int ret; 6175 + 6176 + o->dry_run = 1; 6177 + o->found_changes = 0; 6178 + diff_flush_patch(p, o); 6179 + ret = o->found_changes; 6180 + o->dry_run = saved_dry_run; 6181 + o->found_changes |= saved_found_changes; 6182 + return ret; 6183 + } 6184 + 6185 static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o, 6186 struct diffstat_t *diffstat) 6187 { ··· 6810 DIFF_FORMAT_CHECKDIFF)) { 6811 for (i = 0; i < q->nr; i++) { 6812 struct diff_filepair *p = q->queue[i]; 6813 + 6814 + if (!check_pair_status(p)) 6815 + continue; 6816 + 6817 + if (options->flags.diff_from_contents && 6818 + !diff_flush_patch_quietly(p, options)) 6819 + continue; 6820 + 6821 + flush_one_pair(p, options); 6822 } 6823 separator++; 6824 } ··· 6870 if (output_format & DIFF_FORMAT_NO_OUTPUT && 6871 options->flags.exit_with_status && 6872 options->flags.diff_from_contents) { 6873 for (i = 0; i < q->nr; i++) { 6874 struct diff_filepair *p = q->queue[i]; 6875 if (check_pair_status(p)) 6876 + diff_flush_patch_quietly(p, options); 6877 if (options->found_changes) 6878 break; 6879 }
+2
diff.h
··· 400 #define COLOR_MOVED_WS_ERROR (1<<0) 401 unsigned color_moved_ws_handling; 402 403 struct repository *repo; 404 struct strmap *additional_path_headers; 405
··· 400 #define COLOR_MOVED_WS_ERROR (1<<0) 401 unsigned color_moved_ws_handling; 402 403 + bool dry_run; 404 + 405 struct repository *repo; 406 struct strmap *additional_path_headers; 407
+13
t/t4013-diff-various.sh
··· 648 test_grep "invalid regex given to -I: " error 649 ' 650 651 # check_prefix <patch> <src> <dst> 652 # check only lines with paths to avoid dependency on exact oid/contents 653 check_prefix () {
··· 648 test_grep "invalid regex given to -I: " error 649 ' 650 651 + test_expect_success 'diff -I<regex>: ignore matching file' ' 652 + test_when_finished "git rm -f file1" && 653 + test_seq 50 >file1 && 654 + git add file1 && 655 + test_seq 50 | sed -e "s/13/ten and three/" -e "s/^[124-9].*/& /" >file1 && 656 + 657 + : >actual && 658 + git diff --raw --ignore-blank-lines -I"ten.*e" -I"^[124-9]" >>actual && 659 + git diff --name-only --ignore-blank-lines -I"ten.*e" -I"^[124-9]" >>actual && 660 + git diff --name-status --ignore-blank-lines -I"ten.*e" -I"^[124-9]" >>actual && 661 + test_grep ! "file1" actual 662 + ' 663 + 664 # check_prefix <patch> <src> <dst> 665 # check only lines with paths to avoid dependency on exact oid/contents 666 check_prefix () {
+2 -6
t/t4015-diff-whitespace.sh
··· 11 . "$TEST_DIRECTORY"/lib-diff.sh 12 13 for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \ 14 - --raw! --name-only! --name-status! 15 do 16 - opts=${opt_res%!} expect_failure= 17 - test "$opts" = "$opt_res" || 18 - expect_failure="test_expect_code 1" 19 - 20 test_expect_success "status with $opts (different)" ' 21 echo foo >x && 22 git add x && ··· 43 echo foo >x && 44 git add x && 45 echo " foo" >x && 46 - $expect_failure git diff -w $opts --exit-code x 47 ' 48 done 49
··· 11 . "$TEST_DIRECTORY"/lib-diff.sh 12 13 for opt_res in --patch --quiet -s --stat --shortstat --dirstat=lines \ 14 + --raw --name-only --name-status 15 do 16 test_expect_success "status with $opts (different)" ' 17 echo foo >x && 18 git add x && ··· 39 echo foo >x && 40 git add x && 41 echo " foo" >x && 42 + git diff -w $opts --exit-code x 43 ' 44 done 45
+3 -3
xdiff-interface.h
··· 28 * from an error internal to xdiff, xdiff itself will see that 29 * non-zero return and translate it to -1. 30 * 31 - * See "diff_grep" in diffcore-pickaxe.c for a trick to work around 32 - * this, i.e. using the "consume_callback_data" to note the desired 33 - * early return. 34 */ 35 typedef int (*xdiff_emit_line_fn)(void *, char *, unsigned long); 36 typedef void (*xdiff_emit_hunk_fn)(void *data,
··· 28 * from an error internal to xdiff, xdiff itself will see that 29 * non-zero return and translate it to -1. 30 * 31 + * See "diff_grep" in diffcore-pickaxe.c and "quick_consume" in diff.c 32 + * for a trick to work around this, i.e. using the "consume_callback_data" 33 + * to note the desired early return. 34 */ 35 typedef int (*xdiff_emit_line_fn)(void *, char *, unsigned long); 36 typedef void (*xdiff_emit_hunk_fn)(void *data,