Search code examples
gitgit-stashgit-filter-branch

Is it possible to retrieve a stash after running git filter-branch?


I ran git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE' to fix the commit dates after I rebased. However, I didn't know that my stash would be lost.

I've tried the following:

  • running git reflog --all, checking out the earliest commit that it showed (c9e4e26 HEAD@{37}: rebase (start): checkout e3536c9^) and running git stash list
  • running git fsck, checking out every unreachable/dangling blob and commit and running git stash list

Is there a way to retrieve that stash?


Solution

  • Your existing stash is not exactly lost. Well, it's hard to find, so in that sense, it's "lost". What has happened is that git filter-branch has damaged it. What git stash does is make two, or sometimes three, commits, with the key one looking like a merge commit. Most Git commands treat it as a merge. That includes git filter-branch. This can damage the stash-group since git stash itself demands these oddly-formed clumps of commits—they look like merges, but can't be treated as merges.

    Since nothing in Git can actually change any existing commits, though, what filter-branch did was copy the stash to new and "improved" (but actually, damaged) commits. The name stash now refers to these new and unimproved (deproved? depraved?) commits.

    If you have not clobbered all the refs/original space:

    git update-ref refs/stash refs/original/refs/stash
    

    will restore refs/stash to the way it was before the filter-branch operation. (This assumes a single pass of filter-branch; each additional pass would require -f or deleting the previous refs/original/ space, either of which destroys the value you wanted to get back here.)

    If you were using the stash "stack", that's in the reflog for refs/stash itself. It should be undamaged except that the last entry, stash@{1}, should hold the old value of refs/stash from before the filter-branch operation. That provides another means of recovery, if you have clobbered the refs/original names. If you ran multiple passes of git filter-branch, you may need a higher number than 1 here.

    If all else fails, the git fsck method described in the git stash documentation, near the end under Recovering stash entries that were cleared/dropped erroneously, is available, but painful.

    (Incidentally—not that this helps at this point—this is one of many reasons I recommend avoiding git stash most of the time. Since all it does is make commits, just make normal commits. The rest of Git will deal nicely with these normal commits.)