Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

git

git-stash

People also ask

How do I stash pop untracked files?

Stash Untracked Files Using “git add” You have to add the untracked files of the repository by using the “git add” command and run the “git stash” command to save the untracked file and clean the current directory for working by removing the untracked file from the repository folder.

Does stash work on untracked files?

In order to stash untracked files, add the “–include-untracked” option to your “git stash” initial command. Alternatively, you can simply use the “-u” which is equivalent to the untracked longer version.

How do I preview a git stash?

git stash show will show you the files that changed in your most recent stash. You can add the -p option to show the diff. Use git stash show -p stash@{0} to see a specific 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".


However, said untracked files don't show up at all with git stash show stash@{0}.

Note: since Git 2.11 (Q4 2016, 4 years after theis OP), you can reference stash with its index only

git stash show 0

There was a more recent bug due to git stash being rewritten in C, fixed in Git 2.22 (Q2 2019)

Is there any way to show untracked stashed files without applying the stash?

Why, yes, there is, with Git 2.32 (Q2 2021, 9 years after the OP).

"git stash show"(man) learned to optionally show untracked part of the stash.

See commit 0af760e, commit d3c7bf7 (03 Mar 2021) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit f5c73f6, 22 Mar 2021)

stash show: teach --include-untracked and --only-untracked

Signed-off-by: Denton Liu

Stash entries can be made with untracked files via git stash push --include-untracked(man).

However, because the untracked files are stored in the third parent of the stash entry and not the stash entry itself, running git stash show(man) does not include the untracked files as part of the diff.

With --include-untracked, untracked paths, which are recorded in the third-parent if it exists, are shown in addition to the paths that have modifications between the stash base and the working tree in the stash.

It is possible to manually craft a malformed stash entry where duplicate untracked files in the stash entry will mask tracked files.
We detect and error out in that case via a custom unpack_trees() callback: stash_worktree_untracked_merge().

Also, teach stash the --only-untracked option which only shows the untracked files of a stash entry.
This is similar to git show stash^3(man) but it is nice to provide a convenient abstraction for it so that users do not have to think about the underlying implementation.

git stash now includes in its man page:

'git stash' show [-u|--include-untracked|--only-untracked] [<diff-options>] [<stash>]

git stash now includes in its man page:

--no-include-untracked

When used with the push and save commands, all untracked files are also stashed and then cleaned up with git clean.

When used with the show command, show the untracked files in the stash entry as part of the diff.

--only-untracked

This option is only valid for the show command.
Show only the untracked files in the stash entry as part of the diff.


And you have a configuration to goes with those new options:

stash show: learn stash.showIncludeUntracked

Signed-off-by: Denton Liu

The previous commit teaches git stash show --include-untracked(man).
It may be desirable for a user to be able to always enable the --include-untracked behavior.
Teach the stash.showIncludeUntracked config option which allows users to do this in a similar manner to stash.showPatch.

git config now includes in its man page:

stash.showIncludeUntracked

If this is set to true, the git stash show command without an option will show the untracked files of a stash entry.

Defaults to false.

git stash now includes in its man page:

You can use stash.showIncludeUntracked, stash.showStat, and stash.showPatch config variables to change the default behavior.


With Git 2.32 (Q2 2021), the code to handle options recently added to "git stash show"(man) around untracked part of the stash segfaulted when these options were used on a stash entry that does not record untracked part.

See commit 1ff595d, commit aa2b05d (12 May 2021) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit a8a2491, 16 May 2021)

stash show: fix segfault with --{include,only}-untracked

Signed-off-by: Denton Liu

When git stash show --include-untracked(man) or git stash show --only-untracked(man) is run on a stash that doesn't include an untracked entry, a segfault occurs.

This happens because we do not check whether the untracked entry is actually present and just attempt to blindly dereference it.

Ensure that the untracked entry is present before actually attempting to dereference it.

And:

See commit af5cd44 (21 May 2021) by Denton Liu (Denton-L).
(Merged by Junio C Hamano -- gitster -- in commit 378c7c6, 22 May 2021)

stash show: use stash.showIncludeUntracked even when diff options given

Signed-off-by: Denton Liu

If options pertaining to how the diff is displayed is provided to git stash show(man), the command will ignore the stash.showIncludeUntracked configuration variable, defaulting to not showing any untracked files.
This is unintuitive behaviour since the format of the diff output and whether or not to display untracked files are orthogonal.

Use stash.showIncludeUntracked even when diff options are given.
Of course, this is still overridable via the command-line options.

Update the documentation to explicitly say which configuration variables will be overridden when a diff options are given.

git config now includes in its man page:

If this is set to true, the git stash show command will show the untracked files of a stash entry.

Defaults to false.

git stash now includes in its man page:

If no <diff-option> is provided, the default behavior will be given by the stash.showStat, and stash.showPatch config variables.

You can also use stash.showIncludeUntracked to set whether --include-untracked is enabled by default.


To see all the files in the stash (both tracked and untracked), I added this alias to my config:

showstash = "!if test -z $1; then set -- 0; fi; git show --stat stash@{$1} && git show --stat stash@{$1}^3 2>/dev/null || echo No untracked files -"

It takes a single argument of which stash you want to view. Note it will still present it in two back-to-back lists.

The if...fi section changes the bash argument $1 to 0 if none was passed.


A workaround: Staging files before stashing them will make git stash show -p work as expected.

git add .
git stash save

Note: This way gives the power adding interactive portions too, here is how.
Caution: Ensure you don't have previously staged work, or you won't be able to distinguish it.
This may be of use.