DEV Community

Cover image for Recover a lost Git stash in two steps
Mehdi M.
Mehdi M.

Posted on • Updated on

Recover a lost Git stash in two steps

Sometimes you end up stashing code, then at some point those stashes get cleaned. And one day, you may encounter the situation I faced this week:

Fine, this code is merged, so let’s delete the related stashes. Done! And… hey… wasn’t this part of the feature supposed to be in the codebase? Is the stash I just deleted lost forever?

Fortunately, I managed to recover lost stashes. I’m not a Git expert, but here’s what worked for me after going through various readings (including some Stack Overflow answers).

Here’s the two-steps recovery procedure.

1. List lost stashes

Let’s run this command for a project where all stashes were trashed:

git fsck --unreachable | grep commit | cut -d ' ' -f3 | xargs git log --merges --no-walk
Enter fullscreen mode Exit fullscreen mode

It returns a list of lost stashes, ordered by date.
Ho, 3 lost stashes!

  • To quit the list of stashes, press the Q key.
  • To navigate in a long stashes list, use up and down arrows.
  • For Windows user, maybe johnwait’s comment will help you during the battle.

2. Send a lost stash back where it comes from

Let’s use the commit hash of the second stash:

git update-ref refs/stash 4b3fc45c94caadcc87d783064624585c194f4be8 -m "My recovered stash"
Enter fullscreen mode Exit fullscreen mode

And that’s it! You’ll find your stash as usual, using git stash list or by having a look in your favorite Git client.


1. I still can’t see my recovered stash

Retry using the --create-reflog parameter (thanks studoggithub):

git update-ref refs/stash 4b3fc45c94caadcc87d783064624585c194f4be8 --create-reflog -m "My recovered stash"
Enter fullscreen mode Exit fullscreen mode

2. My Git isn’t in English

If your Git isn’t in English, you’ll have to run alias git='LANG=en_GB git' each time you want to recover a set of stashes (thanks mathieuschopfer).

Some advices

Commit messages are healthy

Always use a commit message using git stash save -m "My commit message": without message, the only informations helping to identify a stash are its timestamp and the branch it was saved from, which may not be enough compared to a strong explicit name.

Commit messages also help Git clients:

  • GitUp, the Git client I use, completely fails at showing unnamed stashes. That’s probably why you can’t create a stash in GitUp without giving it a name, which is great!
  • The well-known SourceTree succeeds at showing unnamed stashes, but as you can guess, the list isn’t friendly to browse: Unnamed stashes in SourceTree

Yes, git stash apply > git stash pop

Unlike git stash pop, git stash apply does not remove the stash from the list of stashes, which can avoid some loss.

Branches > stashes

Finally, I’d recommend to avoid git stash. Instead, try to use a branch. This seems obvious but it only comes to me as I was finding a way to recover a stash: maybe I should use temporary branches instead of stashes. Using the Git Flow method at work, this could have come to my mind before encountering a painful experience.

If you have any stash hint or experience that you want to share, comments are welcome.

Discussion (21)

johnwait profile image

On Windows, in a good old command window (your usual cmd.exe), step 1. could be translated to:

for /f "tokens=3" %a in ('git fsck --unreachable ^| find "commit"') do @git log --merges --no-walk %a

If your Git speaks français, and you're one to choose the more complicated path, you could use something like:

for /f "tokens=1,2,3,4" %a in ('git fsck --unreachable ^| find "commit"') do @if "%c"=="inatteignable" (@git log --merges --no-walk %d) else (@git log --merges --no-walk %c)

or, really, keep it simple with alias git='LANG=en_GB git' instead.


For PowerShell aficionados, here's a command that should work regardless of your Git's locale (well, as long as a commit is still referred to as commit):

(git fsck --unreachable | Select-String "commit") -split '\s+' |
Select-String -pattern "^[0-9a-fA-F]{40}$" |
ForEach-Object { git log --merges --no-walk $_ }

(Really useful post btw!)

meduzen profile image
Mehdi M. Author

Thanks! A link to your comment has been added to the article.

studoggithub profile image

This almost worked for me. I found that the update-ref command created the stash ref correctly but git stash list still did not show anything.

I added the --create-reflog parameter on a second try, and then things worked.

git version 2.22.0 on Ubuntu 18.04

meduzen profile image
Mehdi M. Author

Thanks! I don’t have this issue in Git 2.20.1 (macOS 10.14.16) but added a note in the article.

mathieuschopfer profile image
Mathieu Schopfer

This may fail if you don't use git in English. To quickly fix it:
alias git='LANG=en_GB git'

meduzen profile image
Mehdi M. Author


What is different when you use Git in another language? I didn't know it existed.

mathieuschopfer profile image
Mathieu Schopfer

In French (I cannot tell for other languages), commit seems to have been translated by objet commit.

git fsck --unreachable returns
objet commit inatteignable 977ee79082f2e1179c3d2156f8f0e6c66682ea2d
instead of
unreachable commit 977ee79082f2e1179c3d2156f8f0e6c66682ea2d

Thus, cut -d ' ' -f3 returns inatteignable instead of the commit tag.

Thread Thread
meduzen profile image
Mehdi M. Author

Ha oui, carrément. :D

Gonna update the article. Thanks a lot!

xrzhuang profile image

this saved my life

rjean99 profile image

Mine too!

rstrausslogyx profile image
Randy Strauss • Edited on

I tried both commands (git 2.21.1):
git update-ref refs/stash b68ecd901f90158d7c41edf2d2d3868e3599ca29 -m "My recovered stash"
git update-ref refs/stash b68ecd901f90158d7c41edf2d2d3868e3599ca29 --create-reflog -m "My recovered stash"

both give usage (below, removing the '-d' and '-stdin' stuff:
usage: git update-ref [] []
-m reason of the update
--no-deref update not the one it points to
-z stdin has NUL-terminated arguments
--create-reflog create a reflog

Is refs/stash the refname? Or is the sha the refname?
What's the "new-val" and "old-val" - values of what?

This page seems to help:

git log --graph --oneline --decorate ( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
and then
git stash apply YOUR_WIP_COMMIT_HASH

Thanks for the hope, and being a stepping stone to most of what I needed. :?)

(4 of my files weren't stashed, though. It turns out NASA's backup utility has been silently failing for months, so I've lost a few days work. Under-staffed projects are a pain. Luckily, the project and my attitude don't really matter...)

mansehej profile image
Mansehej Singh

This was extremely helpful. Thank you for sharing your knowledge!

moopet profile image
Ben Sinclair

It never occurred to me you could do this!

simesy profile image
Simon Hobbs

Thanks, saved me some work!

pedroverceze profile image
Pedro Verceze

It is good to know, after the fist command, pick your hash and use:

$ git stash apply e3cf5932f4816f5b0022190ce6b871f51cf882de

It worked for me

shankarshastri profile image

Thanks, it saved my day !!

daniaaalarshad profile image

Thanks a lot lot lot lot lot lot. You saved my time and I recovered 70 - 80 percent of my work :)

zeke profile image
Zeke Hernandez

saved my butt! thanks!

abelgriffen profile image
Abel Griffen

Thanks for the solution. It worked for me.

mahipalabhijith profile image
Abhijith Mahipal M

Thanks, i got my changes back while my rebase autostash failed

ericus123 profile image

Thanks a lot. This saved me .