Home > Software engineering >  "git stash show" after stashing only one file
"git stash show" after stashing only one file

Time:08-30

Ran git stash to stash just one file out of 4 tracked files.

Using git stash show displays not only that file but the other staged files as well. Why? For example: why does it show anything other than the file "application.xml" that I stashed?

$ git status
On branch some/0.0.1
Your branch is up to date with 'origin/some/0.0.1'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    modified:   src/main/java/ServiceServiceImpl.java
    modified:   src/main/java/util/ServiceUtil.java
    modified:   src/test/SystemTest.java

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:   src/main/java/util/ServiceUtil.java
    modified:   src/main/resources/application-local.yml
    modified:   src/main/resources/application.yml
    modified:   src/main/resources/logback.xml


$ git stash push src/main/resources/application.yml -m "app.xml stashed" <-- stash just one file
Saved working directory and index state On 0.0.1: app.xml stashed

$ git stash list
stash@{0}: On 0.0.1: app.xml stashed

$ git stash show stash@{0} <---------------- Why does it show "staged" files other than the one I stashed (which is src/main/resources/application.yml)
 .../java/ServiceServiceImpl.java   |  8     ----
 .../java/util/ServiceUtil.java    |  1  
 src/main/resources/application.yml            | 20               ------
 .../test/SystemTest.java |  6    ---
 4 files changed, 22 insertions( ), 13 deletions(-)

This is from the man git-stash:

show [-u|--include-untracked|--only-untracked] [] [] Show the changes recorded in the stash entry as a diff between the stashed contents and the commit back when the stash entry was first created.

CodePudding user response:

TL;DR

You see four stashed files because Git really has "stashed" four files. This abuses the word "stash" rather badly, but the four stashed files are the three you had already staged-for-commit plus the one more than git stash push -- <pathspec> staged for commit into the working-tree commit that git stash push makes.

Long

The git stash documentation is, in my opinion, somewhat lacking. It's particularly bad for your case. The documentation is better now than it was 15 years ago, but it's still not great. (Unfortunately, fixing it is hard.)

Fundamentally, git stash is about making two, or sometimes three, commits. I like to refer to these as the i, w, and (optional) u commits. The i commit saves the index state, the w commit saves the working tree state, and the u commit, if it exists, saves some or all untracked files.

These three commits are tied together so that a single commit hash ID can locate all three of them (or the two, for the two-commit case). Diagrammatically, we can draw these three commits like this:

...--o--o--@   <-- current-branch (HEAD)
           |\
           i-w   <-- refs/stash
            /
           u

That is, the refs/stash ref (which is not a branch name) will contain the hash ID of the w commit, when all is said and done. The w commit has the form of a merge commit because it has two or three parents: the first parent of w is @, the current commit; the second parent of w is i, the index commit; and the third parent if it exists is u, the untracked-files commit.

Now, the index, as is so clearly explained

  • Related