{"thread":{"id":"62434","subject":"`git apply -p` doesn't remove source prefix in 'rename' diff entries.","startedAt":"2024-11-01T05:03:11Z","lastAt":"2024-11-05T00:36:22Z","messageCount":4,"participants":["Iago-lito","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"506434","messageId":"3af246eb-3473-4964-9aed-ecff62b215b7@cleb.io","threadId":"62434","inReplyTo":null,"subject":"`git apply -p` doesn't remove source prefix in 'rename' diff entries.","fromName":"Iago-lito","fromEmail":"iago-lito@cleb.io","sentAt":"2024-11-01T00:17:20Z","receivedAt":"2024-11-01T05:03:11Z","isPatch":false,"sender":{"key":"iago-lito@cleb.io","avatar":null},"body":"Hello,\n\nI have troubles understanding the behaviour of `git apply` with respect to renames in a `--no-index` context.\n\nLet us craft a toy folder:\n```sh\n$ mkdir x\n$ echo a > x/a # To be modified.\n$ echo b > x/b # To be renamed.\n```\n\nDuplicate it twice to get three identical folders `x = y = z`.\n\n```sh\n$ cp -r x y\n$ cp -r x z\n```\n\nModify `y`:\n```sh\n$ echo newline >> y/a # Edit.\n$ mv y/b y/c # Rename.\n```\n\nNow I would like to use git as a \"better GNU patch\".\nCalculate the diff from `x` to `y`:\n```sh\n$ git diff --no-prefix x y | tee patch\ndiff --git x/a y/a\nindex 7898192..4030aa5 100644\n--- x/a\n+++ y/a\n@@ -1 +1,2 @@\na\n+newline\ndiff --git x/b y/c\nsimilarity index 100%\nrename from x/b\nrename to y/c\n```\n\nThen apply this patch to `z` so as to end up with `x != y = z`:\n```sh\n$ git apply -p1 --directory z patch\nerror: z/x/b: No such file or directory\n```\n\nI would expect `z/b` to be renamed into `z/c`, but I get the above error instead.\n\nAlthough understand that `z/x/b` is not a valid path, I don't understand that git produces such a path, because I'm assuming that `-p1` is supposed to remove the `x/` part.\n\nInterestingly, the procedure works fine without the rename. The rename also worth fine if I manually remove the `x/` and `y/` prefixes from the rename lines in the patch.\n\nThis makes the behaviour of `git apply` appear inconsistent. It is nonetheless expected ? If so, why ? If not, then is it a bug ?\n\nThank you for support,\n\n[System Info]\ngit version:\ngit version 2.46.2\ncpu: x86_64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nlibcurl: 8.10.1\nOpenSSL: OpenSSL 3.3.2 3 Sep 2024\nzlib: 1.3.1\nuname: Linux 6.10.10-arch1-1 #1 SMP PREEMPT_DYNAMIC Thu, 12 Sep 2024\n17:21:02 +0000 x86_64\ncompiler info: gnuc: 14.2\nlibc info: glibc: 2.40\n$SHELL (typically, interactive shell): /usr/bin/zsh\n\n\n[Enabled Hooks]\nnot run from a git repository - no hooks to show\n\n--\nIago-lito\n"},{"id":"506435","messageId":"xmqq4j4r4enh.fsf@gitster.g","threadId":"62434","inReplyTo":"3af246eb-3473-4964-9aed-ecff62b215b7@cleb.io","subject":"Re: `git apply -p` doesn't remove source prefix in 'rename' diff entries.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-11-01T07:05:54Z","receivedAt":"2024-11-01T07:05:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Iago-lito <iago-lito@cleb.io> writes:\n\n> Hello,\n>\n> I have troubles understanding the behaviour of `git apply` with respect to renames in a `--no-index` context.\n>\n> Let us craft a toy folder:\n> ```sh\n> $ mkdir x\n> $ echo a > x/a # To be modified.\n> $ echo b > x/b # To be renamed.\n> ```\n>\n> Duplicate it twice to get three identical folders `x = y = z`.\n>\n> ```sh\n> $ cp -r x y\n> $ cp -r x z\n> ```\n>\n> Modify `y`:\n> ```sh\n> $ echo newline >> y/a # Edit.\n> $ mv y/b y/c # Rename.\n> ```\n>\n> Now I would like to use git as a \"better GNU patch\".\n> Calculate the diff from `x` to `y`:\n> ```sh\n> $ git diff --no-prefix x y | tee patch\n> diff --git x/a y/a\n> index 7898192..4030aa5 100644\n> --- x/a\n> +++ y/a\n> @@ -1 +1,2 @@\n> a\n> +newline\n> diff --git x/b y/c\n> similarity index 100%\n> rename from x/b\n> rename to y/c\n> ```\n\nInteresting.  I think \"git diff --no-index\" is \"wrong\" here, but\n\"wrong\" is not in the sense that it is _incorrect_, but in the sense\nthat it merely is incompatible with what you are trying to achieve.\n\nIf you had files a and b, modified a in place and renamed b to c,\nand if you did this in a repository with tracked files, you would\nhave seen\n\n   $ git diff --src-prefix=x --dst-prefix=y\n   diff --git x/a y/a\n   index ...\n   --- x/a\n   +++ y/a\n   ...\n   diff --git x/b y/c\n   similarity index 100%\n   rename from b\n   rename to c\n\nNotice how \"rename from\" and \"rename to\" information is different in\nthe \"real\" git-diff output, as opposed to \"git diff --no-index\"\noutput you have?\n\nAt least when comparing two directories, \"git diff --no-index X Y\"\ncould be interpreted as a request to treat as if X and Y were\ncheckouts from two Git commits X and Y, and by comparing them the\noutput should be identical to the result of comparing the contents\nof commits X and Y.\n\nBut feeding \"git apply\" however may not be the only reason why\npeople are using \"diff --no-index X Y\", and there may be a\nlegitimate reason why peole want to see \"from x/b to y/c\" in the\noutput, so unconditionally changing the output may very likely break\nworkflows of other people.\n\n\n"},{"id":"506577","messageId":"d67e133c-f287-4009-9244-eaeffd84daeb@cleb.io","threadId":"62434","inReplyTo":"xmqq4j4r4enh.fsf@gitster.g","subject":"Re: `git apply -p` doesn't remove source prefix in 'rename' diff entries.","fromName":"Iago-lito","fromEmail":"iago-lito@cleb.io","sentAt":"2024-11-04T20:35:47Z","receivedAt":"2024-11-04T23:15:34Z","isPatch":false,"sender":{"key":"iago-lito@cleb.io","avatar":null},"body":"Hello @Junio, and thank you for feedback :)\n\nIf I understand correctly, you are suggesting that `git diff`/`git \napply` are behaving correctly here, but they might not be the right tool \nfor the job? I sort of sense that `git` could achieve this \"z = x + 𝛥y\" \nfolder operation (because it has all the machinery required to do so), \nbut I'm not sure how to leverage it correctly. Do I need to get into \n\"plumbing\"?\n\n--\nIago-lito\n\n\nOn 01/11/2024 08:05, Junio C Hamano wrote:\n> Iago-lito <iago-lito@cleb.io> writes:\n>\n>> Hello,\n>>\n>> I have troubles understanding the behaviour of `git apply` with respect to renames in a `--no-index` context.\n>>\n>> Let us craft a toy folder:\n>> ```sh\n>> $ mkdir x\n>> $ echo a > x/a # To be modified.\n>> $ echo b > x/b # To be renamed.\n>> ```\n>>\n>> Duplicate it twice to get three identical folders `x = y = z`.\n>>\n>> ```sh\n>> $ cp -r x y\n>> $ cp -r x z\n>> ```\n>>\n>> Modify `y`:\n>> ```sh\n>> $ echo newline >> y/a # Edit.\n>> $ mv y/b y/c # Rename.\n>> ```\n>>\n>> Now I would like to use git as a \"better GNU patch\".\n>> Calculate the diff from `x` to `y`:\n>> ```sh\n>> $ git diff --no-prefix x y | tee patch\n>> diff --git x/a y/a\n>> index 7898192..4030aa5 100644\n>> --- x/a\n>> +++ y/a\n>> @@ -1 +1,2 @@\n>> a\n>> +newline\n>> diff --git x/b y/c\n>> similarity index 100%\n>> rename from x/b\n>> rename to y/c\n>> ```\n> Interesting.  I think \"git diff --no-index\" is \"wrong\" here, but\n> \"wrong\" is not in the sense that it is _incorrect_, but in the sense\n> that it merely is incompatible with what you are trying to achieve.\n>\n> If you had files a and b, modified a in place and renamed b to c,\n> and if you did this in a repository with tracked files, you would\n> have seen\n>\n>     $ git diff --src-prefix=x --dst-prefix=y\n>     diff --git x/a y/a\n>     index ...\n>     --- x/a\n>     +++ y/a\n>     ...\n>     diff --git x/b y/c\n>     similarity index 100%\n>     rename from b\n>     rename to c\n>\n> Notice how \"rename from\" and \"rename to\" information is different in\n> the \"real\" git-diff output, as opposed to \"git diff --no-index\"\n> output you have?\n>\n> At least when comparing two directories, \"git diff --no-index X Y\"\n> could be interpreted as a request to treat as if X and Y were\n> checkouts from two Git commits X and Y, and by comparing them the\n> output should be identical to the result of comparing the contents\n> of commits X and Y.\n>\n> But feeding \"git apply\" however may not be the only reason why\n> people are using \"diff --no-index X Y\", and there may be a\n> legitimate reason why peole want to see \"from x/b to y/c\" in the\n> output, so unconditionally changing the output may very likely break\n> workflows of other people.\n>\n>\n\n"},{"id":"506583","messageId":"xmqqjzdiv7nf.fsf@gitster.g","threadId":"62434","inReplyTo":"d67e133c-f287-4009-9244-eaeffd84daeb@cleb.io","subject":"Re: `git apply -p` doesn't remove source prefix in 'rename' diff entries.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-11-05T00:36:20Z","receivedAt":"2024-11-05T00:36:22Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Iago-lito <iago-lito@cleb.io> writes:\n\n> Hello @Junio, and thank you for feedback :)\n>\n> If I understand correctly, you are suggesting that `git diff`/`git\n> apply` are behaving correctly here, but they might not be the right\n> tool for the job?\n\nNo.  \n\n\"git diff --no-index\" is giving \"wrong\" information in the\nrename/copy extended diff headers, but regular \"git diff\" is\nperfectly fine.  Also \"git apply\" is perfectly fine.\n\nAnd the \"wrong\"-ness above is in the eyes of beholder, in the sense\nthat the original folks who coaxed \"these two directories are not\ncontrolled by Git, but unlike GNU diff, \"git diff\" has a few nice\nbells and whistles, so instead of adding these properly to GNU diff,\nabuse \"git diff\" to add a mode where two directories are compared\"\nprobably did not view that \"git diff --no-index X Y\" must be\nequivalent to committing the contents of X first and then Y next,\nand then doing \"git show\" on the resulting history.\n\nI do not know why being different and showing X and Y as part of the\npaths reported on the \"rename from\" etc. extended diff headers could\nsometimes be useful, but they must have had some use cases I am not\nseeing offhand.\n\nSo in order to lift this \"wrong\"-ness, you'd probably want an option\nto the \"no-index\" mode of the \"git diff\" (in \"diff-no-index.c\") to\nomit the leading directory name (i.e. X/ and Y/) from these\nrename/copy extended diff headers.  Then your toy example would work\nwhen the \"git diff --no-index --fixed-rename-copy-path-info\" is used.\n"}]}