{"thread":{"id":"63660","subject":"Rename detection fails on symlinked files","startedAt":"2025-06-17T11:14:00Z","lastAt":"2025-09-25T07:39:19Z","messageCount":4,"participants":["Michal Suchánek","Elijah Newren"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"520311","messageId":"aFFN9UHCspTjliMv@kitsune.suse.cz","threadId":"63660","inReplyTo":null,"subject":"Rename detection fails on symlinked files","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-06-17T11:13:57Z","receivedAt":"2025-06-17T11:14:00Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"commit 5d51b10d8b5206ef5eeb9d214237b2ec2e0b789e (HEAD -> master)\nAuthor: Michal Suchanek <msuchanek@suse.de>\nDate:   Tue Jun 17 13:08:51 2025 +0200\n\n    rename file\n\ndiff --git a/somefile b/somefile-renamed\nsimilarity index 100%\nrename from somefile\nrename to somefile-renamed\n\nln -s somefile-renamed somefile\ngit add somefile\ngit commit --amend\n\ncommit 377d9bd045aed61c7be55482f3c98f8f9d04a33d (HEAD -> master)\nAuthor: Michal Suchanek <msuchanek@suse.de>\nDate:   Tue Jun 17 13:08:51 2025 +0200\n\n    rename file\n\ndiff --git a/somefile b/somefile\ndeleted file mode 100644\nindex a53032b..0000000\nBinary files a/somefile and /dev/null differ\ndiff --git a/somefile b/somefile\nnew file mode 120000\nindex 0000000..fc49048\n--- /dev/null\n+++ b/somefile\n@@ -0,0 +1 @@\n+somefile-renamed\n\\ No newline at end of file\ndiff --git a/somefile-renamed b/somefile-renamed\nnew file mode 100644\nindex 0000000..a53032b\nBinary files /dev/null and b/somefile-renamed differ\n\nCan the rename detection be fixed to detect symlinked files as well?\n\nThanks\n\nMichal\n"},{"id":"520325","messageId":"CABPp-BFdEn8rYu+FW+CdgrKNDUGBY9h6ePSH-vjYy-f_Pji0-Q@mail.gmail.com","threadId":"63660","inReplyTo":"aFFN9UHCspTjliMv@kitsune.suse.cz","subject":"Re: Rename detection fails on symlinked files","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2025-06-17T17:44:23Z","receivedAt":"2025-06-17T17:44:36Z","isPatch":false,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"Hi,\n\nOn Tue, Jun 17, 2025 at 4:16 AM Michal Suchánek <msuchanek@suse.de> wrote:\n\nI think your subject might be slightly misleading, and that a more\naccurate subject might be: Rename detection is not performed for files\nstill present in the target version.  Let me explain why and you can\ncheck if I'm understanding your problem setup correctly.\n\n> commit 5d51b10d8b5206ef5eeb9d214237b2ec2e0b789e (HEAD -> master)\n> Author: Michal Suchanek <msuchanek@suse.de>\n> Date:   Tue Jun 17 13:08:51 2025 +0200\n>\n>     rename file\n>\n> diff --git a/somefile b/somefile-renamed\n> similarity index 100%\n> rename from somefile\n> rename to somefile-renamed\n\nSo you've renamed a file, detected at the time you run git log -p.\n\n> ln -s somefile-renamed somefile\n> git add somefile\n> git commit --amend\n\nHere, you reintroduce the original file, as a symlink, and amend the commit.\n\n> commit 377d9bd045aed61c7be55482f3c98f8f9d04a33d (HEAD -> master)\n> Author: Michal Suchanek <msuchanek@suse.de>\n> Date:   Tue Jun 17 13:08:51 2025 +0200\n>\n>     rename file\n>\n> diff --git a/somefile b/somefile\n> deleted file mode 100644\n> index a53032b..0000000\n> Binary files a/somefile and /dev/null differ\n> diff --git a/somefile b/somefile\n> new file mode 120000\n> index 0000000..fc49048\n> --- /dev/null\n> +++ b/somefile\n> @@ -0,0 +1 @@\n> +somefile-renamed\n> \\ No newline at end of file\n> diff --git a/somefile-renamed b/somefile-renamed\n> new file mode 100644\n> index 0000000..a53032b\n> Binary files /dev/null and b/somefile-renamed differ\n\nIf I'm understanding the behavior that bothers you, it doesn't seem to\nbe related to symlinks.  You could create any regular text file\nunrelated to the original somefile (or even introduce a submodule) and\nplace it in somefile and amend the commit, and you'd see that the\nrename wasn't detected.  For example, replace your `ln -s/git add/git\ncommit --amend` sequence with\n\n$ echo content >somefile\n$ git add somefile\n$ git commit --amend\n\nand you'd see that there was no rename detected from the original\nsomefile to the new somefile-renamed.  By default, if the file is\npresent in both the source and the destination, it is not involved in\nrename detection.\n\n> Can the rename detection be fixed to detect symlinked files as well?\n\nSymlink renames can be and are detected, by default.  For example:\n\n$ ln -s somefile old-symlink\n$ git add old-symlink\n$ git commit -m old\n$ git mv old-symlink new-symlink\n$ git commit -m new\n$ git diff HEAD~1\ndiff --git a/old-symlink b/new-symlink\nsimilarity index 100%\nrename from old-symlink\nrename to new-symlink\n\nBut from your example, you're not renaming a symlink, so instead of\n\"Can rename detection handle symlinked files?\", your question really\nis more of \"Can a renamed file be detected even when some other\nfile/link/submodule is immediately placed where the renamed file used\nto be?\"\n\ngit assumes, by default, that a file which exists in both the source\nand destination are \"related\" and will only look for renames in\ndeleted or added files.  Allowing git to mark a file as both a delete\nand an add even when it's present in both the source and the target is\nthe job of break detection, which is not turned on by default.\nFurther, break detection and rename detection have a bug or two when\nused together (brought up on the mailing list by Junio some years\nago), which might need to be fixed for your example to work as you\nexpect if you try to turn on break detection.\n\nAlso, not sure how deep your interest in break detection goes, but\nmerge-ort was written with some implicit assumptions that break\ndetection is _not_ active.  Trying to retrofit it to support break\ndetection might take a significant chunk of work; and even if someone\nis motivated to make it work, it'd defeat the safety of every\noptimization added to it (making it orders of magnitude slower), and\nalso tack on a significant performance penalty on top of all that\n(break detection is not cheap when at least one side of the merge has\na significant number of files modified).\n\nAnyway...does that help explain what's going on?\n"},{"id":"520327","messageId":"aFGypy83l9DSPvF4@kitsune.suse.cz","threadId":"63660","inReplyTo":"CABPp-BFdEn8rYu+FW+CdgrKNDUGBY9h6ePSH-vjYy-f_Pji0-Q@mail.gmail.com","subject":"Re: Rename detection fails on symlinked files","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-06-17T18:23:35Z","receivedAt":"2025-06-17T18:23:38Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"On Tue, Jun 17, 2025 at 10:44:23AM -0700, Elijah Newren wrote:\n> Hi,\n> \n> On Tue, Jun 17, 2025 at 4:16 AM Michal Suchánek <msuchanek@suse.de> wrote:\n> \n> I think your subject might be slightly misleading, and that a more\n> accurate subject might be: Rename detection is not performed for files\n> still present in the target version.  Let me explain why and you can\n> check if I'm understanding your problem setup correctly.\n> \n> > commit 5d51b10d8b5206ef5eeb9d214237b2ec2e0b789e (HEAD -> master)\n> > Author: Michal Suchanek <msuchanek@suse.de>\n> > Date:   Tue Jun 17 13:08:51 2025 +0200\n> >\n> >     rename file\n> >\n> > diff --git a/somefile b/somefile-renamed\n> > similarity index 100%\n> > rename from somefile\n> > rename to somefile-renamed\n> \n> So you've renamed a file, detected at the time you run git log -p.\n> \n> > ln -s somefile-renamed somefile\n> > git add somefile\n> > git commit --amend\n> \n> Here, you reintroduce the original file, as a symlink, and amend the commit.\n> \n> > commit 377d9bd045aed61c7be55482f3c98f8f9d04a33d (HEAD -> master)\n> > Author: Michal Suchanek <msuchanek@suse.de>\n> > Date:   Tue Jun 17 13:08:51 2025 +0200\n> >\n> >     rename file\n> >\n> > diff --git a/somefile b/somefile\n> > deleted file mode 100644\n> > index a53032b..0000000\n> > Binary files a/somefile and /dev/null differ\n> > diff --git a/somefile b/somefile\n> > new file mode 120000\n> > index 0000000..fc49048\n> > --- /dev/null\n> > +++ b/somefile\n> > @@ -0,0 +1 @@\n> > +somefile-renamed\n> > \\ No newline at end of file\n> > diff --git a/somefile-renamed b/somefile-renamed\n> > new file mode 100644\n> > index 0000000..a53032b\n> > Binary files /dev/null and b/somefile-renamed differ\n> \n> If I'm understanding the behavior that bothers you, it doesn't seem to\n> be related to symlinks.  You could create any regular text file\n> unrelated to the original somefile (or even introduce a submodule) and\n> place it in somefile and amend the commit, and you'd see that the\n> rename wasn't detected.  For example, replace your `ln -s/git add/git\n> commit --amend` sequence with\n> \n> $ echo content >somefile\n> $ git add somefile\n> $ git commit --amend\n> \n> and you'd see that there was no rename detected from the original\n> somefile to the new somefile-renamed.  By default, if the file is\n> present in both the source and the destination, it is not involved in\n> rename detection.\n> \n> > Can the rename detection be fixed to detect symlinked files as well?\n> \n> Symlink renames can be and are detected, by default.  For example:\n> \n> $ ln -s somefile old-symlink\n> $ git add old-symlink\n> $ git commit -m old\n> $ git mv old-symlink new-symlink\n> $ git commit -m new\n> $ git diff HEAD~1\n> diff --git a/old-symlink b/new-symlink\n> similarity index 100%\n> rename from old-symlink\n> rename to new-symlink\n> \n> But from your example, you're not renaming a symlink, so instead of\n> \"Can rename detection handle symlinked files?\", your question really\n> is more of \"Can a renamed file be detected even when some other\n> file/link/submodule is immediately placed where the renamed file used\n> to be?\"\n> \n> git assumes, by default, that a file which exists in both the source\n> and destination are \"related\" and will only look for renames in\n> deleted or added files.  Allowing git to mark a file as both a delete\n> and an add even when it's present in both the source and the target is\n> the job of break detection, which is not turned on by default.\n> Further, break detection and rename detection have a bug or two when\n> used together (brought up on the mailing list by Junio some years\n> ago), which might need to be fixed for your example to work as you\n> expect if you try to turn on break detection.\n\nThere is indeed something fishy going on:\n\ngit show -B100 (or any value of B, really)\n\ncommit 377d9bd045aed61c7be55482f3c98f8f9d04a33d (HEAD -> master)\nAuthor: Michal Suchanek <msuchanek@suse.de>\nDate:   Tue Jun 17 13:08:51 2025 +0200\n\n    rename file\n\ndiff --git a/somefile b/somefile\ndeleted file mode 100644\nindex a53032b..0000000\nBinary files a/somefile and /dev/null differ\ndiff --git a/somefile b/somefile\nnew file mode 120000\nindex 0000000..fc49048\n--- /dev/null\n+++ b/somefile\n@@ -0,0 +1 @@\n+somefile-renamed\n\\ No newline at end of file\ndiff --git a/somefile b/somefile-renamed\nsimilarity index 100%\ncopy from somefile\ncopy to somefile-renamed\n\n> Also, not sure how deep your interest in break detection goes, but\n> merge-ort was written with some implicit assumptions that break\n> detection is _not_ active.  Trying to retrofit it to support break\n> detection might take a significant chunk of work; and even if someone\n> is motivated to make it work, it'd defeat the safety of every\n> optimization added to it (making it orders of magnitude slower), and\n> also tack on a significant performance penalty on top of all that\n> (break detection is not cheap when at least one side of the merge has\n> a significant number of files modified).\n\nDoes merge-ort at least refuse to run with break detection enabled?\n\nThis is mainly for examining changes, following a file trough history, and\nsuch. When it comes to that there are other merge strategies besides ort so it\nmay not be completely hopeless trying to merge across renames, too.\n\nThanks\n\nMichal\n"},{"id":"527301","messageId":"aNTxpDrfUKsbvkZt@kitsune.suse.cz","threadId":"63660","inReplyTo":"CABPp-BFdEn8rYu+FW+CdgrKNDUGBY9h6ePSH-vjYy-f_Pji0-Q@mail.gmail.com","subject":"Re: Rename detection fails on symlinked files","fromName":"Michal Suchánek","fromEmail":"msuchanek@suse.de","sentAt":"2025-09-25T07:39:16Z","receivedAt":"2025-09-25T07:39:19Z","isPatch":false,"sender":{"key":"msuchanek@suse.de","avatar":"https://avatars.githubusercontent.com/u/787652?v=4"},"body":"On Tue, Jun 17, 2025 at 10:44:23AM -0700, Elijah Newren wrote:\n> Hi,\n> \n> On Tue, Jun 17, 2025 at 4:16 AM Michal Suchánek <msuchanek@suse.de> wrote:\n> \n> I think your subject might be slightly misleading, and that a more\n> accurate subject might be: Rename detection is not performed for files\n> still present in the target version.  Let me explain why and you can\n> check if I'm understanding your problem setup correctly.\n> \n> > commit 5d51b10d8b5206ef5eeb9d214237b2ec2e0b789e (HEAD -> master)\n> > Author: Michal Suchanek <msuchanek@suse.de>\n> > Date:   Tue Jun 17 13:08:51 2025 +0200\n> >\n> >     rename file\n> >\n> > diff --git a/somefile b/somefile-renamed\n> > similarity index 100%\n> > rename from somefile\n> > rename to somefile-renamed\n> \n> So you've renamed a file, detected at the time you run git log -p.\n> \n> > ln -s somefile-renamed somefile\n> > git add somefile\n> > git commit --amend\n> \n> Here, you reintroduce the original file, as a symlink, and amend the commit.\n\nNo, there is no original file:\n\ndiff --git a/some file b/some file\ndeleted file mode 100644\nindex b649a9b..0000000\n--- a/some file \n+++ /dev/null\n@@ -1 +0,0 @@\n-some text\n\\ No newline at end of file\ndiff --git a/some file b/some file\nnew file mode 120000\nindex 0000000..b649a9b\n--- /dev/null\n+++ b/some file \n@@ -0,0 +1 @@\n+some text\n\\ No newline at end of file\n\nSee, the plain file and symlink is so different that changing the mode\nto symlink is represented as removing a file, and adding a symlink. Not\nsame file mode change, not even a rename. The symlink is so different\nfrom the file that it's completely unrelated, even with exactly same\ncontent. Mode change to/from symlink always breaks, regardless of content and\nthe break rewrites setting.\n\ndiff --git a/some file b/some file\ndeleted file mode 100644\nindex b649a9b..0000000\n--- a/some file \n+++ /dev/null\n@@ -1 +0,0 @@\n-some text\n\\ No newline at end of file\ndiff --git a/some file b/some file\nnew file mode 120000\nindex 0000000..b649a9b\n--- /dev/null\n+++ b/some file \n@@ -0,0 +1 @@\n+some text\n\\ No newline at end of file\ndiff --git a/some other file b/some other file\nnew file mode 100644\nindex 0000000..b649a9b\n--- /dev/null\n+++ b/some other file   \n@@ -0,0 +1 @@\n+some text\n\\ No newline at end of file\n\nAnd here we now have one removal and two additions of the same content,\nno rename detected.\n\nSo git cannot agree with itself if symlink and plain file is actually\nthe same file or not. They are presented as comletely unrelated to the\nuser yet rename detection fails to detect the rename of the plain file\nthat is completely unrelated to the added symlink. That is the\ndiscrepancy, and the bug.\n\nThanks\n\nMichal\n"}]}