{"thread":{"id":"59690","subject":"git diff -U0 header off-by-one error when deleting no lines","startedAt":"2023-05-03T20:49:01Z","lastAt":"2023-05-03T21:26:35Z","messageCount":3,"participants":["Lukas Tenbrink","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"476562","messageId":"B097ECB7-1976-40FC-B91D-A60D648F973B@gmail.com","threadId":"59690","inReplyTo":null,"subject":"git diff -U0 header off-by-one error when deleting no lines","fromName":"Lukas Tenbrink","fromEmail":"lukastenbrink@gmail.com","sentAt":"2023-05-03T20:48:44Z","receivedAt":"2023-05-03T20:49:01Z","isPatch":false,"sender":{"key":"lukastenbrink@gmail.com","avatar":null},"body":"Thank you for filling out a Git bug report!\nPlease answer the following questions to help us understand your issue.\n\nWhat did you do before the bug happened? (Steps to reproduce your issue)\n\nFull reproduction:\n\necho \"A\\nB\\nC\" > test1\necho \"A\\nB\\nC\\nD\\nE\\nF\" > test2\ngit diff -U0 test1 test2\n\n\nWhat did you expect to happen? (Expected behavior)\n\nI expected the header of the change to show the correct \"from line index\".\nFor reference, a plain git diff:\n\n> git diff test1 test2\ndiff --git a/test1 b/test2\nindex b1e6722..cead32e 100644\n--- a/test1\n+++ b/test2\n@@ -1,3 +1,6 @@\n A\n B\n C\n+D\n+E\n+F\n\nWhen passing -U0, I would expect the from line index to be 3 larger, because the 3 lines of context are omitted:\n\ndiff --git a/test1 b/test2\nindex b1e6722..cead32e 100644\n--- a/test1\n+++ b/test2\n@@ -4,0 +4,3 @@ C\n+D\n+E\n+F\n\n\nWhat happened instead? (Actual behavior)\n\nThe actual output places the new text at line 3:\n\n> git diff -U0 test1 test2\ndiff --git a/test1 b/test2\nindex b1e6722..cead32e 100644\n--- a/test1\n+++ b/test2\n@@ -3,0 +4,3 @@ C\n+D\n+E\n+F\n\n\nWhat's different between what you expected and what actually happened?\n\nThe header information \"-3\" is incorrect, because if a script wishes to insert the added code using the line indicator, it will place the newly added code at line 3 (before the C).\nInstead, I would expect \"-4\", because we wish to insert the DEF starting at line 4.\n\n\nAnything else you want to add:\n\nNotably, the bug does not occur when also deleting lines.\nNow, we are correctly placed at the beginning of line 3:\n\necho \"A\\nB\\nD\\nE\\nF\" > test3\n\n> git diff -U0 test1 test3\ndiff --git a/test1 b/test3\nindex b1e6722..98422e9 100644\n--- a/test1\n+++ b/test3\n@@ -3 +3,3 @@ B\n-C\n+D\n+E\n+F\n\n\n[System Info]\ngit version:\ngit version 2.39.2 (Apple Git-143)\ncpu: x86_64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nfeature: fsmonitor--daemon\nuname: Darwin 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:17 PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64 x86_64\ncompiler info: clang: 14.0.3 (clang-1403.0.22.14.1)\nlibc info: no libc information available\n$SHELL (typically, interactive shell): /bin/zsh\n\n\n[Enabled Hooks]\n\n"},{"id":"476563","messageId":"xmqqednxp0ys.fsf@gitster.g","threadId":"59690","inReplyTo":"B097ECB7-1976-40FC-B91D-A60D648F973B@gmail.com","subject":"Re: git diff -U0 header off-by-one error when deleting no lines","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-03T21:19:23Z","receivedAt":"2023-05-03T21:19:29Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Lukas Tenbrink <lukastenbrink@gmail.com> writes:\n\n> Thank you for filling out a Git bug report!\n> Please answer the following questions to help us understand your issue.\n>\n> What did you do before the bug happened? (Steps to reproduce your issue)\n>\n> Full reproduction:\n>\n> echo \"A\\nB\\nC\" > test1\n> echo \"A\\nB\\nC\\nD\\nE\\nF\" > test2\n\nFor many folks, the above will place one line each in these files.\nFor portability, you'd need to do something like\n\n\tprintf \"%s\\n\" A B C >test1\n\tprintf \"%s\\n\" A B C D E F >test2\n\n> git diff -U0 test1 test2\n\n> The actual output places the new text at line 3:\n>\n>> git diff -U0 test1 test2\n> diff --git a/test1 b/test2\n> index b1e6722..cead32e 100644\n> --- a/test1\n> +++ b/test2\n> @@ -3,0 +4,3 @@ C\n> +D\n> +E\n> +F\n\nI think this is very much in line with how \"diff -U0\" by other\npeople do it, and any tool like \"git am\" that need to read \"diff\"\noutput need to understand how these output work correctly; \"-U0\"\noutput and \",1\" that is omitted are things that have confused us\ntool writers forever ;-).\n\nWith -U0, you'd get\n\n    $ diff -U0 test1 test2\n    --- test1       2023-05-03 14:02:27.718960038 -0700\n    +++ test2       2023-05-03 14:02:20.094156573 -0700\n    @@ -3,0 +4,3 @@\n    +D\n    +E\n    +F\n\nwhich has \"-3,0\" that says \"there were 3 lines before this hunk that\ndid not have any line before the change\".\n\nThis might be unintuitive, but it is specified by POSIX.  \n\nOpen\n\n  https://pubs.opengroup.org/onlinepubs/9699919799/\n\nand look for \"@@\".\n\n    \"@@-%s+%s@@\", <file1 range>, <file2 range>\n\n    Each <range> field shall be of the form:\n\n    \"%1d\", <beginning line number>\n\n    or:\n\n    \"%1d,1\", <beginning line number>\n\n    if the range contains exactly one line, and:\n\n    \"%1d,%1d\", <beginning line number>, <number of lines>\n\n    otherwise.\n\n    If a range is empty, its beginning line number shall be the\n    number of the line just before the range, or 0 if the empty\n    range starts the file.\n\nSo a patch that adds lines to an empty file would look like\n\n    $ diff -U0 /dev/null test1\n    --- /dev/null   2023-04-29 22:24:54.395999895 -0700\n    +++ test1       2023-05-03 14:02:27.718960038 -0700\n    @@ -0,0 +1,3 @@\n    +A\n    +B\n    +C\n\njust as specified.  Note \"-0,0\" that says \"there was no line before\nthis hunk before this change\".\n"},{"id":"476566","messageId":"7F1955DC-0296-470F-96F7-7BB96860D4BD@gmail.com","threadId":"59690","inReplyTo":"xmqqednxp0ys.fsf@gitster.g","subject":"Re: git diff -U0 header off-by-one error when deleting no lines","fromName":"Lukas Tenbrink","fromEmail":"lukastenbrink@gmail.com","sentAt":"2023-05-03T21:26:17Z","receivedAt":"2023-05-03T21:26:35Z","isPatch":false,"sender":{"key":"lukastenbrink@gmail.com","avatar":null},"body":"> This might be unintuitive, but it is specified by POSIX.  \n> \n> Open\n> \n>  https://pubs.opengroup.org/onlinepubs/9699919799/\n> \n> and look for \"@@\".\n> \n>    \"@@-%s+%s@@\", <file1 range>, <file2 range>\n> \n>    Each <range> field shall be of the form:\n> \n>    \"%1d\", <beginning line number>\n> \n>    or:\n> \n>    \"%1d,1\", <beginning line number>\n> \n>    if the range contains exactly one line, and:\n> \n>    \"%1d,%1d\", <beginning line number>, <number of lines>\n> \n>    otherwise.\n> \n>    If a range is empty, its beginning line number shall be the\n>    number of the line just before the range, or 0 if the empty\n>    range starts the file.\n> \n> So a patch that adds lines to an empty file would look like\n> \n>    $ diff -U0 /dev/null test1\n>    --- /dev/null   2023-04-29 22:24:54.395999895 -0700\n>    +++ test1       2023-05-03 14:02:27.718960038 -0700\n>    @@ -0,0 +1,3 @@\n>    +A\n>    +B\n>    +C\n> \n> just as specified.  Note \"-0,0\" that says \"there was no line before\n> this hunk before this change\".\n\n\nThat is indeed fairly unintuitive, but I appreciate the detailed response. I shall adapt my scripts.\nThanks and best wishes,\n\nLukas\n\n"}]}