1. Overview
Commands like git stash and git stash pop are used to Shelve (stash) and restore changes in our working directory. In this tutorial, we’ll learn how to recover a dropped stash in Git.
2. Stashing the Changes in Working Directory
For our example, let’s say that we’ve forked and cloned a Git Repository. Now, let’s make some changes to the README.md file by simply adding a new line at the end and checking the status of our working directory:
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
From here, we can use the git stash command to shelve our changes temporarily.
$ git stash
Saved working directory and index state WIP on master: a8088442db Updated pom.xml
Now, if do a git status again, we will see that our working directory is clean.
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
3. Restoring Stashed Changes and Finding the Hash
Let’s see how we can restore the stashed changes and find the hash associated with the stash commit.
3.1. Restoring Stashed Changes into the Working Directory
We can bring the stashed changes back into our working directory like this:
$ git stash pop
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (59861637f7b599d87cb7a1ff003f1b0212e8908e)
As we can see in the last line git stash pop not only restores the stashed changes but also removes the reference to its associated commit.
3.2. Locating the Hash When the Terminal Is Open
If our terminal is still open, we can easily locate the hash generated after the execution of git stash pop. In our example, the hash, displayed in the last line is 59861637f7b599d87cb7a1ff003f1b0212e8908e.
3.3. Recovering the Hash After the Terminal Is Closed
Even if we have closed the terminal we can still find our hash in the following manner:
$ git fsck --no-reflog
Checking object directories: 100% (256/256), done.
Checking objects: 100% (302901/302901), done.
dangling commit 59861637f7b599d87cb7a1ff003f1b0212e8908e
The commit hash for the dropped stash is now visible to us.
4. Recovering the Dropped Stash
We would not normally need a stash entry once we’ve applied it. However, there may be a situation where we wish to go back to a stash entry after we’ve dropped it. For example, if using git reset –hard HEAD will throw away all the uncommitted changes from our working directory. In this situation, we may wish to recall some earlier stashed changes, even though they were dropped.
4.1. Use the Hash to Restore the Stash
Using the hash for a dangling commit, it’s still possible for us to recover those changes:
$ git stash apply 59861637f7b599d87cb7a1ff003f1b0212e8908e
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
We can see that our working directory is restored with the changes that were stashed earlier.
4.2. Finding All the Hash Commits
If we don’t have the hash readily available, we can find it:
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
Here, we combine our –no-reflog option with awk to filter out only the hash for us.
5. Conclusion
In this article, we saw how git stash works and how it drops an entry when we use it. Then we saw how we can still use a dropped entry when we know its hash, and how the hash of a stash commit can be found.