Is it possible to undo the changes caused by the following command? If so, how?
git reset --hard HEAD~1
If you have not yet garbage collected your repository (e.g. using git repack -d
or git gc
, but note that garbage collection can also happen automatically), then your commit is still there – it's just no longer reachable through the HEAD.
You can try to find your commit by looking through the output of git fsck --lost-found
.
Newer versions of Git have something called the "reflog", which is a log of all changes that are made to the refs (as opposed to changes that are made to the repository contents). So, for example, every time you switch your HEAD (i.e. every time you do a git checkout
to switch branches) that will be logged. And, of course, your git reset
also manipulated the HEAD, so it was also logged. You can access older states of your refs in a similar way that you can access older states of your repository, by using an @
sign instead of a ~
, like git reset HEAD@{1}
.
It took me a while to understand what the difference is between HEAD@{1} and HEAD~1, so here is a little explanation:
git init
git commit --allow-empty -mOne
git commit --allow-empty -mTwo
git checkout -b anotherbranch
git commit --allow-empty -mThree
git checkout master # This changes the HEAD, but not the repository contents
git show HEAD~1 # => One
git show HEAD@{1} # => Three
git reflog
So, HEAD~1
means "go to the commit before the commit that HEAD currently points at", while HEAD@{1}
means "go to the commit that HEAD pointed at before it pointed at where it currently points at".
That will easily allow you to find your lost commit and recover it.