{"thread":{"id":"29747","subject":"Stash during incomplete merge","startedAt":"2012-02-26T18:36:55Z","lastAt":"2012-02-29T19:34:25Z","messageCount":4,"participants":["Phil Hord","Neal Kreitzinger"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"185466","messageId":"4F4A7BC7.5010702@cisco.com","threadId":"29747","inReplyTo":null,"subject":"Stash during incomplete merge","fromName":"Phil Hord","fromEmail":"hordp@cisco.com","sentAt":"2012-02-26T18:36:55Z","receivedAt":"2012-02-26T18:36:55Z","isPatch":false,"sender":{"key":"phil.hord@gmail.com","avatar":"https://avatars.githubusercontent.com/u/123908?v=4"},"body":"Hi list,\n\nI was cherry-picking changes from an old branch recently when I ran into\nunexpected behavior with git stash pop.  When I git-stash-save after\nresolving a  merge-conflict, the subsequent git-stash-pop does not\nrestore my index.\n\nI think it is the same problem being asked about here:\nhttp://stackoverflow.com/questions/9009354/git-stash-during-a-merge-conflict\n\nIs this expected behavior or a bug?\n\n<http://stackoverflow.com/questions/9009354/git-stash-during-a-merge-conflict>Here's\na script the demonstrates the anomaly, but my actual encounter involved\nmore files, some of which I added to the index and some I did not:\n\n# Create a sample merge-conflict\ngit init  tmp-repo && cd tmp-repo\necho foo > foo.txt && git add foo.txt && git commit -m \"foo\"\ngit checkout -b A master && echo foo-A > foo.txt && git commit -am \"foo-A\"\ngit checkout -b B master && echo foo-B > foo.txt && git commit -am \"foo-B\"\ngit merge A\ngit status\n# Resolve the conflict\necho foo-AB > foo.txt && git add foo.txt\ngit status\ngit stash\n# test test test...  Resume...\ngit stash pop\n\n\n\n\n\n\nHere's some of the final output:\n\n$ git merge A\nAuto-merging foo.txt\nCONFLICT (content): Merge conflict in foo.txt\nRecorded preimage for 'foo.txt'\nAutomatic merge failed; fix conflicts and then commit the result.\n\n$ git status\n# On branch B\n# Unmerged paths:\n#   (use \"git add/rm <file>...\" as appropriate to mark resolution)\n#\n#       both modified:      foo.txt\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n$ # Resolve the conflict\n$ echo foo-AB > foo.txt && git add foo.txt\n$ git status\n# On branch B\n# Changes to be committed:\n#\n#       modified:   foo.txt\n#\n\n$ # Now foo.txt is in my index.  But I have to test something before I\ncommit.\n$ git stash\nSaved working directory and index state WIP on B: 80f2a13 foo-B\nHEAD is now at 80f2a13 foo-B\n\n$ # test test test...  Resume...\n$ git stash pop\n\n# On branch B\n# Changes not staged for commit:\n#   (use \"git add <file>...\" to update what will be committed)\n#   (use \"git checkout -- <file>...\" to discard changes in working\ndirectory)\n#\n#       modified:   foo.txt\n#\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nDropped refs/stash@{0} (460a6d5c67a3db613fd27f1854ecc7b89eeaa207)\n"},{"id":"185671","messageId":"4F4D377B.2000206@gmail.com","threadId":"29747","inReplyTo":"4F4A7BC7.5010702@cisco.com","subject":"Re: Stash during incomplete merge","fromName":"Neal Kreitzinger","fromEmail":"nkreitzinger@gmail.com","sentAt":"2012-02-28T20:22:19Z","receivedAt":"2012-02-28T20:22:19Z","isPatch":false,"sender":{"key":"nkreitzinger@gmail.com","avatar":null},"body":"On 2/26/2012 12:36 PM, Phil Hord wrote:\n> Hi list,\n>\n> I was cherry-picking changes from an old branch recently when I ran into\n> unexpected behavior with git stash pop.  When I git-stash-save after\n> resolving a  merge-conflict, the subsequent git-stash-pop does not\n> restore my index.\n>\n> I think it is the same problem being asked about here:\n> http://stackoverflow.com/questions/9009354/git-stash-during-a-merge-conflict\n>\n> Is this expected behavior or a bug?\n>\n> <http://stackoverflow.com/questions/9009354/git-stash-during-a-merge-conflict>Here's\n> a script the demonstrates the anomaly, but my actual encounter involved\n> more files, some of which I added to the index and some I did not:\n>\n> # Create a sample merge-conflict\n> git init  tmp-repo&&  cd tmp-repo\n> echo foo>  foo.txt&&  git add foo.txt&&  git commit -m \"foo\"\n> git checkout -b A master&&  echo foo-A>  foo.txt&&  git commit -am \"foo-A\"\n> git checkout -b B master&&  echo foo-B>  foo.txt&&  git commit -am \"foo-B\"\n> git merge A\n> git status\n> # Resolve the conflict\n> echo foo-AB>  foo.txt&&  git add foo.txt\n> git status\n> git stash\n> # test test test...  Resume...\n> git stash pop\n>\n>\n> Here's some of the final output:\n>\n> $ git merge A\n> Auto-merging foo.txt\n> CONFLICT (content): Merge conflict in foo.txt\n> Recorded preimage for 'foo.txt'\n> Automatic merge failed; fix conflicts and then commit the result.\n>\n> $ git status\n> # On branch B\n> # Unmerged paths:\n> #   (use \"git add/rm<file>...\" as appropriate to mark resolution)\n> #\n> #       both modified:      foo.txt\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n>\n> $ # Resolve the conflict\n> $ echo foo-AB>  foo.txt&&  git add foo.txt\n> $ git status\n> # On branch B\n> # Changes to be committed:\n> #\n> #       modified:   foo.txt\n> #\n>\n> $ # Now foo.txt is in my index.  But I have to test something before I\n> commit.\n> $ git stash\n> Saved working directory and index state WIP on B: 80f2a13 foo-B\n> HEAD is now at 80f2a13 foo-B\n>\n> $ # test test test...  Resume...\n> $ git stash pop\n>\n> # On branch B\n> # Changes not staged for commit:\n> #   (use \"git add<file>...\" to update what will be committed)\n> #   (use \"git checkout --<file>...\" to discard changes in working\n> directory)\n> #\n> #       modified:   foo.txt\n> #\n> no changes added to commit (use \"git add\" and/or \"git commit -a\")\n> Dropped refs/stash@{0} (460a6d5c67a3db613fd27f1854ecc7b89eeaa207)\n>\nWas the foo.txt in your worktree still the same as the one you resolved \nand added to the index?\n\nIf so, at that point you can just do \"git add foo.txt\" to put it back in \nyour index.\n\n(merge conflict)\ngit add conflict-resolution (file is in worktree and index)\ngit stash (file is in stash of worktree and stash of index)\ngit stash pop (file is back in worktree but not back in index)\ngit add conflict-resolution (file is back in the index)\n\nIf not, then you must have a more complicated case like a modified \nworktree version that differs from the index version (original conflict \nresolution) in which case you need to also consider whether or not it is \nan [a]\"evil merge\".  Ideally, you intend to commit the index (conflict \nresolution) as the merge commit and add any worktree mods in addition to \nthat as a commit after the merge commit. If so, then I see your problem. \nThe next time, you can get both the worktree version and the index \nversion back with:\n\ngit stash apply --index\n\ngit stash does not apply the index by default so you have to specify the \n--index option if you want the index back also.  I recommend git stash \napply instead of git stash pop in case you realize you forgot the index. \nThen you can rerun git stash apply --index.  git stash pop can only be \nrun once because it throws away the stash after popping it.  You can run \ngit stash drop after you confirm that you did the git stash apply \ncorrectly.\n\nI assume you know that the stash is a stack and how to specify which \nstash you want by using the reflog syntax (see git-stash manpage: \nhttp://schacon.github.com/git/git-stash.html).  Stashes are really \n[b]\"commit objects\" of the worktree and index trees (you can see them in \ngitk by viewing all refs), but they are treated according to \"stash \nrules\" instead of \"commit rules\".\n\nIf you still want to try and get that conflict-resolution from the \n\"lost\" index from that stash you popped you can try this variation of \nthe \"Recovering stashes that were cleared/dropped erroneously\" procedure \nat the end of manpage:\n\n(1) Find the lost stash:\n$ git fsck --unreachable | grep commit | cut -d\" \"  -f3 | xargs git log \n--no-walk --grep=WIP --grep=\"index on\"\n\n(2) Review the list of commits and decide which pair is for the stash \nyou want.  Note on stash commit-object messages:\nWIP = stash commit-object of the worktree\n\"index on\" = stash commit-object of the index (this may not exist of the \nindex didn't differ from the worktree)\n\n(3) Reset the conflict-resolution-file(s) from the stash of the index:\n\n$ git reset <sha1-of-stash-commit-object-of-index> -- \n<conflict-resolution-file>\n\ngit reset will just put it back in your index and leave the worktree alone.\n\nYou may also want to consider the --keep-index option on your \"git stash \nsave\" if your \"testing\" workflow doesn't involve adds or commits before \nthe git stash apply/pop.\n\nFootnotes:\na. If you resolved the conflict and then made further mods that is \ncalled an \"evil merge\" because you really didn't just merge the changes \nof the two parents, but also made additional changes that were not part \nof the changes made by either of the parents your are merging.  The \nadditional changes really should be their own commit after the merge. \n\"Evil merges\" are misleading (and also probably not documented in the \nmerge commit message with a git commit --amend).\nb. There are only 4 types of objects in git: tag, commit, tree, blob.\n\nHope this helps. Maybe someone else has a better way to do this.  Maybe \nmy assumptions are incorrect and I'm missing something about what you \nare trying to do.\n\nv/r,\nneal\n"},{"id":"185676","messageId":"4F4D5408.3060505@gmail.com","threadId":"29747","inReplyTo":"4F4D377B.2000206@gmail.com","subject":"Re: Stash during incomplete merge","fromName":"Neal Kreitzinger","fromEmail":"nkreitzinger@gmail.com","sentAt":"2012-02-28T22:24:08Z","receivedAt":"2012-02-28T22:24:08Z","isPatch":false,"sender":{"key":"nkreitzinger@gmail.com","avatar":null},"body":"On 2/28/2012 2:22 PM, Neal Kreitzinger wrote:\n>\n> You may also want to consider the --keep-index option on your \"git\n> stash save\" if your \"testing\" workflow doesn't involve adds or\n> commits before the git stash apply/pop.\n>\nthe very limited case I had in mind (and probably incorrect assumption)\nabout your \"testing\" workflow was:\n\nhack merge-conflicts\n$ git add conflict-resolution  (conflict-resolution is in worktree and\nindex)\nhack conflict-resolution with extra stuff (original conflict-resolution\nis still in index)\nuh-oh, i got carried away and started doing extra stuff (evil merge) and\nforgot to finish testing just the conflict-resolutions (pure merge-commit)\n$ git stash --keep-index (conflict-resolution is still in index and now\nback in wokrtree)\nfinish testing just the conflict-resolutions (merge-commit-to-be)\n(conflict resolutions worked (I knew they would))\n$ git stash pop (original conflict resolution is still in index, but\nextra-stuff is back in worktree)\n$ git commit (commit the conflict-resolutions/merge-commit)\n$ git add foo\n$ git commit (new foo stuff committed after merge commit)\n\nv/r,\nneal\n"},{"id":"185737","messageId":"4F4E7DC1.1050700@gmail.com","threadId":"29747","inReplyTo":"4F4D5408.3060505@gmail.com","subject":"Re: Stash during incomplete merge","fromName":"Neal Kreitzinger","fromEmail":"nkreitzinger@gmail.com","sentAt":"2012-02-29T19:34:25Z","receivedAt":"2012-02-29T19:34:25Z","isPatch":false,"sender":{"key":"nkreitzinger@gmail.com","avatar":null},"body":"On 2/28/2012 4:24 PM, Neal Kreitzinger wrote:\n> On 2/28/2012 2:22 PM, Neal Kreitzinger wrote:\n>>\n>> You may also want to consider the --keep-index option on your \"git\n>>  stash save\" if your \"testing\" workflow doesn't involve adds or\n>> commits before the git stash apply/pop.\n>>\n> the very limited case I had in mind (and probably incorrect\n> assumption) about your \"testing\" workflow was:\n>\n> hack merge-conflicts $ git add conflict-resolution\n> (conflict-resolution is in worktree and index) hack\n> conflict-resolution with extra stuff (original conflict-resolution\n> is still in index) uh-oh, i got carried away and started doing extra\n> stuff (evil merge) and forgot to finish testing just the\n> conflict-resolutions (pure merge-commit) $ git stash --keep-index\n> (conflict-resolution is still in index and now back in wokrtree)\n> finish testing just the conflict-resolutions (merge-commit-to-be)\n> (conflict resolutions worked (I knew they would)) $ git stash pop\n> (original conflict resolution is still in index, but extra-stuff is\n> back in worktree) $ git commit (commit the\n> conflict-resolutions/merge-commit) $ git add foo $ git commit (new\n> foo stuff committed after merge commit)\n>\nThis imaginary scenario I proposed for --keep-index can get a\nmerge-conflict on the pop so its invalid.  Please disregard it.  Sorry\nfor the bum scoop.\n\nv/r,\nneal\n"}]}