{"thread":{"id":"57939","subject":"BUG? git stash and immediate git apply results in conflict","startedAt":"2022-06-01T06:56:03Z","lastAt":"2022-06-02T12:25:06Z","messageCount":4,"participants":["Akos Vandra-Meyer","Chris Torek"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"456434","messageId":"CAHHcNoe12h5E9OmkZy03-i7miFg2hLiT04BF3_t9C2bcmduR5Q@mail.gmail.com","threadId":"57939","inReplyTo":null,"subject":"BUG? git stash and immediate git apply results in conflict","fromName":"Akos Vandra-Meyer","fromEmail":"axos88@gmail.com","sentAt":"2022-06-01T06:55:46Z","receivedAt":"2022-06-01T06:56:03Z","isPatch":false,"sender":{"key":"axos88@gmail.com","avatar":null},"body":"Hello!\n\nI believe there might be a bug in how a git stash is calculated with\nthe -k flag.\nI would expect to always be able to stash and pop a set of changes,\nbut if the working directory contains staged and unstaged changes for\na file, this results in a conflict.\n\nThe stashed diff shows the changes from the last commit, rather than\nwhat is in the current working directory, so when the stash is applied\nit results in a conflict, because there are staged changes in the\ncurrent working directory.\n\nSteps to reproduce:\n\n mkdir test\n cd test\n git init .\n echo foo > a\n echo bar >> a\n echo baz >> a\n git add a\n git commit -m \"initial\"\n cat a | sed s/bar/foo2/ > a2; mv a2 a git status\n git add a\n cat a | sed s/foo2/xxx/ > a2; mv a2 a\n git status\n git stash -ku\n git stash pop\n\nThanks for looking into this,\n  Akos Vandra-Meyer\n"},{"id":"456478","messageId":"CAPx1GvfQLP3q-SvW38=VOxoAmQpMMau_UfXXXQiZSV3NOJCs0w@mail.gmail.com","threadId":"57939","inReplyTo":"CAHHcNoe12h5E9OmkZy03-i7miFg2hLiT04BF3_t9C2bcmduR5Q@mail.gmail.com","subject":"Re: BUG? git stash and immediate git apply results in conflict","fromName":"Chris Torek","fromEmail":"chris.torek@gmail.com","sentAt":"2022-06-02T06:32:45Z","receivedAt":"2022-06-02T06:33:04Z","isPatch":false,"sender":{"key":"chris.torek@gmail.com","avatar":"https://avatars.githubusercontent.com/u/16826774?v=4"},"body":"On Wed, Jun 1, 2022 at 2:11 PM Akos Vandra-Meyer <axos88@gmail.com> wrote:\n>  git stash -ku\n>  git stash pop\n\nThis is not a bug in `git stash` itself, but rather in the way you're using it.\n\nThere are two mistakes on your part here:\n\n1: You are using `-k`, aka `--keep-index`. This flag is intended for usages\nthat are not yours here.\n\n2. You are *not* using `--index` in your `git pop`.  The `--index` flag is\nintended for the kind of thing you are doing here.\n\nIt's a bit unfortunate (and perhaps worth some work in the documentation)\nthat the `--keep-index` and `--index` flags sound so similar, and yet are so\ndifferent.  The documentation could use some examples here, I think.\n\nNote that if you *do* want to use `--keep-index` during the `git stash` step,\nyou will need a `git reset --hard` before your `git stash apply --index &&\ngit stash drop` step (aka `git stash pop --index`).\n\nChris\n"},{"id":"456490","messageId":"CAHHcNodnB8gnaLgxW-vr6PxHh_YjCOAf7CTuot-CJsonb1mdnA@mail.gmail.com","threadId":"57939","inReplyTo":"CAPx1GvfQLP3q-SvW38=VOxoAmQpMMau_UfXXXQiZSV3NOJCs0w@mail.gmail.com","subject":"Re: BUG? git stash and immediate git apply results in conflict","fromName":"Akos Vandra-Meyer","fromEmail":"axos88@gmail.com","sentAt":"2022-06-02T11:31:33Z","receivedAt":"2022-06-02T11:31:49Z","isPatch":false,"sender":{"key":"axos88@gmail.com","avatar":null},"body":"Hi Chris,\n\nThanks for getting back to me on this.\nMy use case is the following:\n\nI made a bunch of (loosely related) changes to my code, but I have\nbeen asked to submit them as separate commits, so I need to separate\nthe changes to dependent files relating to the first and second\nfeature.\n\nSo I need to separate the changes in my workdir into two commits\n(let's call them two features). Turns out the first feature needs a\ndependent file changed in one way, and the second feature improves on\nit, so it needs it changed in another way - normally this would result\nin a conflict if they would have been done separately in different\nbranches.\n\nI start off by stashing everything except stuff directly relating to\nthe first feature and stashing everything else. Check for build\nerrors, unstage, and incrementally staging more stuff that need to be\nadded in order to make the first feature build correctly. At some\npoint I reach the file that has to be changed differently, so I will\nhave a set of changes staged for that file, while another set of\nchanges remain unstaged - the changes that will be required by the\nsecond feature.\n\nAt this point you pointed out that apparantly I'm misusing git, but I\nam confused on how to correctly stash the unstaged changes to check if\nthe code would build with the staged changes only, and unstage them\nand add more stuff if not?\n\nThanks,\n  Akos\n\n\n\n\n\nOn Thu, 2 Jun 2022 at 08:32, Chris Torek <chris.torek@gmail.com> wrote:\n>\n> On Wed, Jun 1, 2022 at 2:11 PM Akos Vandra-Meyer <axos88@gmail.com> wrote:\n> >  git stash -ku\n> >  git stash pop\n>\n> This is not a bug in `git stash` itself, but rather in the way you're using it.\n>\n> There are two mistakes on your part here:\n>\n> 1: You are using `-k`, aka `--keep-index`. This flag is intended for usages\n> that are not yours here.\n>\n> 2. You are *not* using `--index` in your `git pop`.  The `--index` flag is\n> intended for the kind of thing you are doing here.\n>\n> It's a bit unfortunate (and perhaps worth some work in the documentation)\n> that the `--keep-index` and `--index` flags sound so similar, and yet are so\n> different.  The documentation could use some examples here, I think.\n>\n> Note that if you *do* want to use `--keep-index` during the `git stash` step,\n> you will need a `git reset --hard` before your `git stash apply --index &&\n> git stash drop` step (aka `git stash pop --index`).\n>\n> Chris\n"},{"id":"456493","messageId":"CAPx1GveKYjEoAnhJLkGOo9Esd5-vhkFkbz2Uwy10j5fxR_W9Bw@mail.gmail.com","threadId":"57939","inReplyTo":"CAHHcNodnB8gnaLgxW-vr6PxHh_YjCOAf7CTuot-CJsonb1mdnA@mail.gmail.com","subject":"Re: BUG? git stash and immediate git apply results in conflict","fromName":"Chris Torek","fromEmail":"chris.torek@gmail.com","sentAt":"2022-06-02T12:24:50Z","receivedAt":"2022-06-02T12:25:06Z","isPatch":false,"sender":{"key":"chris.torek@gmail.com","avatar":"https://avatars.githubusercontent.com/u/16826774?v=4"},"body":"On Thu, Jun 2, 2022 at 4:31 AM Akos Vandra-Meyer <axos88@gmail.com> wrote:\n> Hi Chris,\n>\n> Thanks for getting back to me on this.\n> My use case is the following:\n>\n> I made a bunch of (loosely related) changes to my code, but I have\n> been asked to submit them as separate commits, so I need to separate\n> the changes to dependent files relating to the first and second\n> feature.\n\nI snipped the rest of this because I *dislike* and *recommend against*\nthe use of `git stash` in the first place. If you want to use it that way, I am\nsure it is possible, but I recommend doing something else entirely.\nThe rest of this message is all opinion! You seem to be looking for\na recommended method, so I'm recommending mine.\n\nLet's say for concreteness that your current branch is named \"topic\".\nHere is what I would do (though I might change strategies and use\nvarious short-cuts depending on various sub-scenarios; this is meant\nfor illustrating how to do what you want, in a way that provides the\nmost clarity):\n\ngit add (files as needed)\ngit commit -m \"final version, to be split up\"\ngit branch -m not-final-topic\n\nThen:\n\n# create a new topic branch\ngit checkout -b new-topic <start-point>\n\n# get a view of commits\ngit log HEAD..topic\n\n# copy some commits, up until some point\ngit cherry-pick <some of those commits as desired>\n\n# begin splitting a commit:\ngit cherry-pick -n <hash>\n\n# split it up: use a mix of the following:\ngit reset / git add -p / git reset -p\n                # as needed here to take part of the commit)\n\n# observe what's to be committed\ngit diff --cached\ngit commit      # and write a commit message\n\ngit add -p ...  # as needed again\ngit diff --cached\ngit commit      # repeat until satisfied with broken up commit(s)\n\n# make sure final result matches - optional: use the same\n# hash here as for the `git cherry-pick -n` command\ngit diff HEAD <hash>\n\n# repeat copying whole and partial commits:\n\ngit cherry-pick ...     # add more whole commits as desired\ngit cherry-pick -n ...  # add commit that is to be split up\n                        # repeat the split-up process\n\n# When finally done, ensure that new-topic and not-final-topic\n# have the same contents. If they do, the split-up was successful.\ngit diff not-final-topic HEAD\n\nNote that there is no longer any branch named \"topic\" at this\npoint: we have instead \"not-final-topic\" and \"new-topic\". We\ncan now rename \"new-topic\" to \"topic\" and use `git push -f`\nor whatever else is appropriate for whatever review system(s)\nyou may be using.\n\nThe entire process above can often be done with a single `git\nrebase -i` command, but that obscures the fundamental nature of\nwhat you're really doing. The repeated cherry-pick, reset, add\n-p, and/or reset -p sequence is what you're really doing: you are\ntaking some set of existing commits, which are *close* to the\ncommits you'd like to have, and rebuilding them to make a new set\nof commits (with different hash IDs) that represent what you\nreally do want.\n\nIn the end, you will have Git *find* your commits by name: the\nname \"topic\" will name the last commit in a chain of commits.\nThe names here are up to you, and you can change any name at\nany time using `git branch -m`. Both Git and any review system\nyou use is going to use the *commits*, with their scary looking\nhash IDs, but like you they will *find* these commits by starting\nfrom a branch name: so by changing the hash ID stored in the\nbranch name, you change the set of commits they (and you) find.\n\nWhat `git stash` does is make several commits that are not on\n*any* branch. These commits are a little weird, requiring the\nuse of the `git stash` command to access them. Ordinary commits\non ordinary branches are not weird and do not need any special\naccess, so that's what I prefer.  But the fact that the stash commits\nare on *no* branch makes it easy to slide them from one branch to\nanother without having to think about hash IDs; that's one reason\nsome people prefer `git stash`. I'm just not one of those people.\n\nChris\n"}]}