{"thread":{"id":"57550","subject":"Bug report for git stash push.","startedAt":"2022-03-13T12:30:10Z","lastAt":"2022-03-13T12:30:10Z","messageCount":1,"participants":["contact@your-diary.io"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"451241","messageId":"aa8c4afddad08838584a5f9ec5c8e7ab@your-diary.io","threadId":"57550","inReplyTo":null,"subject":"Bug report for git stash push.","fromName":"","fromEmail":"contact@your-diary.io","sentAt":"2022-03-13T12:20:46Z","receivedAt":"2022-03-13T12:30:10Z","isPatch":false,"sender":{"key":"contact@your-diary.io","avatar":null},"body":"Dear, Git team\n\nHi.\nI, ynn, am contacting you to report a counter-intuitive behavior of `git \nstash push -- <file(s)>`.\nI believe this is a (at least documentation) bug.\n\nPrior to this email, I've discussed this problem on Stack Overflow:\nhttps://stackoverflow.com/questions/71411369/git-stash-push-file-doesnt-only-save-the-specified-file\n\n---------------------------------------------------\n\n# tl;dr\n\n`git stash push -- <file(s)>` is expected to save only the specified \n`<file(s)>` and let the other files intact.\nHowever, it doesn't.\n\n---------------------------------------------------\n\n# Expected Behavior\n\nAccording to `man git-stash`, `git stash push` is explained as below.\n\n```\npush [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] \n[-u|--include-untracked] [-a|--all]\n[-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> \n[--pathspec-file-nul]] [--]\n[<pathspec>...]\n     Save your local modifications to a new stash entry and roll them \nback to HEAD (in the working\n     tree and in the index). The <message> part is optional and gives the \ndescription along with\n     the stashed state.\n```\n\nwhere `<pathspec>` is defined as\n\n```\n<pathspec>...\n\n     This option is only valid for push command.\n\n     The new stash entry records the modified states only for the files \nthat match the pathspec.\n     The index entries and working tree files are then rolled back to the \nstate in HEAD only for\n     these files, too, leaving files that do not match the pathspec \nintact.\n```\n\nThis definition of `<pathspec>` says two things:\n\n(A) The new stash entry records the modified states only for the files \nthat match the pathspec.\n\n(B) The index entries and working tree files are then rolled back to the \nstate in HEAD only for these files, too, leaving files that do not match \nthe pathspec intact.\n\nLet's confirm these two in the next section.\n\n---------------------------------------------------\n\n# Actual Behavior\n\n## Preparations\n\n```\n$ git init test1\n$ cd test1\n$ echo aaa > a.txt\n$ echo bbb > b.txt\n$ git add .\n$ git commit -m 'H'\n$ cd ..\n$ cp -r test1 test2\n```\n\n## Pattern1\n\nWhen files are not staged, both (A) and (B) are satisfied.\n\n```\n$ cd test1\n\n$ echo aaa >> a.txt\n\n$ echo bbb >> b.txt\n\n$ git status\nOn branch master\nChanges not staged for commit:\n   (use \"git add <file>...\" to update what will be committed)\n   (use \"git restore <file>...\" to discard changes in working directory)\n     modified:   a.txt\n     modified:   b.txt\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n$ git stash push -- a.txt\nSaved working directory and index state WIP on master: 9806f0c H\n\n$ git status # (B) is satisfied\nOn branch master\nChanges not staged for commit:\n   (use \"git add <file>...\" to update what will be committed)\n   (use \"git restore <file>...\" to discard changes in working directory)\n     modified:   b.txt\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n\n$ git stash show # (A) is satisfied\n  a.txt | 1 +\n  1 file changed, 1 insertion(+)\n\n$ cd ..\n```\n\n## Pattern2\n\nWhen files are staged, only (B) is satisfied.\n\n```\n$ cd test2\n\n$ echo aaa >> a.txt\n\n$ echo bbb >> b.txt\n\n$ git add . # stages them\n\n$ git status\nOn branch master\nChanges to be committed:\n   (use \"git restore --staged <file>...\" to unstage)\n     modified:   a.txt\n     modified:   b.txt\n\n$ git stash push -- a.txt\nSaved working directory and index state WIP on master: 9806f0c H\n\n$ git status # (B) is satisfied\nOn branch master\nChanges to be committed:\n   (use \"git restore --staged <file>...\" to unstage)\n     modified:   b.txt\n\n$ git stash show # (A) is NOT satisfied.\n  a.txt | 1 +\n  b.txt | 1 +\n  2 files changed, 2 insertions(+)\n```\n\nLet's cite the explanation (A) again.\n\n(A) The new stash entry records the modified states only for the files \nthat match the pathspec.\n\nHowever, in the example above, the modified states of `a.txt` AND \n`b.txt` are saved in the newly created stash entry.\n\n---------------------------------------------------\n\n# Conclusion\n\n- Though I don't tell if the behavior is what the author of `git stash` \nintended to be, it seems counter-intuitive. Whilst I specify the \npathspec `-- a.txt`, not only `a.txt` but also `b.txt` are saved.\n\n- The behavior seems to contradict with the documentation, meaning at \nleast the documentation should be fixed.\n\nThank you.\n\n---------------------------------------------------\n\n# Environments\n\nInformation from `git bugreport`:\n\n```\n[System Info]\ngit version:\ngit version 2.35.1\ncpu: x86_64\nno commit associated with this build\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nuname: Linux 5.16.11-arch1-1 #1 SMP PREEMPT Thu, 24 Feb 2022 02:18:20 \n+0000 x86_64\ncompiler info: gnuc: 11.1\nlibc info: glibc: 2.35\n$SHELL (typically, interactive shell): <unset>\n\n[Enabled Hooks]\n```\n\n---------------------------------------------------\n"}]}