views:

9391

answers:

9

Is it possible to undo the changes caused by the following:

git reset --hard HEAD~1

?

If so, how?

Thanks.

A: 

According to the Git Documentation, that will undo the commits permanently. I don't believe it's possible to undo the changes.

Jeremy Privett
A: 

From the Git documentation:

--mixed

Resets the index but not the working tree (i.e., the changed files are preserved ut not marked for commit) and reports what has not been updated. This is the default ction.

--soft

Does not touch the index file nor the working tree at all, but requires them to be in a good order. This leaves all your changed files "Changes to be committed", as git-status would put it.

--hard

Matches the working tree and index to that of the tree being switched to. Any changes to tracked files in the working tree since are lost.

So yea, sorry bud. Using --hard is generally not what you want to do unless you WANT to lose any and all changes. I've found that generally I want to use --mixed, leaving the working files around.

codemac
+1  A: 

If you had it pushed to another repo, then you might be able to get it back.

(I use hg, so terminology might be wrong).

Matthew Schinckel
+15  A: 

What you want to do is to specify the sha1 of the commit you want to restore to. You can get the sha1 by examining the reflog (git reflog) and then doing

git reset --hard <sha1 of desired commit>

But don't wait too long... after a few weeks git will eventually see that commit as unreferenced and delete all the blobs.

Pat Notz
+85  A: 

Pat Notz is correct. You can get the commit back so long as it's been within a few days. git only garbage collects after about a month or so unless you explicitly tell it to remove newer blobs.

$ git init
Initialized empty Git repository in .git/

$ echo "testing reset" > file1
$ git add file1
$ git commit -m 'added file1'
Created initial commit 1a75c1d: added file1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file1

$ echo "added new file" > file2
$ git add file2
$ git commit -m 'added file2'
Created commit f6e5064: added file2
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 file2

$ git reset --hard HEAD^
HEAD is now at 1a75c1d... added file1

$ cat file2
cat: file2: No such file or directory

$ git reflog
1a75c1d... HEAD@{0}: reset --hard HEAD^: updating HEAD
f6e5064... HEAD@{1}: commit: added file2

$ git reset --hard f6e5064
HEAD is now at f6e5064... added file2

$ cat file2
added new file

You can see in the example that the file2 was removed as a result of the hard reset, but was put back in place when I reset via the reflog.

Brian Riehman
I've removed the prompt string to improve readability. Fill free to rollback.
J.F. Sebastian
this post just saved me a bunch of time, thanks
anthony
You can use "git reset --hard HEAD@{1}", no need for using SHA1. In most cases it should be enough to use "git reset --hard ORIG_HEAD".
Jakub Narębski
Omg I just about died when I realized what I'd done. You, my friend, are amazing.
Stefan Mai
`git log -g` can be a little bit nicer way to view the reflog than `git reflog`.
Dan Moulding
+9  A: 

It is possible to recover it if Git hasn't garbage collected yet.

Get an overview of dangling commits with fsck:

   $ git fsck --lost-found
   dangling commit b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf

Recover the dangling commit with rebase:

$ git rebase b72e67a9bb3f1fc1b64528bcce031af4f0d6fcbf
sverrejoh
+4  A: 

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.

Jörg W Mittag
Another explanation that I think would be clearer: HEAD~1 means go to "parent of HEAD," while HEAD@{1} go to "go back one step in HEAD's history"
kizzx2
The problem is that the term "history" is really overloaded in VCSs. Yet another way to express is would be that ~ goes backwards in *commit history*, whereas @ goes backwards in *chronological or temporal history*. But none of the three versions is particularly good.
Jörg W Mittag
+9  A: 

I have written a complete guide to recovering any lost commit with git. It even has illustrations :-)

Check it out

webmat
A: 

Hi, what if I just pressed "git reset" by accident? How do I undo it? Thanks,

Ricardo
typing "git reset" on it's own will do nothing except unstage files in the index.
Pod