{"thread":{"id":"42105","subject":"possible bug of git stash deleting uncommitted files in corner case","startedAt":"2016-04-22T11:46:50Z","lastAt":"2016-04-23T03:53:12Z","messageCount":6,"participants":["Daniele Segato","Remi Galan Alfonso","Junio C Hamano","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"284107","messageId":"CAND5yRvCK9YuVOJ91CHbnbWAVYcPrpihGkoKs28f7PJgzRwW6Q@mail.gmail.com","threadId":"42105","inReplyTo":null,"subject":"possible bug of git stash deleting uncommitted files in corner case","fromName":"Daniele Segato","fromEmail":"daniele.segato@gmail.com","sentAt":"2016-04-22T11:46:50Z","receivedAt":"2016-04-22T11:46:50Z","isPatch":false,"sender":{"key":"daniele.segato@gmail.com","avatar":"https://avatars.githubusercontent.com/u/469948?v=4"},"body":"Hi,\n\nmy coworker today claimed git stash deleted his files, I made him\nexplain me what he did and I think it could actually be a bug even if\nhappening only in a corner case better explained with code to\nreproduce:\n\ngit init\necho 'X' > foo\ngit add foo\ngit commit -m 'foo file committed'\n\n\nwhat follow is the corner case I'm talking about: he deleted the file,\ncreated a directory with THE SAME name and added lot of files in it,\nin this example I'll only add one\n\n\nrm foo\nmkdir foo\necho 'B' > foo/bar\n\n\nat this point the working directory looks like this:\n\n $ tree\n.\n└── foo\n    └── bar\n\n1 directory, 1 file\n\n\nbut apparently git status does not seem to see foo directory at all:\n\n\n$ git status\nOn branch master\nChanges not staged for commit:\n\n          deleted:    foo\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n\nI expected something more like:\n\n\n$ git status\nOn branch master\nChanges not staged for commit:\n\n          deleted: foo\n\nUntracked files:\n\n          foo/\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n\nAnyway he went on and decided to stash his work:\n\n\ngit stash\n\n\nat this point stash deleted the \"bar\" file, in his case all the work\non the previous couple of hours, but he didn't know yet\n\n\n$ git stash show stash@{0}\nfoo | 1 -\n1 file changed, 1 deletion(-)\n\n\nthe foo directory was gone, replaced by the foo file\n\n\ngit stash pop\n\n\ndid not complained and deleted foo file again\n\n\nI know my co-worker shouldn't had created a directory with the same\nfile he was deleting but I also think git shouldn't have allowed him\nto stash at all, or should have been cleaver enough to actually stash\nthe directory with its files.\n\n\nRegards,\nDaniele Segato\n"},{"id":"284108","messageId":"CAND5yRvU1-AgvQW106fHbNN-GRQ615HjTDjR6AY9gkpoquBgDw@mail.gmail.com","threadId":"42105","inReplyTo":"CAND5yRvCK9YuVOJ91CHbnbWAVYcPrpihGkoKs28f7PJgzRwW6Q@mail.gmail.com","subject":"Re: possible bug of git stash deleting uncommitted files in corner case","fromName":"Daniele Segato","fromEmail":"daniele.segato@gmail.com","sentAt":"2016-04-22T11:48:55Z","receivedAt":"2016-04-22T11:48:55Z","isPatch":false,"sender":{"key":"daniele.segato@gmail.com","avatar":"https://avatars.githubusercontent.com/u/469948?v=4"},"body":"sorry I forgot:\n\n $ git --version\ngit version 1.9.1\n\n\nOn Fri, Apr 22, 2016 at 1:46 PM, Daniele Segato\n<daniele.segato@gmail.com> wrote:\n> Hi,\n>\n> my coworker today claimed git stash deleted his files, I made him\n> explain me what he did and I think it could actually be a bug even if\n> happening only in a corner case better explained with code to\n> reproduce:\n>\n> git init\n> echo 'X' > foo\n> git add foo\n> git commit -m 'foo file committed'\n>\n>\n> what follow is the corner case I'm talking about: he deleted the file,\n> created a directory with THE SAME name and added lot of files in it,\n> in this example I'll only add one\n>\n>\n> rm foo\n> mkdir foo\n> echo 'B' > foo/bar\n>\n>\n> at this point the working directory looks like this:\n>\n>  $ tree\n> .\n> └── foo\n>     └── bar\n>\n> 1 directory, 1 file\n>\n>\n> but apparently git status does not seem to see foo directory at all:\n>\n>\n> $ git status\n> On branch master\n> Changes not staged for commit:\n>\n>           deleted:    foo\n>\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n>\n> I expected something more like:\n>\n>\n> $ git status\n> On branch master\n> Changes not staged for commit:\n>\n>           deleted: foo\n>\n> Untracked files:\n>\n>           foo/\n>\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n>\n> Anyway he went on and decided to stash his work:\n>\n>\n> git stash\n>\n>\n> at this point stash deleted the \"bar\" file, in his case all the work\n> on the previous couple of hours, but he didn't know yet\n>\n>\n> $ git stash show stash@{0}\n> foo | 1 -\n> 1 file changed, 1 deletion(-)\n>\n>\n> the foo directory was gone, replaced by the foo file\n>\n>\n> git stash pop\n>\n>\n> did not complained and deleted foo file again\n>\n>\n> I know my co-worker shouldn't had created a directory with the same\n> file he was deleting but I also think git shouldn't have allowed him\n> to stash at all, or should have been cleaver enough to actually stash\n> the directory with its files.\n>\n>\n> Regards,\n> Daniele Segato\n"},{"id":"284109","messageId":"1304154573.4013923.1461328186541.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"42105","inReplyTo":"CAND5yRvU1-AgvQW106fHbNN-GRQ615HjTDjR6AY9gkpoquBgDw@mail.gmail.com","subject":"Re: possible bug of git stash deleting uncommitted files in corner case","fromName":"Remi Galan Alfonso","fromEmail":"remi.galan-alfonso@ensimag.grenoble-inp.fr","sentAt":"2016-04-22T12:29:46Z","receivedAt":"2016-04-22T12:29:46Z","isPatch":false,"sender":{"key":"remi.galan-alfonso@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/12509162?v=4"},"body":"Daniele Segato <daniele.segato@gmail.com> wrote:\n> git init\n> echo 'X' > foo\n> git add foo\n> git commit -m 'foo file committed'\n> \n> rm foo\n> mkdir foo\n> echo 'B' > foo/bar\n> \n> # git status\n> \n> git stash\n> \n> at this point stash deleted the \"bar\" file, in his case all the work\n> on the previous couple of hours, but he didn't know yet\n> \n> the foo directory was gone, replaced by the foo file\n> \n> git stash pop\n> \n> did not complained and deleted foo file again\n> \n> I know my co-worker shouldn't had created a directory with the same\n> file he was deleting but I also think git shouldn't have allowed him\n> to stash at all, or should have been clever enough to actually stash\n> the directory with its files.\n\nAFAIK it is a bug.\nWithout even going to the stash command,\n    git init\n    echo 'X' >foo\n    git add foo\n    git commit -m \"Adding foo\"\n    rm foo\n    mkdir foo\n    echo 'B' >foo/bar\n    git status\nAt this point the state is incorrect, the file foo/bar isn't there, as\nyou mentionned.\n\n>  $ git --version\n> git version 1.9.1\n\nContrary to what I expected, this seems to still be the case with:\n  $ git --version\n  git version 2.8.0.rc2\n\nBeing at $daywork right now, I am unable to test this any further.\n\nThanks,\nRémi\n"},{"id":"284159","messageId":"xmqqmvolpmsw.fsf@gitster.mtv.corp.google.com","threadId":"42105","inReplyTo":"1304154573.4013923.1461328186541.JavaMail.zimbra@ensimag.grenoble-inp.fr","subject":"Re: possible bug of git stash deleting uncommitted files in corner case","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-04-22T17:37:19Z","receivedAt":"2016-04-22T17:37:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Remi Galan Alfonso <remi.galan-alfonso@ensimag.grenoble-inp.fr>\nwrites:\n\n> Daniele Segato <daniele.segato@gmail.com> wrote:\n> ...\n>> git version 1.9.1\n>\n> Contrary to what I expected, this seems to still be the case with:\n>   $ git --version\n>   git version 2.8.0.rc2\n\nI do not think \"git stash\" has been updated in any major way to\naddress correctness (including its corner case behaviour) ever since\nit was originally written, so it is very likely that any bug you see\nwould be with it since the very old days.\n"},{"id":"284168","messageId":"754076461.4029096.1461351865455.JavaMail.zimbra@ensimag.grenoble-inp.fr","threadId":"42105","inReplyTo":"xmqqmvolpmsw.fsf@gitster.mtv.corp.google.com","subject":"Re: possible bug of git stash deleting uncommitted files in corner case","fromName":"Remi Galan Alfonso","fromEmail":"remi.galan-alfonso@ensimag.grenoble-inp.fr","sentAt":"2016-04-22T19:04:25Z","receivedAt":"2016-04-22T19:04:25Z","isPatch":false,"sender":{"key":"remi.galan-alfonso@ensimag.grenoble-inp.fr","avatar":"https://avatars.githubusercontent.com/u/12509162?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n> Remi Galan Alfonso <remi.galan-alfonso@ensimag.grenoble-inp.fr>\n> writes:\n> \n> > Daniele Segato <daniele.segato@gmail.com> wrote:\n> > ...\n> >> git version 1.9.1\n> >\n> > Contrary to what I expected, this seems to still be the case with:\n> >   $ git --version\n> >   git version 2.8.0.rc2\n> \n> I do not think \"git stash\" has been updated in any major way to\n> address correctness (including its corner case behaviour) ever since\n> it was originally written, so it is very likely that any bug you see\n> would be with it since the very old days.\n\nFor this bug it doesn't seem to be specifically linked to git stash,\nsince 'git status' doesn't display correct informations in the first\nplace (it doesn't show foo/bar as an untracked file).\n\nI tried something quickly, based on Daniele's case:\n    git init\n    echo 'X' >foo\n    git add foo\n    git commit -m \"Added foo\"\n    rm foo\n    mkdir foo\n    echo 'B' >foo/bar\n\n    git status # foo/bar not shown in Untracked files\n\n    git add foo/bar\n\ngit status then shows as expected:\n# On branch master\n# Changes to be committed:\n#   (use \"git reset HEAD <file>...\" to unstage)\n# \n# \tdeleted:    foo\n# \tnew file:   foo/bar\n\nHowever git stash fails this time:\n# error: foo: is a directory - add individual files instead\n# fatal: Unable to process path foo\n# Cannot save the current worktree state\n\nI am not sure what should be the correct behaviour here.\nThis however might be one of the corner cases you mentionned.\n\nThanks,\nRémi\n"},{"id":"284221","messageId":"20160423035312.GB15994@sigill.intra.peff.net","threadId":"42105","inReplyTo":"754076461.4029096.1461351865455.JavaMail.zimbra@ensimag.grenoble-inp.fr","subject":"Re: possible bug of git stash deleting uncommitted files in corner case","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-04-23T03:53:12Z","receivedAt":"2016-04-23T03:53:12Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 22, 2016 at 09:04:25PM +0200, Remi Galan Alfonso wrote:\n\n> For this bug it doesn't seem to be specifically linked to git stash,\n> since 'git status' doesn't display correct informations in the first\n> place (it doesn't show foo/bar as an untracked file).\n> \n> I tried something quickly, based on Daniele's case:\n>     git init\n>     echo 'X' >foo\n>     git add foo\n>     git commit -m \"Added foo\"\n>     rm foo\n>     mkdir foo\n>     echo 'B' >foo/bar\n> \n>     git status # foo/bar not shown in Untracked files\n> \n>     git add foo/bar\n> \n> git status then shows as expected:\n> # On branch master\n> # Changes to be committed:\n> #   (use \"git reset HEAD <file>...\" to unstage)\n> # \n> # \tdeleted:    foo\n> # \tnew file:   foo/bar\n\nBefore you \"git add foo/bar\", try \"git status -uall\", which asks git to\ndescend into directories when looking for untracked files. It _does_\nshow foo/bar as untracked.\n\nSo I think what is happening is that in the case without \"-uall\", we see\n\"foo\" as an untracked file, but then check that with the index to say\n\"ah, it is not untracked, there is an entry in the index\".  But of\ncourse the earlier mention in \"not staged for commit\" will not say\nanything about the new directory \"foo\", because we only diff actual\nfiles there.\n\nLikewise, if you ask \"ls-files -o\", it mentions \"foo/bar\".\n\nSo I think the bug is in the way dir.c handles\nDIR_SHOW_OTHER_DIRECTORIES, or possibly in the way that\nwt_status_collect_untracked handles its results.\n\nIt may be that the latter needs to special-case its\ncache_name_is_other() check, and make sure we mention an \"other\" file we\nfound that is a directory, even if it has an index entry.\n\n> However git stash fails this time:\n> # error: foo: is a directory - add individual files instead\n> # fatal: Unable to process path foo\n> # Cannot save the current worktree state\n\nI suspect the actual stash bug is separate from the bug above. It just\nlooks like update-index is not smart enough to realize that a file being\nreplaced with a directory is effectively an index deletion of that\nentry. That's just a guess, though.\n\n-Peff\n"}]}