24

I wrote considerable code for a feature and stashed the changes in git.

After that I pushed several changes into the repository and did a git stash and apply multiple times (read over 100 times).

After almost 2 months I now want to retrieve the changes from git stash – but I cant find them no matter what.

Tried several git stash apply, git stash list, git stash list -p. Nothing works. I cant find those old stashed changes.

Wish I had taken a backup instead of trusting git to stash them...sigh...

Can anyone help?

10
  • possible duplicate of Git: how to unstash only certain files?
    – Luceos
    Commented Jan 15, 2014 at 6:49
  • 1
    A stash is held only in the repository which stored them originally - it is not copied with clone, push or pull. Are you running in the same repository? Did you ever check these changes in to HEAD?
    – Alex Brown
    Commented Jan 15, 2014 at 6:49
  • Did the output from git stash list show anything
    – Alex Brown
    Commented Jan 15, 2014 at 6:51
  • Git stash is not a reliable long term store for changes. It's generally better to commit and them move them aside into a separate branch.
    – Alex Brown
    Commented Jan 15, 2014 at 6:51
  • 2
    well, look through the stashes like git show 'stash@{0}', git show 'stash@{1}' etc to find your code. the single quotes are important, because { is a bash metacharacter.
    – Alex Brown
    Commented Jan 15, 2014 at 6:55

6 Answers 6

19

Try this:

git stash list -p | grep 'diff --git' | grep <your file name>

That will find your files in the list. It might take a while.

One thing: git stash apply does not discard a stash. After a successful apply, you should git stash drop so it dos not clutter your list. Personally, I apply the stash using git stash pop.

4
  • Nice - I like git stash list -p, I hadn't seen that before.
    – Alex Brown
    Commented Jan 15, 2014 at 7:11
  • Thank you for the help @Alex Siri. The stash pop tip helped
    – user811433
    Commented Jan 15, 2014 at 7:22
  • 1
    Isn't git stash pop evil? Commented Nov 21, 2016 at 8:14
  • 6
    The problem with this is that it simply shows the diff line 1 or more times, but you don't know what stash are they in. Commented Aug 26, 2019 at 9:58
17

To search inside the changes in your stashes, use git stash list with the pickaxe option -G (from git log):

git stash list -G regex_matching_some_added_or_removed_string
1
  • Thanks to @VonC for the tip about git log options. Commented Apr 6, 2018 at 14:12
7

This is the command I use. It helps me identify which stash is being referred to.

git stash list | while IFS=: read STASH ETC; do echo "$STASH: $ETC"; git diff --stat $STASH~..$STASH --; done | grep -e 'stash\|<partial_name_of_file_being_searched_for>'

I also use it in conjunction with an alias in my .bashrc file like so:

function gitsearch()
{
   searchCrit='stash\|'$1
   git stash list | while IFS=: read STASH ETC; do echo "$STASH: $ETC"; git diff --stat $STASH~..$STASH --; done | grep -e $searchCrit
}
alias githunt=gitsearch

The end result being that I can search my git stashes thus:

githunt LoanApplicationFee

and get the following results where I can quickly see that stash 45 has what I'm looking for:

enter image description here

6

Note: in case of stashed merged commit, a git stash list -p would return nothing.
That will change with Git 2.2 (Q4 2014) and commit 288c67c by Jeff King (peff):

stash: default listing to working-tree diff

When you list stashes, you can provide arbitrary git log options to change the display. However, adding just "-p" does nothing, because each stash is actually a merge commit.

This implementation detail is easy to forget, leading to confused users who think "-p" is not working. We can make this easier by defaulting to "--first-parent -m", which will show the diff against the working tree.
This omits the index portion of the stash entirely, but it's simple and it matches what "git stash show" provides.

People who are more clueful about stash's true form can use "--cc" to override the "-m", and the "--first-parent" will then do nothing.
For diffs, it only affects non-combined diffs, so "--cc" overrides it.
And for the traversal, we are walking the linear reflog anyway, so we do not even care about the parents.

5

If you have only a few stashes listed in git stash list then you can examine them one by one to see if they are the correct one:

git show 'stash@{0}'
git show 'stash@{1}'

etc.

If you have some code in many stashes, and can remember a string or keyword you typed in a file which (almost) uniquely identifies that code (I use DUNKIRK here), search for it using the following bash command.

for i in `git reflog --pretty=format:%H stash`; do git grep DUNKIRK $i; done

note that git grep searches the whole checkout - not just the changes.

Compare the answer from @siri, which searches for filenames which are changed in the stashes - which is another useful strategy.

Alternatively, to search only the diffs

 git reflog -p stash | less

and then search for your strings OR files, or just browse it. This might be large.

1
  • git reflog -p stash is probably the same logic as git stash list -p from @siri's answer.
    – Alex Brown
    Commented Jan 15, 2014 at 7:11
1

A combination of git commands from the above answers helped me with what I need. Posting my answer here as it might help others and because I cant accept any one single answer/comment

git stash list -p - showed me the list of stashes

git stash pop 'stash@{12}' - popped out the 12th stash which contains my code.

Not the answer you're looking for? Browse other questions tagged or ask your own question.