'git stash push <file> doesn't only save the specified file
In man git-stash, git stash push is explained as below:
push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all]
[-q|--quiet] [-m|--message <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--]
[<pathspec>...]
Save your local modifications to a new stash entry and roll them back to HEAD (in the working
tree and in the index). The <message> part is optional and gives the description along with
the stashed state.
where <pathspec> is
<pathspec>...
This option is only valid for push command.
The new stash entry records the modified states only for the files that match the pathspec.
The index entries and working tree files are then rolled back to the state in HEAD only for
these files, too, leaving files that do not match the pathspec intact.
So git stash push -- <file> should only save <file> as a stash entry, right?
However, as far as I tested, git stash push -- <file> saves everything (i.e. not limited to <file>):
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: LICENSE.md
modified: README.md
modified: src/attach.ts
$ git stash push -- README.md
Saved working directory and index state WIP on master: ccd0b050 fix(highlight): use coc#compat#buf_line_count
$ git status #This is as expected.
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: LICENSE.md
modified: src/attach.ts
$ git stash show #Why? This is not what I expect.
LICENSE.md | 2 +-
README.md | 2 +-
src/attach.ts | 1 +
3 files changed, 3 insertions(+), 2 deletions(-)
$ git reset --hard
HEAD is now at ccd0b050 fix(highlight): use coc#compat#buf_line_count
$ git status #This is as expected.
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
$ git stash pop #Strangely, not only `README.md` is restored.
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: LICENSE.md
modified: README.md
modified: src/attach.ts
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (0ee651d4a9206e2e8ce384ca6623175fa3edcdcd)
How can this be explained?
Environments: macOS with git 2.35.1 (installed via brew), Arch Linux with git 2.35.1
Solution 1:[1]
TL;DR : I think git stash starts by storing the complete index, so if your files are staged for commit before you run git stash push -- <paths...>, you will have the complete index stored in the stash.
Starting from the following setup :
$ git init
$ echo aaa > a.txt && echo bbb > b.txt
$ git add a.txt b.txt
$ git commit -m "first commit"
$ echo aaa >> a.txt # add a line to a.txt
$ echo bbb >> b.txt # add a line to b.txt
# repo state after the above setup :
$ git status -s
M a.txt
M b.txt
$ git stash show
No stash entries found.
If the files are not staged before stashing, stashing only one file works as we would expect :
$ git stash push -- a.txt
Saved working directory and index state WIP on master: c652c35 first commit
# index and stash content are as is expected :
$ git status -s
M b.txt
$ git stash show
a.txt | 1 +
1 file changed, 1 insertion(+)
$ git log --oneline --graph --name-status --cc stash
* 07770c0 (refs/stash) WIP on master: c652c35 first commit
|\
| |
MM a.txt
| * 58d58bf index on master: c652c35 first commit
|/
* c652c35 (HEAD -> master) first commit
...
If the files are staged before stashing, though (and I think this is the situation you describe ?), it looks like git stash starts with writing the complete index :
$ git add a.txt b.txt
$ git stash push -- a.txt
Saved working directory and index state WIP on master: c652c35 first commit
$ git status -s
M b.txt
$ git stash show
a.txt | 1 +
b.txt | 1 +
2 files changed, 2 insertions(+)
$ git log --oneline --graph --name-only --cc stash
* 1a10665 (refs/stash) WIP on master: c652c35 first commit
|\
| |
| * c26f4a2 index on master: c652c35 first commit
|/
| M a.txt # the complete index is stashed
| M b.txt
* c652c35 (HEAD -> master) first commit
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
