{"thread":{"id":"34339","subject":"unexpected file deletion after using git rebase --abort","startedAt":"2013-07-03T22:44:02Z","lastAt":"2013-07-05T07:07:02Z","messageCount":6,"participants":["Paul A. Kennedy","Jonathan Nieder","Junio C Hamano","Eric Sunshine"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"222515","messageId":"20130703224402.GF9016@localhost.localdomain","threadId":"34339","inReplyTo":null,"subject":"unexpected file deletion after using git rebase --abort","fromName":"Paul A. Kennedy","fromEmail":"pakenned@pobox.com","sentAt":"2013-07-03T22:44:02Z","receivedAt":"2013-07-03T22:44:02Z","isPatch":false,"sender":{"key":"pakenned@pobox.com","avatar":null},"body":"Hello!\n\nI lost a previously untracked file that I added to the index in the\nmiddle of a git rebase --interactive session after a git rebase --abort.\nThis was unexpected.\n\n    $ ls forgotten_file\n    forgotten_file\n    $ git rebase --interactive HEAD~3 \n      [change first rebase command from pick to  edit]\n    $ git add forgotten_file\n    $ git rebase --abort\n    $ ls forgotten_file\n    ls: cannot access forgotten_file: No such file or directory\n    $\n\nI was (of course) able to find the SHA-1 of the dangling blob using 'git\nfsck', and then retrieve the file using 'git cat-file -p SHA1'\n\nShould this behaviour be considered a bug?  That is, should the contents\nof the working directory (including untracked files) before the git\nrebase invocation be returned (as if preserved by a git stash\n--include-untracked)?  \n\nIf we don't expect this, should we update the documentation for the\n--abort heading in the git rebase man page to indicate that newly\nstaged content will be lost after a git rebase --abort?\n\nThis is for git version 1.8.3\n\nPaul\n\n--\nPaul A. Kennedy\npakenned@pobox.com\n"},{"id":"222516","messageId":"20130703225642.GU408@google.com","threadId":"34339","inReplyTo":"20130703224402.GF9016@localhost.localdomain","subject":"Re: unexpected file deletion after using git rebase --abort","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2013-07-03T22:56:43Z","receivedAt":"2013-07-03T22:56:43Z","isPatch":false,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Paul A. Kennedy wrote:\n\n> If we don't expect this, should we update the documentation for the\n> --abort heading in the git rebase man page to indicate that newly\n> staged content will be lost after a git rebase --abort?\n\nHow about something along these lines?\n\ndiff --git i/Documentation/git-rebase.txt w/Documentation/git-rebase.txt\nindex 6b2e1c8..dcae40d 100644\n--- i/Documentation/git-rebase.txt\n+++ w/Documentation/git-rebase.txt\n@@ -240,6 +240,9 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \tstarted, then HEAD will be reset to <branch>. Otherwise HEAD\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n++\n+This discards any changes to files tracked in the working tree or <branch>.\n+You may want to stash your changes first (see linkgit:git-stash[1]).\n \n --keep-empty::\n \tKeep the commits that do not change anything from its\n"},{"id":"222517","messageId":"7vip0rckjs.fsf@alter.siamese.dyndns.org","threadId":"34339","inReplyTo":"20130703225642.GU408@google.com","subject":"Re: unexpected file deletion after using git rebase --abort","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-07-03T23:04:23Z","receivedAt":"2013-07-03T23:04:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> Paul A. Kennedy wrote:\n>\n>> If we don't expect this, should we update the documentation for the\n>> --abort heading in the git rebase man page to indicate that newly\n>> staged content will be lost after a git rebase --abort?\n>\n> How about something along these lines?\n>\n> diff --git i/Documentation/git-rebase.txt w/Documentation/git-rebase.txt\n> index 6b2e1c8..dcae40d 100644\n> --- i/Documentation/git-rebase.txt\n> +++ w/Documentation/git-rebase.txt\n> @@ -240,6 +240,9 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n>  \tstarted, then HEAD will be reset to <branch>. Otherwise HEAD\n>  \twill be reset to where it was when the rebase operation was\n>  \tstarted.\n> ++\n> +This discards any changes to files tracked in the working tree or <branch>.\n> +You may want to stash your changes first (see linkgit:git-stash[1]).\n>  \n\n\"rebase --abort\" is typically used to get rid of conflicted mess the\nuser does not want to resolve right now, and \"stash\" would not be a\nsensible thing to use in such a situation, I think.  Doesn't it even\nrefuse to work if there is a conflicted entry in the index?\n"},{"id":"222581","messageId":"20130704193550.GA4183@localhost.localdomain","threadId":"34339","inReplyTo":"7vip0rckjs.fsf@alter.siamese.dyndns.org","subject":"Re: unexpected file deletion after using git rebase --abort","fromName":"Paul A. Kennedy","fromEmail":"pakenned@pobox.com","sentAt":"2013-07-04T19:35:51Z","receivedAt":"2013-07-04T19:35:51Z","isPatch":false,"sender":{"key":"pakenned@pobox.com","avatar":null},"body":"On Wed, Jul 03, 2013 at 04:04:23PM -0700, Junio C Hamano wrote:\n> Jonathan Nieder <jrnieder@gmail.com> writes:\n> > Paul A. Kennedy wrote:\n> > > If we don't expect this, should we update the documentation for the\n> > > --abort heading in the git rebase man page to indicate that newly\n> > > staged content will be lost after a git rebase --abort?\n> >\n> > How about something along these lines?\n> >\n> > diff --git i/Documentation/git-rebase.txt w/Documentation/git-rebase.txt\n> > index 6b2e1c8..dcae40d 100644\n> > --- i/Documentation/git-rebase.txt\n> > +++ w/Documentation/git-rebase.txt\n> > @@ -240,6 +240,9 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n> >  \tstarted, then HEAD will be reset to <branch>. Otherwise HEAD\n> >  \twill be reset to where it was when the rebase operation was\n> >  \tstarted.\n> > ++\n> > +This discards any changes to files tracked in the working tree or <branch>.\n> > +You may want to stash your changes first (see linkgit:git-stash[1]).\n> >  \n> \n> \"rebase --abort\" is typically used to get rid of conflicted mess the\n> user does not want to resolve right now, and \"stash\" would not be a\n> sensible thing to use in such a situation, I think.  Doesn't it even\n> refuse to work if there is a conflicted entry in the index?\n\nThanks for thinking about this with me.  \n\nAfter contemplating your messages, I think that it's unreasonable to\nexpect git rebase --abort to be able to properly handle content from\ncompletely outside the repo and only placed in the index.\n\nI think that Jonathan's suggestion makes too mild a point (and I\nthink Junio's objection may be a consequence of this).  I've added a\nlittle paragraph to the documentation that covers two cases: what you\nshould do before you started (i.e. git-stash if messing about with\nadding content); and how to recover in case you managed to \"lose\"\ncontent in this way (hence the links to git-fsck and git-cat-file).\n\nThis is the diff (against v.1.8.3.2 in the git tree):\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex aca8405..ffaef29 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -238,6 +238,13 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n \twill be reset to where it was when the rebase operation was\n \tstarted.\n \n+\tUntracked files added to the index will not be unstaged, and\n+\ttherefore, not present in the working directory upon abort.\n+\tUnstage files before the abort, or stash untracked content before\n+\tstarting the rebase (see linkgit:git-stash[1]).  Dangling blobs\n+\tmay be found and recovered using fsck and cat-file (see\n+\tlinkgit:git-fsck[1], linkgit:git-cat-file[1]).\n+\n --keep-empty::\n \tKeep the commits that do not change anything from its\n \tparents in the result.\n\n--\nPaul A. Kennedy\npakenned@pobox.com\n"},{"id":"222596","messageId":"CAPig+cSz2MH4REJyNDox_NCM3DnFamizzMMiDzX=SumpDL77Gw@mail.gmail.com","threadId":"34339","inReplyTo":"20130704193550.GA4183@localhost.localdomain","subject":"Re: unexpected file deletion after using git rebase --abort","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2013-07-04T23:27:36Z","receivedAt":"2013-07-04T23:27:36Z","isPatch":false,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jul 4, 2013 at 3:35 PM, Paul A. Kennedy <pakenned@pobox.com> wrote:\n> diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\n> index aca8405..ffaef29 100644\n> --- a/Documentation/git-rebase.txt\n> +++ b/Documentation/git-rebase.txt\n> @@ -238,6 +238,13 @@ leave out at most one of A and B, in which case it defaults to HEAD.\n>         will be reset to where it was when the rebase operation was\n>         started.\n>\n> +       Untracked files added to the index will not be unstaged, and\n> +       therefore, not present in the working directory upon abort.\n> +       Unstage files before the abort, or stash untracked content before\n> +       starting the rebase (see linkgit:git-stash[1]).  Dangling blobs\n> +       may be found and recovered using fsck and cat-file (see\n> +       linkgit:git-fsck[1], linkgit:git-cat-file[1]).\n> +\n\nNot commenting about the change in general, just one issue: The\ntransition to \"dangling blobs\" seems abrupt and may convey little\nmeaning to non-expert users. Perhaps lead in to that sentence with\nsomething along the lines of:\n\n  \"If you neglect to unstage untracked files before abort, they become\ndangling blogs, which may be found ...\"\n\nAlso, a bit earlier, perhaps: s/Unstage files/Manually unstage files/\n"},{"id":"222602","messageId":"7vd2qxa3jd.fsf@alter.siamese.dyndns.org","threadId":"34339","inReplyTo":"20130704193550.GA4183@localhost.localdomain","subject":"Re: unexpected file deletion after using git rebase --abort","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-07-05T07:07:02Z","receivedAt":"2013-07-05T07:07:02Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Paul A. Kennedy\" <pakenned@pobox.com> writes:\n\n>> \"rebase --abort\" is typically used to get rid of conflicted mess the\n>> user does not want to resolve right now, and \"stash\" would not be a\n>> sensible thing to use in such a situation, I think.  Doesn't it even\n>> refuse to work if there is a conflicted entry in the index?\n>\n> Thanks for thinking about this with me.  \n>\n> After contemplating your messages, I think that it's unreasonable to\n> expect git rebase --abort to be able to properly handle content from\n> completely outside the repo and only placed in the index.\n\nThe essense of \"--abort\" is to bring your index and the working tree\nstate back to the state you had before you got into a conflicted\nmess.\n\nFor paths that still have higher/conflicted stages in the index, it\nis easy to decide what should happen.  Because we do not even allow\nrebase to start with an index with conflicted paths, they must have\ncome from the rebase operation itself, so matching them to what is\nin the HEAD (and removing such conflicted paths that are not in the\nHEAD) is always the right thing.\n\nBut for paths in the index that are already resolved at stage #0,\nit is not simple.  They can come from\n\n (1) a clean automatic resolution (including the case where the\n     rebase did not even touch the path).\n\n (2) a conflict that was resolved manually and then \"git add\"ed.\n\n (3) manual \"git add\" of a path that a mechanical part of the rebase\n     operation did not touch at all.\n\nFor (1) and (2), it is the right thing to match with HEAD and\nto remove the path if it is not in HEAD (e.g. the path may have\nappeared by attempting to replay a change to add it).\n\nFor (3), a change may update existing files in HEAD or it may add a\nnew path not in HEAD.  Ideally, the former should be reverted to\nHEAD, and the latter should be only reverted in the index but leave\nthe file in the working tree untracked.\n\nBut there is no good way to tell these three classes apart,\nunfortunately.  With recent Git, I think you can tell paths in\ncategory (2) by noticing that they have \"REUC\" entries for them in\nthe index extension section.\n\nThe only case we may want to behave differently is \"git add\" that\nadds a path that does not exist (at any stage) to the index, so\ntheoretically, we could teach the end-user facing \"git add\" to leave\na new extension entry to the index, teach \"git reset --no-so-hard\"\nto notice the index extension to leave the path in the working tree\nwhen reverting to a HEAD that does not have such a path and use it\nin \"rebase --abort\" codepath.  Which would also allow us to be less\naggressive in a case like this:\n\n\t... have many untracked and unignored paths\n        $ git add .\n        ... oops, I did not mean it\n        $ git reset --hard\n\t... double-oops, these untracked paths are all gone\n\nBut that is \"theoretical\" primarily because it is unclear what the\nexhaustive set of situations where we must clear such a \"this is\nnewly added\" mark to avoid false positives.  After \"git commit\" that\nrecords such a path in a commit is obviously one of them, but that\nis not the only one, and every place we forget to clear the mark\nwill be a cause of confusion.\n\nAlternatively, perhaps we could create the \"REUC\" extension for\ncategory (1) paths as well.  Then \"git reset --not-so-hard $commit\"\ncould be changed to behave the same way as it does today, except\nthat it would not remove paths without \"REUC\" extension entry from\nthe working tree.\n\n> +\tUntracked files added to the index will not be unstaged, and\n> +\ttherefore, not present in the working directory upon abort.\n> +\tUnstage files before the abort, or stash untracked content before\n> +\tstarting the rebase (see linkgit:git-stash[1]).\n\n\"Unstage files\" is a less than ideal suggestion.\n\n\t$ git rebase\n        ... oops conflicted\n        ... ouch, this is too much for me to resolve\n        $ git reset\n        $ git rebase --abort\n\nwould leave a path that was introduced by the change being replayed\nin the working tree, which may later interfere when you try to\ncheckout a branch that does have that path.  At least it has to be\n\"Unstage such files that were untracked and added by you\" to be\nhelpful, I think.\n"}]}