In git, is there a way to show untracked stashed files without applying the stash?

Untracked files are stored in the third parent of a stash commit. (This isn't actually documented, but is pretty obvious from The commit which introduced the -u feature, 787513..., and the way the rest of the documentation for git-stash phrases things... or just by doing git log --graph stash@{0})

You can view just the "untracked" portion of the stash via:

git show stash@{0}^3

or, just the "untracked" tree itself, via:

git show stash@{0}^3:

or, a particular "untracked" file in the tree, via:

git show stash@{0}^3:<path/to/file>

There is, unfortunately, no good way to get a summary of the differences between all staged+unstaged+untracked vs "current" state. ie: git show stash@{0} cannot be made to include the untracked files. This is because the tree object of the stash commit itself, referred to as stash@{0}:, does not include any changes from the third, "unstaged" parent.

This is due to the way stashes are re-applied: tracked files can be easily applied as patches, whereas untracked files can only be applied, in theory, as "whole files".


You can list all stash commits with the following command:

git rev-list -g stash

Since stashes are represented as a 3-way merge commit of HEAD, the index, and a parent-less "root" commit of untracked files, untracked file stashes can be listed by piping the above output into the following:

git rev-list -g stash | git rev-list --stdin --max-parents=0

Useful applications of the above:

Show only untracked, stashed files

git rev-list -g stash | git rev-list --stdin --max-parents=0 | xargs git show --stat

Of course, remove the --stat to see the contents of the files.

Find a specific file

git rev-list -g stash | xargs -n1 git ls-tree -r | sort -u | grep <pattern>

Grep untracked files

git rev-list -g stash | git rev-list --stdin --max-parents=0 | xargs git grep <pattern>

List all contents of all stashes

git rev-list -g stash | git rev-list --stdin | xargs git show --stat

To list the untracked files in the stash:

git ls-tree -r stash@{0}^3 --name-only

To show a complete diff of all untracked files (with content):

git show stash@{0}^3

These commands read the last (most recent) stash. For earlier stashes, increment the number behind the "stash@", for example stash@{2} for the second from the last stash.

The reason this works is that git stash creates a merge commit for each stash, which can be referenced as stash@{0}, stash@{1} etc. The first parent of this commit is the HEAD at the time of the stash, the second parent contains the changes to tracked files, and the third (which may not exist) the changes to untracked files.

This is partly explained in the manpage under "Discussion".

Tags:

Git

Git Stash