29

Not quite sure what's happened, but git stash seems to be in a bad place.

% git stash list
stash@{0}: filter-branch: rewrite
stash@{1}: filter-branch: rewrite
stash@{2}: On mysolr: start mysolr stuff

Is OK, and git show stash@{0} works fine. But:

% git stash drop
'' is not a stash reference
% git stash pop
'' is not a stash reference
% git stash drop stash@{0}
'stash@{0}' is not a stash reference

I've used git stash plenty in the past and not come across this. I had recently rewritten history to remove a file from history before publishing to github. The command I ran then was

git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch FILENAME' \
  --prune-empty --tag-name-filter cat -- --all

Any ideas how to fix the stash?

Alexis King
  • 43,109
  • 15
  • 131
  • 205
Hamish Downer
  • 16,603
  • 16
  • 90
  • 84

3 Answers3

25

I think filter-branch has broken your stashes. If the argument to git stash does not sufficiently resemble a stash bag, you get that not a stash reference complaint.

Note that git show stashref uses plain old git show, which does not require that a commit given as an argument resemble a stash. If git stash show fails the same way as the other git stash commands, or if manual examination of the stash in question shows that it's no longer a two- or three-parent merge commit, then this is in fact the case.

It was likely the --prune-empty that did it here. If you had not added anything at the time of the stash, the index commits would be empty. In general it's probably wiser to avoid filtering stash refs.

You can try two different approaches:

  • Recover the original stash SHA-1(s) from refs/original/ (where filter-branch left them) and/or reflogs; use those to rebuild refs/stash and/or the stash reflogs, or use them directly and then clobber the stash ref and its reflog.
  • Use just the remaining work-tree commits in the rewritten stashes. All you really need, since the index commits were empty, is that one work-tree commit. You can get a patch using the git show command you've already run.

(For a bit more on stash and stash bags, including the three-parent form used with --all or --untracked, see How to recover from “git stash save --all”?.)

Assuming you have gotten your contents back and wish to wipe out the stash reference entirely, this will do it. Note that this is the "nuke it from orbit" option—don't do it until you're sure you're ready:

git update-ref -d refs/stash
Community
  • 1
  • 1
torek
  • 448,244
  • 59
  • 642
  • 775
  • 2
    Thanks for this. I managed to get commit ids from `git reflog stash` and then I managed to `git stash apply stash@{2}`. Once I committed that I used the nuke from orbit option and I'm happy again. Thank you. – Hamish Downer Feb 28 '14 at 10:41
  • 1
    `git update-ref -d refs/stash` is exactly what I needed, thanks! – Chin Dec 14 '14 at 14:21
  • 1
    A much simpler `git stash clear` worked for me, even if I had the same error. – o0'. Jul 15 '15 at 09:51
  • 2
    Not too surprising; `git stash clear` should do the equivalent "nuke from orbit" thing. You lose all your old stashes either way... – torek Jul 15 '15 at 12:20
  • i found the stash commit from refs/original/ , and than just cherry picked on my branch :O dont know yet if that had any side effects , but code looks great :) – almaruf Sep 03 '15 at 09:58
  • @almaruf: if filter-branch pruned an empty one of the `i-w` pair, the other one should work fine as a cherry-pick. In general you should be able to `git apply` the original directly though. – torek Sep 03 '15 at 19:56
7

You don’t have to nuke all of your stashes. You can delete just the broken ones manually using git reflog. In your case:

git reflog delete --rewrite stash@{1}
git reflog delete --rewrite stash@{0}

(I put these in reverse order here because every deletion decreases the numbering of the following entries. In practice, don’t bother doing the math mentally, just do git stash list after every deletion to get an updated list and pick another remaining broken entry from that.)

Aristotle Pagaltzis
  • 112,955
  • 23
  • 98
  • 97
3

all above answers don't work for me, the below command work, it can delete one stash which you want. I hope it will work for you.

git stash list

//--- apply target stash
git stash apply refs/stash@{n} 

//---- delete target stash
git stash drop --index n
// or
git stash drop refs/stash@{n}
Zero.D.Saber
  • 371
  • 2
  • 6
  • I had an issue with being unable to pop stash, using refs/stash@{n} instead of stash@{n} helped – Eduard Mar 29 '20 at 12:10