A stash consists of two (or sometimes three) commits. These commits are not on a branch, but rather are found through the special stash
reference (refs/stash
) and its reflog (stash@{n}
, for any integer n, is a reflog name). These two (or three) commits hold the index/staging-area state, the work-tree state, and—if the third commit is present—the untracked files or the extra "all" files (from git stash save -u
or git stash save -a
). I like to refer to these as the i
, w
, and u
commits of a "stash bag", since if you draw these two (or three) commits as part of a commit-graph drawing, they look like a little bag hanging off a commit.
The git stash show
command runs git diff
to compare the w
commit to its parent. What you need is to compare the i
commit (to i
's or w
's parent, marked *
in the diagram below) instead. There is no flag to git stash show
to do this, but you can make use of the stash-bag's structure:
- The
stash
or stash@{n}
reference points directly to to the w
commit.
- The first parent of the
w
commit is the commit that was HEAD
when the stash was saved.
- The
i
commit is the second parent of the w
commit. (This means that the w
commit is a merge commit; but do not try to use it as a merge!) The i
commit has a single parent, which is the same parent as w
's first parent.
- If the
u
commit exists, it is the third parent of w
, and it is itself a root commit (has no parent).
I find that the Unicode arrow characters do not display properly on all viewers so this diagram has the arrows drawn a bit larger:
...<-- o <-- o <-- * <-- o <-- o <-- branch
^
|\
| \
i<-w <-- stash@{3}
In this diagram, commit *
is the commit that was the HEAD
commit when this stash was saved (but since then, there have been two more commits added to branch
).
Git has some special syntax for going from any specific commit to its parents, as described in the gitrevisions
documentation, so you can get a diff comparing commit w
to commit *
:
git diff stash@{3} stash@{3}^
This is what git stash show
does: stash@{3}
names commit w
and stash@{3}^
names its parent, which is commit *
. But what you want is to compare commit i
to commit *
:
git diff stash@{3}^2 stash@{3}^
Note that you can also compare i
and w
, if you like, by naming stash@{3}^2
(w
's second parent = i
) and stash@{3}
(w
itself), in that order.
(As a shortcut, you can use git show
on the i
commit, since git show
diffs a commit against its parent(s). Note that using git show
on w
is less useful: w
has two parents, so git show
produces a combined diff, which is reasonable for regular merge commits, but rarely very useful for these w
commits, since they are not normal merge commits.)