{"thread":{"id":"19669","subject":"Troubles when directory is replaced by symlink","startedAt":"2009-06-05T05:43:08Z","lastAt":"2009-06-26T14:14:26Z","messageCount":9,"participants":["Alexander Gladysh","Jeff King","Kjetil Barvik","James Pickens","Johannes Sixt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"115473","messageId":"c6c947f60906042243v2e36251dn9a46343cf6b8a2f4@mail.gmail.com","threadId":"19669","inReplyTo":null,"subject":"Troubles when directory is replaced by symlink","fromName":"Alexander Gladysh","fromEmail":"agladysh@gmail.com","sentAt":"2009-06-05T05:43:08Z","receivedAt":"2009-06-05T05:43:08Z","isPatch":false,"sender":{"key":"agladysh@gmail.com","avatar":"https://avatars.githubusercontent.com/u/38239?v=4"},"body":"Hi, list!\n\nOS X 10.5.7\n\n$ git --version\ngit version 1.6.3.2\n\nIn my master branch I've had this structure:\n\nroot /\n    directory1 /\n        some-files\n    directory2 /\n        copy-of-directory1 /\n            some-files\n\nIn a separate branch I replaced copy-of-directory1 with a symlink to\n../directory1. I did it in two commits: first remove\ncopy-of-directory1, in second commit -- create the symlink.\n\nMy master branch is then moved by couple commits ahead.\n\nNow I have nasty problems when I try to merge that separate branch\nback to master (see log below).\n\nIf I split the branch history in two, and first merge up to commit\nwith deletion, and then separately merge the rest of it with symlink\ncreation -- all goes well.\n\nBelow is the log on how to reproduce the problem:\n\nAlexander.\n\n$ mkdir test\n$ cd test\n$ git init\nInitialized empty Git repository in /users/agladysh/tmp/test/.git/\n$ mkdir alpha\n$ echo \"file1\" > alpha/file1\n$ git add .\n$ git commit -m \"first commit\"\n[master (root-commit) 1df90a8] first commit\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 100644 alpha/file1\n\n$ mkdir beta\n$ cp -R alpha beta/\n$ git add .\n$ git commit -m \"second commit\"\n[master 0eddb98] second commit\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 100644 beta/alpha/file1\n\n$ git checkout -b branch\nSwitched to a new branch 'branch'\n$ rm -rf beta/alpha\n$ git add -u\n$ git commit -m \"deleted\"\n[branch 34134ea] deleted\n 1 files changed, 0 insertions(+), 1 deletions(-)\n delete mode 100644 beta/alpha/file1\n\n$ cd beta/\n$ ln -s ../alpha\n$ cd ..\n$ git add .\n$ git commit -m \"symlink\"\n[branch b8dfba0] symlink\n 1 files changed, 1 insertions(+), 0 deletions(-)\n create mode 120000 beta/alpha\n\n$ git checkout master\nSwitched to branch 'master'\n\n### All works if we're just fast-forwarding ###\n\n$ git branch backup\n$ git merge branch\nUpdating 0eddb98..b8dfba0\nFast forward\n beta/alpha       |    1 +\n beta/alpha/file1 |    1 -\n 2 files changed, 1 insertions(+), 1 deletions(-)\n create mode 120000 beta/alpha\n delete mode 100644 beta/alpha/file1\n\n### Trying to restore to backup\n$ git reset --hard backup\nerror: Invalid path ''\nHEAD is now at 0eddb98 second commit\n$ git status\n# On branch master\n# Changed but not updated:\n#   (use \"git add/rm <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working directory)\n#\n#\tdeleted:    alpha/file1\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n### Needed second reset --hard.\n\n$ git reset --hard\nHEAD is now at 0eddb98 second commit\n\n$ git status\n# On branch master\nnothing to commit (working directory clean)\n\n### We're back to original master now\n\n$ echo \"change\" >> alpha/file1\n$ git commit -a -m \"third commit\"\n[master 0f64b88] third commit\n 1 files changed, 1 insertions(+), 0 deletions(-)\n\n### Here it goes\n\n$ git merge branch\nCONFLICT (directory/file): There is a directory with name beta/alpha\nin HEAD. Adding beta/alpha as beta/alpha~branch\nRemoving beta/alpha/file1\nAutomatic merge failed; fix conflicts and then commit the result.\n[4168][agladysh.agmac: test]$ git status\nbeta/alpha: needs merge\n# On branch master\n# Changes to be committed:\n#   (use \"git reset HEAD <file>...\" to unstage)\n#\n#\tdeleted:    beta/alpha/file1\n#\n# Changed but not updated:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working directory)\n#\n#\tunmerged:   beta/alpha\n#\n# Untracked files:\n#   (use \"git add <file>...\" to include in what will be committed)\n#\n#\tbeta/alpha~branch\n$ git mergetool\nMerging the files: beta/alpha\n\nmv: rename beta/alpha to ./beta/alpha.BACKUP.55777: No such file or directory\ncp: ./beta/alpha.BACKUP.55777: No such file or directory\nDeleted merge conflict for 'beta/alpha':\n  {local}: deleted\n  {remote}: a symbolic link -> '../alpha'\nUse (c)reated or (d)eleted file, or (a)bort? c\nfatal: beta/alpha: unable to stat (No such file or directory)\nmv: rename ./beta/alpha.BACKUP.55777 to beta/alpha.orig: No such file\nor directory\n"},{"id":"115884","messageId":"c6c947f60906090118n78d3c40fq11d1390f8776c2c0@mail.gmail.com","threadId":"19669","inReplyTo":"c6c947f60906042243v2e36251dn9a46343cf6b8a2f4@mail.gmail.com","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Alexander Gladysh","fromEmail":"agladysh@gmail.com","sentAt":"2009-06-09T08:18:16Z","receivedAt":"2009-06-09T08:18:16Z","isPatch":false,"sender":{"key":"agladysh@gmail.com","avatar":"https://avatars.githubusercontent.com/u/38239?v=4"},"body":"Any help here? This bug is pretty annoying (especially that it\nrequires double hard resets).\n\nShould I provide any extra information?\n\nAlexander.\n\nOn Fri, Jun 5, 2009 at 9:43 AM, Alexander Gladysh<agladysh@gmail.com> wrote:\n> Hi, list!\n>\n> OS X 10.5.7\n>\n> $ git --version\n> git version 1.6.3.2\n>\n> In my master branch I've had this structure:\n>\n> root /\n>    directory1 /\n>        some-files\n>    directory2 /\n>        copy-of-directory1 /\n>            some-files\n>\n> In a separate branch I replaced copy-of-directory1 with a symlink to\n> ../directory1. I did it in two commits: first remove\n> copy-of-directory1, in second commit -- create the symlink.\n>\n> My master branch is then moved by couple commits ahead.\n>\n> Now I have nasty problems when I try to merge that separate branch\n> back to master (see log below).\n>\n> If I split the branch history in two, and first merge up to commit\n> with deletion, and then separately merge the rest of it with symlink\n> creation -- all goes well.\n>\n> Below is the log on how to reproduce the problem:\n>\n> Alexander.\n>\n> $ mkdir test\n> $ cd test\n> $ git init\n> Initialized empty Git repository in /users/agladysh/tmp/test/.git/\n> $ mkdir alpha\n> $ echo \"file1\" > alpha/file1\n> $ git add .\n> $ git commit -m \"first commit\"\n> [master (root-commit) 1df90a8] first commit\n>  1 files changed, 1 insertions(+), 0 deletions(-)\n>  create mode 100644 alpha/file1\n>\n> $ mkdir beta\n> $ cp -R alpha beta/\n> $ git add .\n> $ git commit -m \"second commit\"\n> [master 0eddb98] second commit\n>  1 files changed, 1 insertions(+), 0 deletions(-)\n>  create mode 100644 beta/alpha/file1\n>\n> $ git checkout -b branch\n> Switched to a new branch 'branch'\n> $ rm -rf beta/alpha\n> $ git add -u\n> $ git commit -m \"deleted\"\n> [branch 34134ea] deleted\n>  1 files changed, 0 insertions(+), 1 deletions(-)\n>  delete mode 100644 beta/alpha/file1\n>\n> $ cd beta/\n> $ ln -s ../alpha\n> $ cd ..\n> $ git add .\n> $ git commit -m \"symlink\"\n> [branch b8dfba0] symlink\n>  1 files changed, 1 insertions(+), 0 deletions(-)\n>  create mode 120000 beta/alpha\n>\n> $ git checkout master\n> Switched to branch 'master'\n>\n> ### All works if we're just fast-forwarding ###\n>\n> $ git branch backup\n> $ git merge branch\n> Updating 0eddb98..b8dfba0\n> Fast forward\n>  beta/alpha       |    1 +\n>  beta/alpha/file1 |    1 -\n>  2 files changed, 1 insertions(+), 1 deletions(-)\n>  create mode 120000 beta/alpha\n>  delete mode 100644 beta/alpha/file1\n>\n> ### Trying to restore to backup\n> $ git reset --hard backup\n> error: Invalid path ''\n> HEAD is now at 0eddb98 second commit\n> $ git status\n> # On branch master\n> # Changed but not updated:\n> #   (use \"git add/rm <file>...\" to update what will be committed)\n> #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n> #\n> #       deleted:    alpha/file1\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n> ### Needed second reset --hard.\n>\n> $ git reset --hard\n> HEAD is now at 0eddb98 second commit\n>\n> $ git status\n> # On branch master\n> nothing to commit (working directory clean)\n>\n> ### We're back to original master now\n>\n> $ echo \"change\" >> alpha/file1\n> $ git commit -a -m \"third commit\"\n> [master 0f64b88] third commit\n>  1 files changed, 1 insertions(+), 0 deletions(-)\n>\n> ### Here it goes\n>\n> $ git merge branch\n> CONFLICT (directory/file): There is a directory with name beta/alpha\n> in HEAD. Adding beta/alpha as beta/alpha~branch\n> Removing beta/alpha/file1\n> Automatic merge failed; fix conflicts and then commit the result.\n> [4168][agladysh.agmac: test]$ git status\n> beta/alpha: needs merge\n> # On branch master\n> # Changes to be committed:\n> #   (use \"git reset HEAD <file>...\" to unstage)\n> #\n> #       deleted:    beta/alpha/file1\n> #\n> # Changed but not updated:\n> #   (use \"git add <file>...\" to update what will be committed)\n> #   (use \"git checkout -- <file>...\" to discard changes in working directory)\n> #\n> #       unmerged:   beta/alpha\n> #\n> # Untracked files:\n> #   (use \"git add <file>...\" to include in what will be committed)\n> #\n> #       beta/alpha~branch\n> $ git mergetool\n> Merging the files: beta/alpha\n>\n> mv: rename beta/alpha to ./beta/alpha.BACKUP.55777: No such file or directory\n> cp: ./beta/alpha.BACKUP.55777: No such file or directory\n> Deleted merge conflict for 'beta/alpha':\n>  {local}: deleted\n>  {remote}: a symbolic link -> '../alpha'\n> Use (c)reated or (d)eleted file, or (a)bort? c\n> fatal: beta/alpha: unable to stat (No such file or directory)\n> mv: rename ./beta/alpha.BACKUP.55777 to beta/alpha.orig: No such file\n> or directory\n>\n"},{"id":"116069","messageId":"20090611114846.GC4409@coredump.intra.peff.net","threadId":"19669","inReplyTo":"c6c947f60906090118n78d3c40fq11d1390f8776c2c0@mail.gmail.com","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-06-11T11:48:46Z","receivedAt":"2009-06-11T11:48:46Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"[Kjetil: I bisected this bug to your 92604b4. Details below.]\n\nOn Tue, Jun 09, 2009 at 12:18:16PM +0400, Alexander Gladysh wrote:\n\n> Any help here? This bug is pretty annoying (especially that it\n> requires double hard resets).\n> \n> Should I provide any extra information?\n\nActually, I think the problem happens earlier than you realize; I see\nproblems when switching back to master:\n\n-- >8 --\n# make a repo\nmkdir repo && cd repo && git init\n\n# content in alpha\nmkdir alpha && echo content >alpha/file && git add . && git commit -m one\n# and duplicate content inside beta\nmkdir beta && cp -R alpha beta && git add . && git commit -m two\n\n# now replace the duplicate with a symlink\ngit checkout -b branch\nrm -rf beta/alpha && git add -u && git commit -m deleted\nln -s ../alpha beta/alpha && git add . && git commit -m symlink\n\n# now checkout master again; alpha/file will be missing, even\n# though it wasn't touched at all\ngit checkout master\ngit status\n-- 8< --\n\nWe handled this correctly in v1.6.1, so I was able to bisect it down to:\n\n    commit 92604b466344b2157efc42ef3521dac22d7906a2\n    Author: Kjetil Barvik <barvik@broadpark.no>\n    Date:   Sun Jan 18 16:14:50 2009 +0100\n\n        lstat_cache(): more cache effective symlink/directory detection\n\n        Make the cache functionality more effective.  Previously when\n        A/B/C/D was in the cache and A/B/C/E/file.c was called for,\n        there was no match at all from the cache.  Now we use the fact\n        that the paths \"A\", \"A/B\" and \"A/B/C\" are already tested, and we\n        only need to do an lstat() call on \"A/B/C/E\".\n\nI don't have time to look more closely now, but I'm guessing we are\ntreating the symlink to the directory like the directory itself in a\nplace that we shouldn't.\n\n-Peff\n"},{"id":"116073","messageId":"86ab4erg3m.fsf@broadpark.no","threadId":"19669","inReplyTo":"20090611114846.GC4409@coredump.intra.peff.net","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-06-11T14:37:49Z","receivedAt":"2009-06-11T14:37:49Z","isPatch":false,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"Jeff King <peff@peff.net> writes:\n\n> [Kjetil: I bisected this bug to your 92604b4. Details below.]\n>\n> On Tue, Jun 09, 2009 at 12:18:16PM +0400, Alexander Gladysh wrote:\n>\n>> Any help here? This bug is pretty annoying (especially that it\n>> requires double hard resets).\n>> \n>> Should I provide any extra information?\n>\n> Actually, I think the problem happens earlier than you realize; I see\n> problems when switching back to master:\n>\n> -- >8 --\n> # make a repo\n> mkdir repo && cd repo && git init\n>\n> # content in alpha\n> mkdir alpha && echo content >alpha/file && git add . && git commit -m one\n> # and duplicate content inside beta\n> mkdir beta && cp -R alpha beta && git add . && git commit -m two\n>\n> # now replace the duplicate with a symlink\n> git checkout -b branch\n> rm -rf beta/alpha && git add -u && git commit -m deleted\n> ln -s ../alpha beta/alpha && git add . && git commit -m symlink\n>\n> # now checkout master again; alpha/file will be missing, even\n> # though it wasn't touched at all\n> git checkout master\n> git status\n> -- 8< --\n>\n> We handled this correctly in v1.6.1, so I was able to bisect it down to:\n>\n>     commit 92604b466344b2157efc42ef3521dac22d7906a2\n>     Author: Kjetil Barvik <barvik@broadpark.no>\n>     Date:   Sun Jan 18 16:14:50 2009 +0100\n>\n>         lstat_cache(): more cache effective symlink/directory detection\n>\n>         Make the cache functionality more effective.  Previously when\n>         A/B/C/D was in the cache and A/B/C/E/file.c was called for,\n>         there was no match at all from the cache.  Now we use the fact\n>         that the paths \"A\", \"A/B\" and \"A/B/C\" are already tested, and we\n>         only need to do an lstat() call on \"A/B/C/E\".\n>\n> I don't have time to look more closely now, but I'm guessing we are\n> treating the symlink to the directory like the directory itself in a\n> place that we shouldn't.\n>\n> -Peff\n\n  OK, I start debuging in a few minutes.  Thanks for mail!\n\n  -- kjetil\n"},{"id":"116281","messageId":"861vpmkhob.fsf@broadpark.no","threadId":"19669","inReplyTo":"20090611114846.GC4409@coredump.intra.peff.net","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-06-14T14:34:44Z","receivedAt":"2009-06-14T14:34:44Z","isPatch":false,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"\nFrom: Kjetil Barvik <barvik@broadpark.no>\nDate: Sun, 14 Jun 2009 15:08:28 +0200\nSubject: [PATCH] lstat_cache: guard against full match of length of 'name' parameter\n\nlongest_path_match() in symlinks.c does exactly what it's name says,\nbut in some cases that match can be too long, since the\nhas_*_leading_path() functions assumes that the match will newer be as\nlong as the name string given to the function.\n\nfix this by adding an extra if test which checks if the match length\nis equal to the 'len' parameter.\n---\n\n  OK, this is a first version of a patch for this bug.  I have not added\n  a \"Signed-off-by:\"-tag yet, but I intend to do that when I am more\n  shure that this is the real fix for the bug.  Will also add a test\n  case in a later version.\n\n  The given instructions(1) to repeat the failure, gave me the following\n  4 calls to has_symlink_leading_path() for the failed 'git checkout\n  master' command, and I made the following the table:\n\n   'name' parameter       Kjetil      Linus      tested\n  -------------------------------------------------------\n   \"beta/alpha/file\"        2           1           2\n   \"beta/alpha\"             2C          0           0\n   \"alpha/file\"             0           0           0\n   \"beta/alpha/file\"        0           1C          0\n\n  The \"Kjetil\" column is what the h_s_l_p() function returns as of\n  commit 92604b46 by me.  The \"Linus\" column is what the h_s_l_p()\n  function returns as of commit c40641b7 by Linus.  The \"tested\" column\n  is what will be returned when the cache is clear'ed each time.  An\n  added \"C\" indicate that the result was cached/taken from the cache.\n\n  My bug is from the incorrect cached value from line 2, and since I\n  noticed that it take the symbolic link result, \"beta/alpha\", which was\n  the full length of the 'name' parameter and not the leading part, I\n  have based the included patch on this fact.\n\n  The function is named has_symlink_leading_path(), so I guess it is a\n  reason for that \"leading\" part of the name.  So, is this a reasonable\n  fix?  Other comments?\n\n  -- kjetil\n\n  1) the following commands:\n\n# make a repo\nmkdir repo && cd repo && git init\n\n# content in alpha\nmkdir alpha && echo content >alpha/file && git add . && git commit -m one\n# and duplicate content inside beta\nmkdir beta && cp -R alpha beta && git add . && git commit -m two\n\n# now replace the duplicate with a symlink\ngit checkout -b branch\nrm -rf beta/alpha && git add -u && git commit -m deleted\nln -s ../alpha beta/alpha && git add . && git commit -m symlink\n\n# now checkout master again; alpha/file will be missing, even\n# though it wasn't touched at all\ngit checkout master\n\n\n\n symlinks.c |    4 ++++\n 1 files changed, 4 insertions(+), 0 deletions(-)\n\ndiff --git a/symlinks.c b/symlinks.c\nindex 8dcd632..934abc6 100644\n--- a/symlinks.c\n+++ b/symlinks.c\n@@ -97,6 +97,10 @@ static int lstat_cache(const char *name, int len,\n \t\t\tlongest_path_match(name, len, cache.path, cache.len,\n \t\t\t\t\t   &previous_slash);\n \t\tmatch_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);\n+\n+\t\tif (!(track_flags & FL_FULLPATH) && match_len == len)\n+\t\t\tmatch_len = last_slash = previous_slash;\n+\n \t\tif (match_flags && match_len == cache.len)\n \t\t\treturn match_flags;\n \t\t/*\n-- \n1.6.3.2.277.gd10543\n"},{"id":"116888","messageId":"885649360906241507r6ac78495s802f8b7758bcabf9@mail.gmail.com","threadId":"19669","inReplyTo":"861vpmkhob.fsf@broadpark.no","subject":"Re: Troubles when directory is replaced by symlink","fromName":"James Pickens","fromEmail":"jepicken@gmail.com","sentAt":"2009-06-24T22:07:47Z","receivedAt":"2009-06-24T22:07:47Z","isPatch":false,"sender":{"key":"jepicken@gmail.com","avatar":null},"body":"On Sun, Jun 14, 2009, Kjetil Barvik<barvik@broadpark.no> wrote:\n> From: Kjetil Barvik <barvik@broadpark.no>\n> Date: Sun, 14 Jun 2009 15:08:28 +0200\n> Subject: [PATCH] lstat_cache: guard against full match of length of 'name' parameter\n\nMy project ran into this bug today, and I can confirm that this patch\nfixes it.  I think it's an important bug; it hasn't been mentioned yet,\nbut this can result in lost work if the user had modified, but not added,\none of the files that Git wrongly deleted.\n\nSo, what's the status of this patch?\n\nJames\n"},{"id":"116976","messageId":"86bpocsz9k.fsf@broadpark.no","threadId":"19669","inReplyTo":"885649360906241507r6ac78495s802f8b7758bcabf9@mail.gmail.com","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-06-25T22:51:35Z","receivedAt":"2009-06-25T22:51:35Z","isPatch":false,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"James Pickens <jepicken@gmail.com> writes:\n\n> On Sun, Jun 14, 2009, Kjetil Barvik<barvik@broadpark.no> wrote:\n>> From: Kjetil Barvik <barvik@broadpark.no>\n>> Date: Sun, 14 Jun 2009 15:08:28 +0200\n>> Subject: [PATCH] lstat_cache: guard against full match of length of 'name' parameter\n>\n> My project ran into this bug today, and I can confirm that this patch\n> fixes it.  I think it's an important bug; it hasn't been mentioned yet,\n> but this can result in lost work if the user had modified, but not added,\n> one of the files that Git wrongly deleted.\n>\n> So, what's the status of this patch?\n\n  Sorry, have not have much time, and did not get any response on the\n  patch, and I almost forgot about it for a while.\n\n  But, since you say that the patch is ok, I shall try make a more\n  \"final\" patch by 14:00 UTC Friday 26.\n\n  Thanks for reminding me!\n\n  -- kjetil\n"},{"id":"117019","messageId":"868wjf9lxq.fsf@broadpark.no","threadId":"19669","inReplyTo":"885649360906241507r6ac78495s802f8b7758bcabf9@mail.gmail.com","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Kjetil Barvik","fromEmail":"barvik@broadpark.no","sentAt":"2009-06-26T13:14:25Z","receivedAt":"2009-06-26T13:14:25Z","isPatch":false,"sender":{"key":"barvik@broadpark.no","avatar":null},"body":"\nFrom: Kjetil Barvik <barvik@broadpark.no>\nDate: Fri, 26 Jun 2009 14:51:02 +0200\nSubject: [PATCH] lstat_cache: guard against full match of length of 'name' parameter\n\nlongest_path_match() in symlinks.c does exactly what it's name says,\nbut in some cases that match can be too long, since the\nhas_*_leading_path() functions assumes that the match will newer be as\nlong as the name string given to the function.\n\nFix this by adding an extra if test which checks if the match length\nis equal to the 'len' parameter.  Also, add a test-case to catch this\n\nSigned-off-by: Kjetil Barvik <barvik@broadpark.no>\n---\n\n* James Pickens <jepicken@gmail.com> writes:\n> On Sun, Jun 14, 2009, Kjetil Barvik<barvik@broadpark.no> wrote:\n>> From: Kjetil Barvik <barvik@broadpark.no>\n>> Date: Sun, 14 Jun 2009 15:08:28 +0200\n>> Subject: [PATCH] lstat_cache: guard against full match of length of 'name' parameter\n>\n> My project ran into this bug today, and I can confirm that this patch\n> fixes it.  I think it's an important bug; it hasn't been mentioned yet,\n> but this can result in lost work if the user had modified, but not added,\n> one of the files that Git wrongly deleted.\n>\n> So, what's the status of this patch?\n\n  OK, here is a more final patch with a test case.  \n\n  -- kjetil\n\n\n symlinks.c                  |    2 ++\n t/t2007-checkout-symlink.sh |   31 +++++++++++++++++++++++++++++++\n 2 files changed, 33 insertions(+), 0 deletions(-)\n\ndiff --git a/symlinks.c b/symlinks.c\nindex 8dcd632..66a0e16 100644\n--- a/symlinks.c\n+++ b/symlinks.c\n@@ -96,6 +96,8 @@ static int lstat_cache(const char *name, int len,\n \t\tmatch_len = last_slash =\n \t\t\tlongest_path_match(name, len, cache.path, cache.len,\n \t\t\t\t\t   &previous_slash);\n+\t\tif (!(track_flags & FL_FULLPATH) && match_len == len)\n+\t\t\tmatch_len = last_slash = previous_slash;\n \t\tmatch_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);\n \t\tif (match_flags && match_len == cache.len)\n \t\t\treturn match_flags;\ndiff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh\nindex 20f3343..08e3c32 100755\n--- a/t/t2007-checkout-symlink.sh\n+++ b/t/t2007-checkout-symlink.sh\n@@ -53,4 +53,35 @@ test_expect_success 'switch from dir to symlink' '\n \n '\n \n+test_expect_success 'setup of new directories and a branch' '\n+\n+\tgit checkout master &&\n+\n+\tmkdir alpha &&\n+\techo content >alpha/file &&\n+\tgit add . &&\n+\tgit commit -m one &&\n+\n+\tmkdir beta &&\n+\tcp -R alpha beta &&\n+\tgit add . &&\n+\tgit commit -m two &&\n+\n+\tgit checkout -b branch &&\n+\trm -rf beta/alpha &&\n+\tgit add -u &&\n+\tgit commit -m deleted &&\n+\tln -s ../alpha beta/alpha &&\n+\tgit add . &&\n+\tgit commit -m symlink\n+\n+'\n+\n+test_expect_success 'checkout of master - alpha/file and beta/alpha/file should exist' '\n+\n+\tgit checkout master &&\n+\tls alpha/file beta/alpha/file\n+\n+'\n+\n test_done\n-- \n1.6.3.2.277.gd10543\n"},{"id":"117023","messageId":"4A44D7C2.1060706@viscovery.net","threadId":"19669","inReplyTo":"868wjf9lxq.fsf@broadpark.no","subject":"Re: Troubles when directory is replaced by symlink","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-06-26T14:14:26Z","receivedAt":"2009-06-26T14:14:26Z","isPatch":false,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Kjetil Barvik schrieb:\n> Subject: [PATCH] lstat_cache: guard against full match of length of 'name' parameter\n> \n> longest_path_match() in symlinks.c does exactly what it's name says,\n> but in some cases that match can be too long, since the\n> has_*_leading_path() functions assumes that the match will newer be as\n> long as the name string given to the function.\n\nAnd these \"some cases\" are? When \"a directory was replaced by a symlink\"\n(\"or what??\" I am inclined to add). Would you please be very specific\nhere, perhaps with an example, so that we still know the details in 6 months.\n\n> +test_expect_success 'checkout of master - alpha/file and beta/alpha/file should exist' '\n\ntest_expect_success 'checkout replaces symlink by directory' '\n\nBTW, this is what the test seems to check, and it is the opposite of what\nthe mail's Subject says. So, which one is it?\n\n> +\n> +\tgit checkout master &&\n> +\tls alpha/file beta/alpha/file\n\n\tgit checkout master &&\n\t! test -h alpha &&\n\ttest -f alpha/file &&\n\ttest -f beta/alpha/file\n\n-- Hannes\n"}]}