Depending on the state your repository was in when you ran the command, the effects of git reset --hard can range from trivial to undo, to basically impossible.
Below I have listed a range of different possible scenarios, and how you might recover from them.
All my changes were committed, but now the commits are gone!
This situation usually occurs when you run git reset with an argument, as in git reset --hard HEAD~. Don't worry, this is easy to recover from!
If you just ran git reset and haven't done anything else since, you can get back to where you were with this one-liner:
git reset --hard @{1}
This resets your current branch whatever state it was in before the last time it was modified (in your case, the most recent modification to the branch would be the hard reset you are trying to undo).
If, however, you have made other modifications to your branch since the reset, the one-liner above won't work. Instead, you should run git reflog<branchname> to see a list of all recent changes made to your branch (including resets). That list will look something like this:
Find the operation in this list that you want to "undo". In the example above, it would be the first line, the one that says "reset: moving to HEAD~". Then copy the representation of the commit before (below) that operation. In our case, that would be master@{1} (or 3ae5027, they both represent the same commit), and run git reset --hard <commit> to reset your current branch back to that commit.
I staged my changes with git add, but never committed. Now my changes are gone!
This is a bit trickier to recover from. git does have copies of the files you added, but since these copies were never tied to any particular commit you can't restore the changes all at once. Instead, you have to locate the individual files in git's database and restore them manually. You can do this using git fsck.
I had changes to files in my working directory that I never staged with git add, and never committed. Now my changes are gone!
Uh oh. I hate to tell you this, but you're probably out of luck. git doesn't store changes that you don't add or commit to it, and according to the documentation for git reset:
--hard
Resets the index and working tree. Any changes to tracked files in the working tree since <commit> are discarded.
It's possible that you might be able to recover your changes with some sort of disk recovery utility or a professional data recovery service, but at this point that's probably more trouble than it's worth.
I know this is an old thread... but as many people are searching for ways to undo stuff in Git, I still think it may be a good idea to continue giving tips here.
When you do a "git add" or move anything from the top left to the bottom left in git gui the content of the file is stored in a blob and the file content is possible to recover from that blob.
So it is possible to recover a file even if it was not committed but it has to have been added.
git init
echo hello >> test.txt
git add test.txt
Now the blob is created but it is referenced by the index so it will no be listed with git fsck until we reset. So we reset...
git reset --hard
git fsck
you will get a dangling blob ce013625030ba8dba906f756967f9e9ca394464a
git show ce01362
will give you the file content "hello" back
To find unreferenced commits I found a tip somewhere suggesting this.
gitk --all $(git log -g --pretty=format:%h)
I have it as a tool in git gui and it is very handy.
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.
In most cases, yes.
Depending on the state your repository was in when you ran the command, the effects of
git reset --hard
can range from trivial to undo, to basically impossible.Below I have listed a range of different possible scenarios, and how you might recover from them.
All my changes were committed, but now the commits are gone!
This situation usually occurs when you run
git reset
with an argument, as ingit reset --hard HEAD~
. Don't worry, this is easy to recover from!If you just ran
git reset
and haven't done anything else since, you can get back to where you were with this one-liner:This resets your current branch whatever state it was in before the last time it was modified (in your case, the most recent modification to the branch would be the hard reset you are trying to undo).
If, however, you have made other modifications to your branch since the reset, the one-liner above won't work. Instead, you should run
git reflog
<branchname>
to see a list of all recent changes made to your branch (including resets). That list will look something like this:Find the operation in this list that you want to "undo". In the example above, it would be the first line, the one that says "reset: moving to HEAD~". Then copy the representation of the commit before (below) that operation. In our case, that would be
master@{1}
(or3ae5027
, they both represent the same commit), and rungit reset --hard <commit>
to reset your current branch back to that commit.I staged my changes with
git add
, but never committed. Now my changes are gone!This is a bit trickier to recover from. git does have copies of the files you added, but since these copies were never tied to any particular commit you can't restore the changes all at once. Instead, you have to locate the individual files in git's database and restore them manually. You can do this using
git fsck
.For details on this, see Undo git reset --hard with uncommitted files in the staging area.
I had changes to files in my working directory that I never staged with
git add
, and never committed. Now my changes are gone!Uh oh. I hate to tell you this, but you're probably out of luck. git doesn't store changes that you don't add or commit to it, and according to the documentation for
git reset
:It's possible that you might be able to recover your changes with some sort of disk recovery utility or a professional data recovery service, but at this point that's probably more trouble than it's worth.
If you're really lucky, like I was, you can go back into your text editor and hit 'undo'.
I know that's not really a proper answer, but it saved me half a day's work so hopefully it'll do the same for someone else!
Made a tiny script to make it slightly easier to find the commit one is looking for:
git fsck --lost-found | grep commit | cut -d ' ' -f 3 | xargs -i git show \{\} | egrep '^commit |Date:'
Yes, it can be made considerably prettier with awk or something like it, but it's simple and I just needed it. Might save someone else 30 seconds.
I know this is an old thread... but as many people are searching for ways to undo stuff in Git, I still think it may be a good idea to continue giving tips here.
When you do a "git add" or move anything from the top left to the bottom left in git gui the content of the file is stored in a blob and the file content is possible to recover from that blob.
So it is possible to recover a file even if it was not committed but it has to have been added.
Now the blob is created but it is referenced by the index so it will no be listed with git fsck until we reset. So we reset...
you will get a dangling blob ce013625030ba8dba906f756967f9e9ca394464a
will give you the file content "hello" back
To find unreferenced commits I found a tip somewhere suggesting this.
I have it as a tool in git gui and it is very handy.
If you have not yet garbage collected your repository (e.g. using
git repack -d
orgit 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, yourgit 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~
, likegit 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:
So,
HEAD~1
means "go to the commit before the commit that HEAD currently points at", whileHEAD@{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.
Example of IRL case:
$ git fsck --lost-found
$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a
$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a