{"thread":{"id":"31112","subject":"git stash data loss","startedAt":"2012-07-27T03:06:08Z","lastAt":"2012-09-14T23:04:03Z","messageCount":7,"participants":["Aleksandr Pryimak","Jeff King","Aleksandr Priymak","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"195921","messageId":"55831343358368@web1e.yandex.ru","threadId":"31112","inReplyTo":null,"subject":"git stash data loss","fromName":"Aleksandr Pryimak","fromEmail":"tramsmm-mirror@yandex.ru","sentAt":"2012-07-27T03:06:08Z","receivedAt":"2012-07-27T03:06:08Z","isPatch":false,"sender":{"key":"tramsmm-mirror@yandex.ru","avatar":null},"body":"Hello.\n\nIt is believed that\ngit stash\ngit stash pop\nis safe to-do operation. But sometimes it is not. For example here is an example http://stackoverflow.com/questions/11680453/git-stash-where-did-the-files-in-my-directory-go/11680645\n\nI also recreated it\n\naleksandr@beast:/tmp/test$ git init\nInitialized empty Git repository in /tmp/test/.git/\naleksandr@beast:/tmp/test$ touch x\naleksandr@beast:/tmp/test$ git add x\naleksandr@beast:/tmp/test$ git commit -m \"Initial\"\n[master (root-commit) d3569a0] Initial\n 0 files changed, 0 insertions(+), 0 deletions(-)\n create mode 100644 x\naleksandr@beast:/tmp/test$ rm x\naleksandr@beast:/tmp/test$ mkdir x/\naleksandr@beast:/tmp/test$ ls\nx\naleksandr@beast:/tmp/test$ git stash\nSaved working directory and index state WIP on master: d3569a0 Initial\nHEAD is now at d3569a0 Initial\naleksandr@beast:/tmp/test$ ls\nx\naleksandr@beast:/tmp/test$ git stash pop\nRemoving x\n# On branch master\n# Changes not staged for commit:\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:    x\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nDropped refs/stash@{0} (c500443ae16cf0d846b195cb97eb388dec5f440e)\naleksandr@beast:/tmp/test$ ls\naleksandr@beast:/tmp/test$ git --version\ngit version 1.7.5.4\n\n--\nAleksandr Pryimak\n"},{"id":"195942","messageId":"20120727132953.GA8263@sigill.intra.peff.net","threadId":"31112","inReplyTo":"55831343358368@web1e.yandex.ru","subject":"Re: git stash data loss","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-07-27T13:29:53Z","receivedAt":"2012-07-27T13:29:53Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jul 27, 2012 at 07:06:08AM +0400, Aleksandr Pryimak wrote:\n\n> I also recreated it\n> \n> aleksandr@beast:/tmp/test$ git init\n> Initialized empty Git repository in /tmp/test/.git/\n> aleksandr@beast:/tmp/test$ touch x\n> aleksandr@beast:/tmp/test$ git add x\n> aleksandr@beast:/tmp/test$ git commit -m \"Initial\"\n> [master (root-commit) d3569a0] Initial\n>  0 files changed, 0 insertions(+), 0 deletions(-)\n>  create mode 100644 x\n\nOK, so we have \"x\" as a tracked file.\n\n> aleksandr@beast:/tmp/test$ rm x\n> aleksandr@beast:/tmp/test$ mkdir x/\n> aleksandr@beast:/tmp/test$ ls\n> x\n\nAnd then we remove it in favor of a directory. Note that git does not\ntrack directories directly, only files inside them. So from git's\nperspective, the working tree has no content in it at all.\n\n> aleksandr@beast:/tmp/test$ git stash\n> Saved working directory and index state WIP on master: d3569a0 Initial\n> HEAD is now at d3569a0 Initial\n\nAnd now we stash it. That will stash the working tree removal of x. It\nwill not stash anything about the new directory x, because it has no\ncontent inside it.\n\n> aleksandr@beast:/tmp/test$ ls\n> x\n> aleksandr@beast:/tmp/test$ git stash pop\n> Removing x\n> # On branch master\n> # Changes not staged for commit:\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:    x\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n> Dropped refs/stash@{0} (c500443ae16cf0d846b195cb97eb388dec5f440e)\n> aleksandr@beast:/tmp/test$ ls\n\nAnd your stash pop restores the deletion of \"x\". It does _not_ reinstate\nthe directory \"x\", because as I stated above, that is not part of the\nstash.\n\nSo what is the data loss? That the \"mkdir x\" was lost? That has nothing\nto do with stash, but rather the fact that git does not track empty\ndirectories. You could see the same thing with:\n \n  mkdir x && git commit -a\n\nwhich will not record your mkdir at all. In other words, this is by\ndesign.\n\nIf we put actual files inside \"x\", which git does track, then they would\nbe part of the stash, and should be properly retained. But they're not:\n\n  $ rm x && mkdir x && echo foo >x/file\n\nNow we have some precious contents in the form of \"x/file\". They are\nuntracked by git, but git should be careful about removing them.\n\n  $ git stash\n  Saved working directory and index state WIP on master: 2d32d3a initial\n  HEAD is now at 2d32d3a initial\n  $ ls -l x\n  -rw-r--r-- 1 peff peff 0 Jul 27 09:19 x\n  $ git stash show --raw\n  :100644 000000 e69de29... 0000000... D  x\n\nNow this _is_ data loss. Stash blows away untracked files inside the\ndirectory, but does not record them in the resulting stash. And that\nshould be fixed.\n\nWith \"-u\", I'd expect stash to include the untracked file x/foo in the\nstash. Without \"-u\", I'd expect stash to fail, since it would be\ndeleting untracked files.\n\n-Peff\n"},{"id":"195943","messageId":"20120727135051.GA10303@sigill.intra.peff.net","threadId":"31112","inReplyTo":"20120727132953.GA8263@sigill.intra.peff.net","subject":"Re: git stash data loss","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-07-27T13:50:51Z","receivedAt":"2012-07-27T13:50:51Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Jul 27, 2012 at 09:29:53AM -0400, Jeff King wrote:\n\n> If we put actual files inside \"x\", which git does track, then they would\n> be part of the stash, and should be properly retained. But they're not:\n> \n>   $ rm x && mkdir x && echo foo >x/file\n> \n> Now we have some precious contents in the form of \"x/file\". They are\n> untracked by git, but git should be careful about removing them.\n> \n>   $ git stash\n>   Saved working directory and index state WIP on master: 2d32d3a initial\n>   HEAD is now at 2d32d3a initial\n>   $ ls -l x\n>   -rw-r--r-- 1 peff peff 0 Jul 27 09:19 x\n>   $ git stash show --raw\n>   :100644 000000 e69de29... 0000000... D  x\n> \n> Now this _is_ data loss. Stash blows away untracked files inside the\n> directory, but does not record them in the resulting stash. And that\n> should be fixed.\n\nHrm. The problem is that after creating the stash, we then run \"git\nreset --hard\" to drop the changes that we just stashed. But that is not\nalways accurate. It will not usually touch untracked files, but it might\nif they have D/F conflicts with tracked files. So we need to replace\nthat \"git reset --hard\" with some safer command that will notice we are\nabout to overwrite untracked files. But I am not sure what that command\nwould be.\n\n-Peff\n"},{"id":"195944","messageId":"6BE6FF9E-0952-45D8-AFA7-0843CE3CFC5A@yandex.ru","threadId":"31112","inReplyTo":"20120727132953.GA8263@sigill.intra.peff.net","subject":"Re: git stash data loss","fromName":"Aleksandr Priymak","fromEmail":"tramsmm-mirror@yandex.ru","sentAt":"2012-07-27T14:21:36Z","receivedAt":"2012-07-27T14:21:36Z","isPatch":false,"sender":{"key":"tramsmm-mirror@yandex.ru","avatar":null},"body":"Thanks Jeff for the comment. You are right. I oversimplified the use-case ( forget to fill the directory )\n\nSent from my iPad\n\nOn Jul 27, 2012, at 5:29 PM, Jeff King <peff@peff.net> wrote:\n\n> On Fri, Jul 27, 2012 at 07:06:08AM +0400, Aleksandr Pryimak wrote:\n> \n>> I also recreated it\n>> \n>> aleksandr@beast:/tmp/test$ git init\n>> Initialized empty Git repository in /tmp/test/.git/\n>> aleksandr@beast:/tmp/test$ touch x\n>> aleksandr@beast:/tmp/test$ git add x\n>> aleksandr@beast:/tmp/test$ git commit -m \"Initial\"\n>> [master (root-commit) d3569a0] Initial\n>> 0 files changed, 0 insertions(+), 0 deletions(-)\n>> create mode 100644 x\n> \n> OK, so we have \"x\" as a tracked file.\n> \n>> aleksandr@beast:/tmp/test$ rm x\n>> aleksandr@beast:/tmp/test$ mkdir x/\n>> aleksandr@beast:/tmp/test$ ls\n>> x\n> \n> And then we remove it in favor of a directory. Note that git does not\n> track directories directly, only files inside them. So from git's\n> perspective, the working tree has no content in it at all.\n> \n>> aleksandr@beast:/tmp/test$ git stash\n>> Saved working directory and index state WIP on master: d3569a0 Initial\n>> HEAD is now at d3569a0 Initial\n> \n> And now we stash it. That will stash the working tree removal of x. It\n> will not stash anything about the new directory x, because it has no\n> content inside it.\n> \n>> aleksandr@beast:/tmp/test$ ls\n>> x\n>> aleksandr@beast:/tmp/test$ git stash pop\n>> Removing x\n>> # On branch master\n>> # Changes not staged for commit:\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:    x\n>> #\n>> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>> Dropped refs/stash@{0} (c500443ae16cf0d846b195cb97eb388dec5f440e)\n>> aleksandr@beast:/tmp/test$ ls\n> \n> And your stash pop restores the deletion of \"x\". It does _not_ reinstate\n> the directory \"x\", because as I stated above, that is not part of the\n> stash.\n> \n> So what is the data loss? That the \"mkdir x\" was lost? That has nothing\n> to do with stash, but rather the fact that git does not track empty\n> directories. You could see the same thing with:\n> \n>  mkdir x && git commit -a\n> \n> which will not record your mkdir at all. In other words, this is by\n> design.\n> \n> If we put actual files inside \"x\", which git does track, then they would\n> be part of the stash, and should be properly retained. But they're not:\n> \n>  $ rm x && mkdir x && echo foo >x/file\n> \n> Now we have some precious contents in the form of \"x/file\". They are\n> untracked by git, but git should be careful about removing them.\n> \n>  $ git stash\n>  Saved working directory and index state WIP on master: 2d32d3a initial\n>  HEAD is now at 2d32d3a initial\n>  $ ls -l x\n>  -rw-r--r-- 1 peff peff 0 Jul 27 09:19 x\n>  $ git stash show --raw\n>  :100644 000000 e69de29... 0000000... D  x\n> \n> Now this _is_ data loss. Stash blows away untracked files inside the\n> directory, but does not record them in the resulting stash. And that\n> should be fixed.\n> \n> With \"-u\", I'd expect stash to include the untracked file x/foo in the\n> stash. Without \"-u\", I'd expect stash to fail, since it would be\n> deleting untracked files.\n> \n> -Peff\n"},{"id":"197159","messageId":"7vy5lew5xz.fsf@alter.siamese.dyndns.org","threadId":"31112","inReplyTo":"20120727135051.GA10303@sigill.intra.peff.net","subject":"Re: git stash data loss","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-08-17T03:30:48Z","receivedAt":"2012-08-17T03:30:48Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Fri, Jul 27, 2012 at 09:29:53AM -0400, Jeff King wrote:\n>\n>> If we put actual files inside \"x\", which git does track, then they would\n>> be part of the stash, and should be properly retained. But they're not:\n>> \n>>   $ rm x && mkdir x && echo foo >x/file\n>> \n>> Now we have some precious contents in the form of \"x/file\". They are\n>> untracked by git, but git should be careful about removing them.\n>> \n>>   $ git stash\n>>   Saved working directory and index state WIP on master: 2d32d3a initial\n>>   HEAD is now at 2d32d3a initial\n>>   $ ls -l x\n>>   -rw-r--r-- 1 peff peff 0 Jul 27 09:19 x\n>>   $ git stash show --raw\n>>   :100644 000000 e69de29... 0000000... D  x\n>> \n>> Now this _is_ data loss. Stash blows away untracked files inside the\n>> directory, but does not record them in the resulting stash. And that\n>> should be fixed.\n>\n> Hrm. The problem is that after creating the stash, we then run \"git\n> reset --hard\" to drop the changes that we just stashed. But that is not\n> always accurate. It will not usually touch untracked files, but it might\n> if they have D/F conflicts with tracked files. So we need to replace\n> that \"git reset --hard\" with some safer command that will notice we are\n> about to overwrite untracked files. But I am not sure what that command\n> would be.\n\nIs this something we still want to keep track of?\n\nAs readers can probably guess, I am trying to come up with a list of\nloose ends for the next cycle.  This may be one of the low-hanging\nones.\n"},{"id":"197511","messageId":"20120821065527.GC3238@sigill.intra.peff.net","threadId":"31112","inReplyTo":"7vy5lew5xz.fsf@alter.siamese.dyndns.org","subject":"Re: git stash data loss","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-08-21T06:55:27Z","receivedAt":"2012-08-21T06:55:27Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Aug 16, 2012 at 08:30:48PM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > On Fri, Jul 27, 2012 at 09:29:53AM -0400, Jeff King wrote:\n> >\n> >> If we put actual files inside \"x\", which git does track, then they would\n> >> be part of the stash, and should be properly retained. But they're not:\n> >> \n> >>   $ rm x && mkdir x && echo foo >x/file\n> >> \n> >> Now we have some precious contents in the form of \"x/file\". They are\n> >> untracked by git, but git should be careful about removing them.\n> >> \n> >>   $ git stash\n> >>   Saved working directory and index state WIP on master: 2d32d3a initial\n> >>   HEAD is now at 2d32d3a initial\n> >>   $ ls -l x\n> >>   -rw-r--r-- 1 peff peff 0 Jul 27 09:19 x\n> >>   $ git stash show --raw\n> >>   :100644 000000 e69de29... 0000000... D  x\n> >> \n> >> Now this _is_ data loss. Stash blows away untracked files inside the\n> >> directory, but does not record them in the resulting stash. And that\n> >> should be fixed.\n> >\n> > Hrm. The problem is that after creating the stash, we then run \"git\n> > reset --hard\" to drop the changes that we just stashed. But that is not\n> > always accurate. It will not usually touch untracked files, but it might\n> > if they have D/F conflicts with tracked files. So we need to replace\n> > that \"git reset --hard\" with some safer command that will notice we are\n> > about to overwrite untracked files. But I am not sure what that command\n> > would be.\n> \n> Is this something we still want to keep track of?\n\nYeah, I think it is worth fixing. It's a somewhat rare case, but data\nloss is bad. I was hoping you would respond with \"...and here is the\nmagical incantation of git commands to make the working directory look\nlike we want\". I couldn't come up with one. We may need a new option to\nreset or read-tree.\n\n-Peff\n"},{"id":"199082","messageId":"7vtxv01a1o.fsf@alter.siamese.dyndns.org","threadId":"31112","inReplyTo":"20120821065527.GC3238@sigill.intra.peff.net","subject":"Re: git stash data loss","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-09-14T23:04:03Z","receivedAt":"2012-09-14T23:04:03Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>> > Hrm. The problem is that after creating the stash, we then run \"git\n>> > reset --hard\" to drop the changes that we just stashed. But that is not\n>> > always accurate. It will not usually touch untracked files, but it might\n>> > if they have D/F conflicts with tracked files. So we need to replace\n>> > that \"git reset --hard\" with some safer command that will notice we are\n>> > about to overwrite untracked files. But I am not sure what that command\n>> > would be.\n>> \n>> Is this something we still want to keep track of?\n>\n> Yeah, I think it is worth fixing. It's a somewhat rare case, but data\n> loss is bad. I was hoping you would respond with \"...and here is the\n> magical incantation of git commands to make the working directory look\n> like we want\". I couldn't come up with one. We may need a new option to\n> reset or read-tree.\n\nls-files has an ancient option to show the files \"killed\"; perhaps\nthat is the closest thing to what you are looking for.\n"}]}