{"thread":{"id":"29791","subject":"[PATCH 0/4] \"diff -p\" patch header generation updates","startedAt":"2012-03-01T02:14:13Z","lastAt":"2012-03-01T16:52:34Z","messageCount":10,"participants":["Junio C Hamano","Thomas Rast","Zbigniew Jędrzejewski-Szmek"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"185774","messageId":"1330568057-27304-1-git-send-email-gitster@pobox.com","threadId":"29791","inReplyTo":null,"subject":"[PATCH 0/4] \"diff -p\" patch header generation updates","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T02:14:13Z","receivedAt":"2012-03-01T02:14:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"There has always been one thing fishy about the plumbing level \"diff\" used\nto generate patches with \"-p\" option: we produced a header-only diff when\nthere is no patch necessary to be shown, when there is no contents change.\nWe are calling into xdiff to produce a patch, and we should have all the\nnecessary information to suppress the unnecessary header, but because\nhistorically we didn't, we never updated the code to do so.\n\nIt turns out that we already have the necessary machinery to notice such a\nsituation and suppressing the useless header. We just did not realize that\nwe could use it. There is a backward compatibility worry for scripts, but\nI would imagine that the scripts saw these header-only diff as a nuisance\nthat needs to be filtered out, not a feature to learn about paths that are\nonly stat-dirty.  And more importantly, even if this _were_ a feature, it\nwas not working correctly when \"-w\" option was in effect to begin with, as\nthe second one in the series illustrates.\n\nThis series changes the world order that is almost 6 years old.  No more\nphantom diff headers in patch output due to stat-dirtiness.\n\nThe first patch in this series replaces the one I posted earlier (one\nblock that prepares the expected result was in a wrong test).\n\nThe second patch adds test vectors that illustrate the current behaviour\nthat will be changed with this series.\n\nThe third patch is the real change, whose effect can be seen in the patch\nto the test the second one introduces.\n\nThe fourth one is unrelated from the rest of the series from the feature\npoint of view, but its implementation depends on the updated semantics of\nheader suppression.\n\nThe series is designed to apply on top of v1.7.4-rc0~147 and has trivial\nconflict in diff.h if applied/merged to 'master'.  Just take the addition\nof DIFF_OPT* macros from both sides.\n\nJunio C Hamano (4):\n  t4011: modernise style\n  t4011: illustrate \"diff-index -p\" on stat-dirty paths\n  diff -p: squelch \"diff --git\" header for stat-dirty paths\n  diff --ignore-mode-change\n\n diff.c                  |   31 +++++++-\n diff.h                  |    1 +\n t/t4011-diff-symlink.sh |  196 +++++++++++++++++++++++++++--------------------\n 3 files changed, 141 insertions(+), 87 deletions(-)\n\n-- \n1.7.9.2.350.g74d65\n"},{"id":"185775","messageId":"1330568057-27304-2-git-send-email-gitster@pobox.com","threadId":"29791","inReplyTo":"1330568057-27304-1-git-send-email-gitster@pobox.com","subject":"[PATCH 1/4] t4011: modernise style","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T02:14:14Z","receivedAt":"2012-03-01T02:14:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Match the style to more modern test scripts, namely:\n\n - The first line of each test has prereq, title and opening sq for the\n   script body.  This makes the test shorter while reducing the need for\n   backquotes.\n\n - Be prepared for the case in which the previous test may have failed.\n   If a test wants to start from not having \"frotz\" that the previous test\n   may have created, write \"rm -f frotz\", not \"rm frotz\".\n\n - Prepare the expected output inside your own test.\n\n - The order of comparison to check the result is \"diff expected actual\",\n   so that the output will show how the output from the git you just broke\n   is different from what is expected.\n\n - Write no SP between redirection '>' (or '<' for that matter) and the\n   filename.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * replaces the one I posted earlier (one block that prepares the expected\n   result was in a wrong test).\n\n t/t4011-diff-symlink.sh |  168 +++++++++++++++++++++++------------------------\n 1 file changed, 82 insertions(+), 86 deletions(-)\n\ndiff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh\nindex 408a19c..cb47ec1 100755\n--- a/t/t4011-diff-symlink.sh\n+++ b/t/t4011-diff-symlink.sh\n@@ -9,85 +9,81 @@ test_description='Test diff of symlinks.\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/diff-lib.sh\n \n-cat > expected << EOF\n-diff --git a/frotz b/frotz\n-new file mode 120000\n-index 0000000..7c465af\n---- /dev/null\n-+++ b/frotz\n-@@ -0,0 +1 @@\n-+xyzzy\n-\\ No newline at end of file\n-EOF\n-\n-test_expect_success SYMLINKS \\\n-    'diff new symlink' \\\n-    'ln -s xyzzy frotz &&\n-    git update-index &&\n-    tree=$(git write-tree) &&\n-    git update-index --add frotz &&\n-    GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree > current &&\n-    compare_diff_patch current expected'\n-\n-test_expect_success SYMLINKS \\\n-    'diff unchanged symlink' \\\n-    'tree=$(git write-tree) &&\n-    git update-index frotz &&\n-    test -z \"$(git diff-index --name-only $tree)\"'\n-\n-cat > expected << EOF\n-diff --git a/frotz b/frotz\n-deleted file mode 120000\n-index 7c465af..0000000\n---- a/frotz\n-+++ /dev/null\n-@@ -1 +0,0 @@\n--xyzzy\n-\\ No newline at end of file\n-EOF\n-\n-test_expect_success SYMLINKS \\\n-    'diff removed symlink' \\\n-    'mv frotz frotz2 &&\n-    git diff-index -M -p $tree > current &&\n-    compare_diff_patch current expected'\n+test_expect_success SYMLINKS 'diff new symlink' '\n+\tcat >expected <<-\\EOF &&\n+\tdiff --git a/frotz b/frotz\n+\tnew file mode 120000\n+\tindex 0000000..7c465af\n+\t--- /dev/null\n+\t+++ b/frotz\n+\t@@ -0,0 +1 @@\n+\t+xyzzy\n+\t\\ No newline at end of file\n+\tEOF\n+\tln -s xyzzy frotz &&\n+\tgit update-index &&\n+\ttree=$(git write-tree) &&\n+\tgit update-index --add frotz &&\n+\tGIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current &&\n+\tcompare_diff_patch expected current\n+'\n \n-cat > expected << EOF\n-diff --git a/frotz b/frotz\n-EOF\n+test_expect_success SYMLINKS 'diff unchanged symlink'  '\n+\ttree=$(git write-tree) &&\n+\tgit update-index frotz &&\n+\ttest -z \"$(git diff-index --name-only $tree)\"\n+'\n \n-test_expect_success SYMLINKS \\\n-    'diff identical, but newly created symlink' \\\n-    'ln -s xyzzy frotz &&\n-    git diff-index -M -p $tree > current &&\n-    compare_diff_patch current expected'\n+test_expect_success SYMLINKS 'diff removed symlink' '\n+\tcat >expected <<-\\EOF &&\n+\tdiff --git a/frotz b/frotz\n+\tdeleted file mode 120000\n+\tindex 7c465af..0000000\n+\t--- a/frotz\n+\t+++ /dev/null\n+\t@@ -1 +0,0 @@\n+\t-xyzzy\n+\t\\ No newline at end of file\n+\tEOF\n+\tmv frotz frotz2 &&\n+\tgit diff-index -M -p $tree >current &&\n+\tcompare_diff_patch expected current\n+'\n \n-cat > expected << EOF\n-diff --git a/frotz b/frotz\n-index 7c465af..df1db54 120000\n---- a/frotz\n-+++ b/frotz\n-@@ -1 +1 @@\n--xyzzy\n-\\ No newline at end of file\n-+yxyyz\n-\\ No newline at end of file\n-EOF\n+test_expect_success SYMLINKS 'diff identical, but newly created symlink' '\n+\tcat >expected <<-\\EOF &&\n+\tdiff --git a/frotz b/frotz\n+\tEOF\n+\tln -s xyzzy frotz &&\n+\tgit diff-index -M -p $tree >current &&\n+\tcompare_diff_patch expected current\n+'\n \n-test_expect_success SYMLINKS \\\n-    'diff different symlink' \\\n-    'rm frotz &&\n-    ln -s yxyyz frotz &&\n-    git diff-index -M -p $tree > current &&\n-    compare_diff_patch current expected'\n+test_expect_success SYMLINKS 'diff different symlink' '\n+\tcat >expected <<-\\EOF &&\n+\tdiff --git a/frotz b/frotz\n+\tindex 7c465af..df1db54 120000\n+\t--- a/frotz\n+\t+++ b/frotz\n+\t@@ -1 +1 @@\n+\t-xyzzy\n+\t\\ No newline at end of file\n+\t+yxyyz\n+\t\\ No newline at end of file\n+\tEOF\n+\trm -f frotz &&\n+\tln -s yxyyz frotz &&\n+\tgit diff-index -M -p $tree >current &&\n+\tcompare_diff_patch expected current\n+'\n \n-test_expect_success SYMLINKS \\\n-    'diff symlinks with non-existing targets' \\\n-    'ln -s narf pinky &&\n-    ln -s take\\ over brain &&\n-    test_must_fail git diff --no-index pinky brain > output 2> output.err &&\n-    grep narf output &&\n-    ! grep error output.err'\n+test_expect_success SYMLINKS 'diff symlinks with non-existing targets' '\n+\tln -s narf pinky &&\n+\tln -s take\\ over brain &&\n+\ttest_must_fail git diff --no-index pinky brain >output 2>output.err &&\n+\tgrep narf output &&\n+\t! test -s output.err\n+'\n \n test_expect_success SYMLINKS 'setup symlinks with attributes' '\n \techo \"*.bin diff=bin\" >>.gitattributes &&\n@@ -96,19 +92,19 @@ test_expect_success SYMLINKS 'setup symlinks with attributes' '\n \tgit add -N file.bin link.bin\n '\n \n-cat >expect <<'EOF'\n-diff --git a/file.bin b/file.bin\n-index e69de29..d95f3ad 100644\n-Binary files a/file.bin and b/file.bin differ\n-diff --git a/link.bin b/link.bin\n-index e69de29..dce41ec 120000\n---- a/link.bin\n-+++ b/link.bin\n-@@ -0,0 +1 @@\n-+file.bin\n-\\ No newline at end of file\n-EOF\n test_expect_success SYMLINKS 'symlinks do not respect userdiff config by path' '\n+\tcat >expect <<-\\EOF &&\n+\tdiff --git a/file.bin b/file.bin\n+\tindex e69de29..d95f3ad 100644\n+\tBinary files a/file.bin and b/file.bin differ\n+\tdiff --git a/link.bin b/link.bin\n+\tindex e69de29..dce41ec 120000\n+\t--- a/link.bin\n+\t+++ b/link.bin\n+\t@@ -0,0 +1 @@\n+\t+file.bin\n+\t\\ No newline at end of file\n+\tEOF\n \tgit config diff.bin.binary true &&\n \tgit diff file.bin link.bin >actual &&\n \ttest_cmp expect actual\n-- \n1.7.9.2.350.g74d65\n"},{"id":"185778","messageId":"1330568057-27304-3-git-send-email-gitster@pobox.com","threadId":"29791","inReplyTo":"1330568057-27304-1-git-send-email-gitster@pobox.com","subject":"[PATCH 2/4] t4011: illustrate \"diff-index -p\" on stat-dirty paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T02:14:15Z","receivedAt":"2012-03-01T02:14:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The plumbing that looks at the working tree, i.e. \"diff-index\" and\n\"diff-files\", always emit the \"diff --git a/path b/path\" header lines\nwithout anything else for paths that are only stat-dirty (i.e. different\nonly because the cached stat information in the index no longer matches\nthat of the working tree, but the real contents are the same), when\nthese commands are run with \"-p\" option to produce patches.\n\nIllustrate this current behaviour.  The new part that uses \"-w\" option\ndemonstrates that we do not show any \"diff --git\" header for blobs whose\ntrue contents are different but compares the same when whitespaces are\nignored, which is inconsistent with the behaviour for stat-dirty paths.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t4011-diff-symlink.sh |   47 ++++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 40 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh\nindex cb47ec1..6097e19 100755\n--- a/t/t4011-diff-symlink.sh\n+++ b/t/t4011-diff-symlink.sh\n@@ -9,7 +9,7 @@ test_description='Test diff of symlinks.\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/diff-lib.sh\n \n-test_expect_success SYMLINKS 'diff new symlink' '\n+test_expect_success SYMLINKS 'diff new symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n \tnew file mode 120000\n@@ -19,22 +19,30 @@ test_expect_success SYMLINKS 'diff new symlink' '\n \t@@ -0,0 +1 @@\n \t+xyzzy\n \t\\ No newline at end of file\n+\tdiff --git a/nitfol b/nitfol\n+\tnew file mode 100644\n+\tindex 0000000..7c465af\n+\t--- /dev/null\n+\t+++ b/nitfol\n+\t@@ -0,0 +1 @@\n+\t+xyzzy\n \tEOF\n \tln -s xyzzy frotz &&\n+\techo xyzzy >nitfol &&\n \tgit update-index &&\n \ttree=$(git write-tree) &&\n-\tgit update-index --add frotz &&\n+\tgit update-index --add frotz nitfol &&\n \tGIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current &&\n \tcompare_diff_patch expected current\n '\n \n-test_expect_success SYMLINKS 'diff unchanged symlink'  '\n+test_expect_success SYMLINKS 'diff unchanged symlink and file'  '\n \ttree=$(git write-tree) &&\n-\tgit update-index frotz &&\n+\tgit update-index frotz nitfol &&\n \ttest -z \"$(git diff-index --name-only $tree)\"\n '\n \n-test_expect_success SYMLINKS 'diff removed symlink' '\n+test_expect_success SYMLINKS 'diff removed symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n \tdeleted file mode 120000\n@@ -44,22 +52,39 @@ test_expect_success SYMLINKS 'diff removed symlink' '\n \t@@ -1 +0,0 @@\n \t-xyzzy\n \t\\ No newline at end of file\n+\tdiff --git a/nitfol b/nitfol\n+\tdeleted file mode 100644\n+\tindex 7c465af..0000000\n+\t--- a/nitfol\n+\t+++ /dev/null\n+\t@@ -1 +0,0 @@\n+\t-xyzzy\n \tEOF\n \tmv frotz frotz2 &&\n+\tmv nitfol nitfol2 &&\n \tgit diff-index -M -p $tree >current &&\n \tcompare_diff_patch expected current\n '\n \n-test_expect_success SYMLINKS 'diff identical, but newly created symlink' '\n+test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n+\tdiff --git a/nitfol b/nitfol\n \tEOF\n+\tsleep 3 &&\n+\trm -f frotz &&\n+\techo xyzzy >nitfol3 &&\n+\tmv nitfol3 nitfol &&\n \tln -s xyzzy frotz &&\n \tgit diff-index -M -p $tree >current &&\n+\tcompare_diff_patch expected current &&\n+\n+\t>expected &&\n+\tgit diff-index -M -p -w $tree >current &&\n \tcompare_diff_patch expected current\n '\n \n-test_expect_success SYMLINKS 'diff different symlink' '\n+test_expect_success SYMLINKS 'diff different symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n \tindex 7c465af..df1db54 120000\n@@ -70,9 +95,17 @@ test_expect_success SYMLINKS 'diff different symlink' '\n \t\\ No newline at end of file\n \t+yxyyz\n \t\\ No newline at end of file\n+\tdiff --git a/nitfol b/nitfol\n+\tindex 7c465af..df1db54 100644\n+\t--- a/nitfol\n+\t+++ b/nitfol\n+\t@@ -1 +1 @@\n+\t-xyzzy\n+\t+yxyyz\n \tEOF\n \trm -f frotz &&\n \tln -s yxyyz frotz &&\n+\techo yxyyz >nitfol &&\n \tgit diff-index -M -p $tree >current &&\n \tcompare_diff_patch expected current\n '\n-- \n1.7.9.2.350.g74d65\n"},{"id":"185776","messageId":"1330568057-27304-4-git-send-email-gitster@pobox.com","threadId":"29791","inReplyTo":"1330568057-27304-1-git-send-email-gitster@pobox.com","subject":"[PATCH 3/4] diff -p: squelch \"diff --git\" header for stat-dirty paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T02:14:16Z","receivedAt":"2012-03-01T02:14:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The plumbing \"diff\" commands look at the working tree files without\nrefreshing the index themselves for performance reasons (the calling\nscript is expected to do that upfront just once, before calling one or\nmore of them).  In the early days of git, they showed the \"diff --git\"\nheader before they actually ask the xdiff machinery to produce patches,\nand ended up showing only these headers if the real contents are the same\nand the difference they noticed was only because the stat info cached in\nthe index did not match that of the working tree. It was too late for the\nimplementation to take the header that it already emitted back.\n\nBut 3e97c7c (No diff -b/-w output for all-whitespace changes, 2009-11-19)\nintroduced necessary logic to keep the meta-information headers in a\nstrbuf and delay their output until the xdiff machinery noticed actual\nchanges. This was primarily in order to generate patches that ignore\nwhitespaces. When operating under \"-w\" mode, we wouldn't know if the\nheader is needed until we actually look at the resulting patch, so it was\na sensible thing to do, but we did not realize that the same reasoning\napplies to stat-dirty paths.\n\nLater, 296c6bb2 generalized this machinery and introduced must_show_header\ntoggle.  This is turned on when the header must be shown even when there\nis no patch to be produced, e.g. only the mode was changed, or the path\nwas renamed, without changing the contents.  However, when it did so, it\nstill kept the special case for the \"-w\" mode, which meant that the\nplumbing would keep showing these phantom changes.\n\nThis corrects this historical inconsistency by allowing the plumbing to\nomit paths that are only stat-dirty from its output in the same way as it\nhandles whitespace only changes under \"-w\" option.\n\nThe change in the behaviour can be seen in the updated test.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff.c                  |    2 +-\n t/t4011-diff-symlink.sh |    5 +----\n 2 files changed, 2 insertions(+), 5 deletions(-)\n\ndiff --git a/diff.c b/diff.c\nindex c8e4366..0ecbf32 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1972,7 +1972,7 @@ static void builtin_diff(const char *name_a,\n \t\tstruct emit_callback ecbdata;\n \t\tconst struct userdiff_funcname *pe;\n \n-\t\tif (!DIFF_XDL_TST(o, WHITESPACE_FLAGS) || must_show_header) {\n+\t\tif (must_show_header) {\n \t\t\tfprintf(o->file, \"%s\", header.buf);\n \t\t\tstrbuf_reset(&header);\n \t\t}\ndiff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh\nindex 6097e19..7547c6d 100755\n--- a/t/t4011-diff-symlink.sh\n+++ b/t/t4011-diff-symlink.sh\n@@ -67,10 +67,7 @@ test_expect_success SYMLINKS 'diff removed symlink and file' '\n '\n \n test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' '\n-\tcat >expected <<-\\EOF &&\n-\tdiff --git a/frotz b/frotz\n-\tdiff --git a/nitfol b/nitfol\n-\tEOF\n+\t>expected &&\n \tsleep 3 &&\n \trm -f frotz &&\n \techo xyzzy >nitfol3 &&\n-- \n1.7.9.2.350.g74d65\n"},{"id":"185777","messageId":"1330568057-27304-5-git-send-email-gitster@pobox.com","threadId":"29791","inReplyTo":"1330568057-27304-1-git-send-email-gitster@pobox.com","subject":"[PATCH 4/4] diff --ignore-mode-change","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T02:14:17Z","receivedAt":"2012-03-01T02:14:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"It may be useful if you can view the diff while ignoring changes that only\ntouch the executable bit without changing the contents (e.g. a careless\nimports of vendor drop from tarballs), and this teaches the diff machinery\nto ignore them. A change that touches both contents and the executable bit\nis not ignored.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n diff.c |   29 ++++++++++++++++++++++++++++-\n diff.h |    1 +\n 2 files changed, 29 insertions(+), 1 deletion(-)\n\ndiff --git a/diff.c b/diff.c\nindex 0ecbf32..62fefba 100644\n--- a/diff.c\n+++ b/diff.c\n@@ -1920,7 +1920,8 @@ static void builtin_diff(const char *name_a,\n \t\tif (one->mode != two->mode) {\n \t\t\tstrbuf_addf(&header, \"%s%sold mode %06o%s\\n\", line_prefix, set, one->mode, reset);\n \t\t\tstrbuf_addf(&header, \"%s%snew mode %06o%s\\n\", line_prefix, set, two->mode, reset);\n-\t\t\tmust_show_header = 1;\n+\t\t\tif (!DIFF_OPT_TST(o, IGNORE_MODE_CHANGE))\n+\t\t\t\tmust_show_header = 1;\n \t\t}\n \t\tif (xfrm_msg)\n \t\t\tstrbuf_addstr(&header, xfrm_msg);\n@@ -3166,6 +3167,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)\n \t}\n \telse if (!strcmp(arg, \"--no-renames\"))\n \t\toptions->detect_rename = 0;\n+\telse if (!strcmp(arg, \"--ignore-mode-change\"))\n+\t\tDIFF_OPT_SET(options, IGNORE_MODE_CHANGE);\n \telse if (!strcmp(arg, \"--relative\"))\n \t\tDIFF_OPT_SET(options, RELATIVE_NAME);\n \telse if (!prefixcmp(arg, \"--relative=\")) {\n@@ -4191,10 +4194,34 @@ void diffcore_fix_diff_index(struct diff_options *options)\n \tqsort(q->queue, q->nr, sizeof(q->queue[0]), diffnamecmp);\n }\n \n+static void diffcore_ignore_mode_change(struct diff_options *diffopt)\n+{\n+\tint i;\n+\tstruct diff_queue_struct *q = &diff_queued_diff;\n+\tstruct diff_queue_struct outq;\n+\tDIFF_QUEUE_CLEAR(&outq);\n+\n+\tfor (i = 0; i < q->nr; i++) {\n+\t\tstruct diff_filepair *p = q->queue[i];\n+\n+\t\tif (DIFF_FILE_VALID(p->one) &&\n+\t\t    DIFF_FILE_VALID(p->two) &&\n+\t\t    (p->one->sha1_valid && p->two->sha1_valid) &&\n+\t\t    !hashcmp(p->one->sha1, p->two->sha1))\n+\t\t\tdiff_free_filepair(p); /* skip this */\n+\t\telse\n+\t\t\tdiff_q(&outq, p);\n+\t}\n+\tfree(q->queue);\n+\t*q = outq;\n+}\n+\n void diffcore_std(struct diff_options *options)\n {\n \tif (options->skip_stat_unmatch)\n \t\tdiffcore_skip_stat_unmatch(options);\n+\tif (DIFF_OPT_TST(options, IGNORE_MODE_CHANGE))\n+\t\tdiffcore_ignore_mode_change(options);\n \tif (!options->found_follow) {\n \t\t/* See try_to_follow_renames() in tree-diff.c */\n \t\tif (options->break_opt != -1)\ndiff --git a/diff.h b/diff.h\nindex 0083d92..9f10f72 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -78,6 +78,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data)\n #define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)\n #define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)\n #define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)\n+#define DIFF_OPT_IGNORE_MODE_CHANGE  (1 << 30)\n \n #define DIFF_OPT_TST(opts, flag)    ((opts)->flags & DIFF_OPT_##flag)\n #define DIFF_OPT_SET(opts, flag)    ((opts)->flags |= DIFF_OPT_##flag)\n-- \n1.7.9.2.350.g74d65\n"},{"id":"185796","messageId":"87399slmh4.fsf@thomas.inf.ethz.ch","threadId":"29791","inReplyTo":"1330568057-27304-3-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 2/4] t4011: illustrate \"diff-index -p\" on stat-dirty paths","fromName":"Thomas Rast","fromEmail":"trast@inf.ethz.ch","sentAt":"2012-03-01T09:05:59Z","receivedAt":"2012-03-01T09:05:59Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> The plumbing that looks at the working tree, i.e. \"diff-index\" and\n> \"diff-files\", always emit the \"diff --git a/path b/path\" header lines\n> without anything else for paths that are only stat-dirty (i.e. different\n> only because the cached stat information in the index no longer matches\n> that of the working tree, but the real contents are the same), when\n> these commands are run with \"-p\" option to produce patches.\n>\n> Illustrate this current behaviour.  The new part that uses \"-w\" option\n> demonstrates that we do not show any \"diff --git\" header for blobs whose\n> true contents are different but compares the same when whitespaces are\n> ignored, which is inconsistent with the behaviour for stat-dirty paths.\n[...]\n> -test_expect_success SYMLINKS 'diff identical, but newly created symlink' '\n> +test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' '\n>  \tcat >expected <<-\\EOF &&\n>  \tdiff --git a/frotz b/frotz\n> +\tdiff --git a/nitfol b/nitfol\n>  \tEOF\n> +\tsleep 3 &&\n> +\trm -f frotz &&\n> +\techo xyzzy >nitfol3 &&\n> +\tmv nitfol3 nitfol &&\n>  \tln -s xyzzy frotz &&\n>  \tgit diff-index -M -p $tree >current &&\n> +\tcompare_diff_patch expected current &&\n> +\n> +\t>expected &&\n> +\tgit diff-index -M -p -w $tree >current &&\n>  \tcompare_diff_patch expected current\n>  '\n\nI find the last bit of the commit message rather confusing.  You appear\nto be using -w here to diff the stat-dirty worktree nitfol 'xyzzy\\n'\nagainst the $tree:nitfol which is also 'xyzzy\\n'.\n\nIf that analysis is correct, then\n\n  we do not show any \"diff --git\" header for blobs whose true contents\n  are different but compares the same when whitespaces are ignored\n\nis not what is going on here; the blobs have exactly the same content.\nThe difference is that\n\n* without -w, the code \"knows\" from the lstat() data that the files are\n  different, prints a header, and then fails to find any differences;\n\n* with -w, the code correctly holds off on printing anything since it\n  will invariably have to inspect the contents beforehand.\n\nSo perhaps you can say\n\n  Illustrate this current behaviour.  Also demonstrate that with the\n  \"-w\" option, we (correctly) hold off showing a \"diff --git\" header\n  until actual differences have been found.  This also suppresses the\n  header for merely stat-dirty files, which is inconsistent.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"185800","messageId":"4F4F49FD.3090504@in.waw.pl","threadId":"29791","inReplyTo":"1330568057-27304-3-git-send-email-gitster@pobox.com","subject":"Re: [PATCH 2/4] t4011: illustrate \"diff-index -p\" on stat-dirty paths","fromName":"Zbigniew Jędrzejewski-Szmek","fromEmail":"zbyszek@in.waw.pl","sentAt":"2012-03-01T10:05:49Z","receivedAt":"2012-03-01T10:05:49Z","isPatch":true,"sender":{"key":"zbyszek@in.waw.pl","avatar":"https://avatars.githubusercontent.com/u/349618?v=4"},"body":"On 03/01/2012 03:14 AM, Junio C Hamano wrote:\n> -test_expect_success SYMLINKS 'diff unchanged symlink'  '\n> +test_expect_success SYMLINKS 'diff unchanged symlink and file'  '\n>   \ttree=$(git write-tree)&&\n> -\tgit update-index frotz&&\n> +\tgit update-index frotz nitfol&&\n>   \ttest -z \"$(git diff-index --name-only $tree)\"\n>   '\nHi,\nwhy modify and extend an existing test instead of adding a new separate \none? I think the test-suite should be getting more unittest-y, ie. \nchecking minimal aspects of functionality, not less.\n\nZbyszek\n\n> -test_expect_success SYMLINKS 'diff removed symlink' '\n> +test_expect_success SYMLINKS 'diff removed symlink and file' '\n>   \tcat>expected<<-\\EOF&&\n>   \tdiff --git a/frotz b/frotz\n>   \tdeleted file mode 120000\n> @@ -44,22 +52,39 @@ test_expect_success SYMLINKS 'diff removed symlink' '\n>   \t@@ -1 +0,0 @@\n>   \t-xyzzy\n>   \t\\ No newline at end of file\n> +\tdiff --git a/nitfol b/nitfol\n> +\tdeleted file mode 100644\n> +\tindex 7c465af..0000000\n> +\t--- a/nitfol\n> +\t+++ /dev/null\n> +\t@@ -1 +0,0 @@\n> +\t-xyzzy\n>   \tEOF\n>   \tmv frotz frotz2&&\n> +\tmv nitfol nitfol2&&\n>   \tgit diff-index -M -p $tree>current&&\n>   \tcompare_diff_patch expected current\n>   '\n"},{"id":"185823","messageId":"7v4nu8pai8.fsf@alter.siamese.dyndns.org","threadId":"29791","inReplyTo":"4F4F49FD.3090504@in.waw.pl","subject":"Re: [PATCH 2/4] t4011: illustrate \"diff-index -p\" on stat-dirty paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T16:10:55Z","receivedAt":"2012-03-01T16:10:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> writes:\n\n> On 03/01/2012 03:14 AM, Junio C Hamano wrote:\n>> -test_expect_success SYMLINKS 'diff unchanged symlink'  '\n>> +test_expect_success SYMLINKS 'diff unchanged symlink and file'  '\n>>   \ttree=$(git write-tree)&&\n>> -\tgit update-index frotz&&\n>> +\tgit update-index frotz nitfol&&\n>>   \ttest -z \"$(git diff-index --name-only $tree)\"\n>>   '\n> why modify and extend an existing test instead of adding a new\n> separate one?\n\nIf you are talking about assigning a new test number for a new script, it\nis better to avoid it when you can.  If on the other hand you meant to add\na new \"test_expect_success\" block, yes, that is one of the right things to\nconsider when adding tests, and I tried it both ways.\n\nThe result was easier to read when done the way it was posted.\n\nFor this update, you could keep the later test that originally checked\nsymlink intact and add an identical check for regular file, but the thing\nis, the behaviour change brought by the update in this series affect both\nsymlink and regular file comes from the same underlying mechanism, and\ndemonstrating the change in a single hunk that makes two phantom output\nlines disappear was far easier to review than two hunks each of which\nshows one phantom output line disapper.\n"},{"id":"185824","messageId":"7vzkc0nvlk.fsf@alter.siamese.dyndns.org","threadId":"29791","inReplyTo":"87399slmh4.fsf@thomas.inf.ethz.ch","subject":"Re: [PATCH 2/4] t4011: illustrate \"diff-index -p\" on stat-dirty paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T16:18:15Z","receivedAt":"2012-03-01T16:18:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@inf.ethz.ch> writes:\n\n> If that analysis is correct, then\n>\n>   we do not show any \"diff --git\" header for blobs whose true contents\n>   are different but compares the same when whitespaces are ignored\n>\n> is not what is going on here; the blobs have exactly the same content.\n\nTrue; an earlier draft actually had an 'echo \" xyzzy\" >nitfol' in there,\nbut it meant that it needed another annoying 'sleep 3' (I could have used\ntest-chmtime), so the test was updated but the above description stayed.\n\n> The difference is that\n>\n> * without -w, the code \"knows\" from the lstat() data that the files are\n>   different, prints a header, and then fails to find any differences;\n\nCorrect. Those quotes around \"knows\" are the most important ;-)\n\nThe code incorrectly thinks the stat dirtyness is all that it \"knows\";\neven though it has a way to act on a better knowledge from the xdiff these\ndays, it does not utilize it.\n\n> * with -w, the code correctly holds off on printing anything since it\n>   will invariably have to inspect the contents beforehand.\n>\n> So perhaps you can say\n>\n>   Illustrate this current behaviour.  Also demonstrate that with the\n>   \"-w\" option, we (correctly) hold off showing a \"diff --git\" header\n>   until actual differences have been found.  This also suppresses the\n>   header for merely stat-dirty files, which is inconsistent.\n\nThat is much better; thanks.\n"},{"id":"185826","messageId":"7vr4xcnu0d.fsf_-_@alter.siamese.dyndns.org","threadId":"29791","inReplyTo":"87399slmh4.fsf@thomas.inf.ethz.ch","subject":"[PATCH 2/4 v2] t4011: illustrate \"diff-index -p\" on stat-dirty paths","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-03-01T16:52:34Z","receivedAt":"2012-03-01T16:52:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The plumbing that looks at the working tree, i.e. \"diff-index\" and\n\"diff-files\", always emit the \"diff --git a/path b/path\" header lines\nwithout anything else for paths that are only stat-dirty (i.e. different\nonly because the cached stat information in the index no longer matches\nthat of the working tree, but the real contents are the same), when\nthese commands are run with \"-p\" option to produce patches.\n\nIllustrate this current behaviour.  Also demonstrate that with the \"-w\"\noption, we (correctly) hold off showing a \"diff --git\" header until actual\ndifferences have been found.  This also suppresses the header for merely\nstat-dirty files, which is inconsistent.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * This time with test-chmtime to get rid of the annoying 3 second delay\n   to invalidate the cached stat information.\n\n t/t4011-diff-symlink.sh |   46 +++++++++++++++++++++++++++++++++++++++-------\n 1 file changed, 39 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh\nindex cb47ec1..164f153 100755\n--- a/t/t4011-diff-symlink.sh\n+++ b/t/t4011-diff-symlink.sh\n@@ -9,7 +9,7 @@ test_description='Test diff of symlinks.\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/diff-lib.sh\n \n-test_expect_success SYMLINKS 'diff new symlink' '\n+test_expect_success SYMLINKS 'diff new symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n \tnew file mode 120000\n@@ -19,22 +19,30 @@ test_expect_success SYMLINKS 'diff new symlink' '\n \t@@ -0,0 +1 @@\n \t+xyzzy\n \t\\ No newline at end of file\n+\tdiff --git a/nitfol b/nitfol\n+\tnew file mode 100644\n+\tindex 0000000..7c465af\n+\t--- /dev/null\n+\t+++ b/nitfol\n+\t@@ -0,0 +1 @@\n+\t+xyzzy\n \tEOF\n \tln -s xyzzy frotz &&\n+\techo xyzzy >nitfol &&\n \tgit update-index &&\n \ttree=$(git write-tree) &&\n-\tgit update-index --add frotz &&\n+\tgit update-index --add frotz nitfol &&\n \tGIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current &&\n \tcompare_diff_patch expected current\n '\n \n-test_expect_success SYMLINKS 'diff unchanged symlink'  '\n+test_expect_success SYMLINKS 'diff unchanged symlink and file'  '\n \ttree=$(git write-tree) &&\n-\tgit update-index frotz &&\n+\tgit update-index frotz nitfol &&\n \ttest -z \"$(git diff-index --name-only $tree)\"\n '\n \n-test_expect_success SYMLINKS 'diff removed symlink' '\n+test_expect_success SYMLINKS 'diff removed symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n \tdeleted file mode 120000\n@@ -44,22 +52,38 @@ test_expect_success SYMLINKS 'diff removed symlink' '\n \t@@ -1 +0,0 @@\n \t-xyzzy\n \t\\ No newline at end of file\n+\tdiff --git a/nitfol b/nitfol\n+\tdeleted file mode 100644\n+\tindex 7c465af..0000000\n+\t--- a/nitfol\n+\t+++ /dev/null\n+\t@@ -1 +0,0 @@\n+\t-xyzzy\n \tEOF\n \tmv frotz frotz2 &&\n+\tmv nitfol nitfol2 &&\n \tgit diff-index -M -p $tree >current &&\n \tcompare_diff_patch expected current\n '\n \n-test_expect_success SYMLINKS 'diff identical, but newly created symlink' '\n+test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n+\tdiff --git a/nitfol b/nitfol\n \tEOF\n+\trm -f frotz nitfol &&\n+\techo xyzzy >nitfol &&\n+\ttest-chmtime +10 nitfol &&\n \tln -s xyzzy frotz &&\n \tgit diff-index -M -p $tree >current &&\n+\tcompare_diff_patch expected current &&\n+\n+\t>expected &&\n+\tgit diff-index -M -p -w $tree >current &&\n \tcompare_diff_patch expected current\n '\n \n-test_expect_success SYMLINKS 'diff different symlink' '\n+test_expect_success SYMLINKS 'diff different symlink and file' '\n \tcat >expected <<-\\EOF &&\n \tdiff --git a/frotz b/frotz\n \tindex 7c465af..df1db54 120000\n@@ -70,9 +94,17 @@ test_expect_success SYMLINKS 'diff different symlink' '\n \t\\ No newline at end of file\n \t+yxyyz\n \t\\ No newline at end of file\n+\tdiff --git a/nitfol b/nitfol\n+\tindex 7c465af..df1db54 100644\n+\t--- a/nitfol\n+\t+++ b/nitfol\n+\t@@ -1 +1 @@\n+\t-xyzzy\n+\t+yxyyz\n \tEOF\n \trm -f frotz &&\n \tln -s yxyyz frotz &&\n+\techo yxyyz >nitfol &&\n \tgit diff-index -M -p $tree >current &&\n \tcompare_diff_patch expected current\n '\n-- \n1.7.9.2.350.g74d65\n"}]}