How can I undo git reset --hard HEAD~1?
Asked Answered
P

20

1637

Is it possible to undo the changes caused by the following command? If so, how?

git reset --hard HEAD~1
Pia answered 7/8, 2008 at 23:22 Comment(12)
I have written a complete guide to recovering any lost commit with git. It even has illustrations :-) [Check it out][fixLink] [fixLink]: programblings.com/2008/06/07/…Folberth
--hard discards uncommitted changes. Since these aren't tracked by git, there's no way to restore them through git.Threephase
stackoverflow.com/questions/34519665/…Restorative
This is a great article to assist you with recovering your files.Pyroconductivity
This is a great resource straight from Github: How to undo (almost) anything with GitCrusado
Don't forget your terminal line buffer if you happen to have run git diff recently. This saved me just now.Pianette
Check this out: youtube.com/watch?v=MijDnC4mz9w. It really saved my situation!!Approximal
Maybe debatable but I inclined to consider this question to be a duplicate of https://mcmap.net/q/22360/-how-do-i-undo-39-git-reset-39.Abdu
When you are using an IDE like PHPStorm you can use local history to revert it.Maxama
@Threephase The statement "--hard discards uncommitted changes" isn't correct without qualification. Staged, uncommitted changes are known to git and can be identified as dangling blobs, as mentioned by some of the answers here.Neilla
For those unlucky persons who didn't stage or commit the changes and lost all their local changes. You can still recover if you have those modified files open in editor. just undo the changes in editor.Cavort
Happened to me to, lesson learned: DON'T USE --hard. Instead, start with just git reset - and if you get an error, it will remind you of what --hard actually means...Bini
B
2420

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.

Brandnew answered 22/8, 2008 at 4:36 Comment(11)
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".Edwinaedwine
git log -g can be a little bit nicer way to view the reflog than git reflog.Impost
There's one very important caveat with this.. and thats the "--hard" part. --hard blows away your local uncommitted changes. And you cant get them back like this (as they've not been committed anywhere). I believe there is nothing you can do about that :(Conoscenti
^ Just so you know you can stash your local changes before doing a reset --hard, and then just pop them and you lose nothing! Gotta love git.Thermel
I prefer git reflog over git log -g simply because you get all the information on one line with sha1, HEAD info and commit messages all lined up. Much easier to read.Saxony
If you haven't committed local changes and use git reset --hard HEAD the only way that you can get the changes back is if you still have an editor open and copy / paste the changes to new files.Wordage
@Thermel Actually, you can't stash if you did git add your changes, I think. In those cases, git reset --hard would be a solution. If you have another solution than git reset --hard, I would love to see it ;)Crescin
Recovering Lost Changes: If you accidentally lost uncommitted changes by git reset --hard, you can still recover lost changes from editor. Simply go to the file that lost changes and press ctrl-z to undo to state before hard reset. Very obvious way but sometimes it doesn't come to mind. Modern day editors also has log of all history of changes, from where you can get the changes.Trackman
I had uncommitted changes and did git reset --hard HEAD. I had intelliJ open at that time. I got the changes back from intelliJ local history. Lifesaver. Hope it helps someone.Nonagon
lifesaver. I was doing everything right committing and pushing as well. but seems I was behind from remote somewhere then I created a local branch from there later I realised the pushed were removed and commits were removed as well. only this showed me those last commits.Theola
This worked beautifully for me, however, "git reflog" surprisingly didn't show one of my recent fast-forward commits (that got lost with reset) and I needed "git reflog show --all"Hiphuggers
P
542

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.

Pleurodynia answered 9/8, 2008 at 5:30 Comment(1)
warning for myself a few minutes ago: this will reset all modifications. it won't touch the untracked files though.Wo
F
271

The answer is hidden in the detailed response above, you can simply do:

$> git reset --hard HEAD@{1}

(See the output of git reflog show)

Fanechka answered 26/2, 2011 at 15:13 Comment(3)
Note that this is not the solution if you've made any other repo changes since the reset. Definitely take a look at the reflog before running anything.Bree
Excellent for when you've realized that you just resetted a branch by mistake and starting to panic.Rosenkrantz
amazing solution. Just use the "git reflog" to see your commit you want to take back and do above solution.Starlin
M
182

As far as I know, --hard will discard uncommitted changes. Since these aren't tracked by git. But you can undo the discarded commit.

$ git reflog

will list:

b0d059c HEAD@{0}: reset: moving to HEAD~1
4bac331 HEAD@{1}: commit: added level introduction....
....

where 4bac331 is the discarded commit.

Now just move the head to that commit:

$ git reset --hard 4bac331
Medovich answered 2/4, 2015 at 8:57 Comment(0)
P
151

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
Paris answered 22/8, 2008 at 6:11 Comment(1)
A detailed explanation can be found here: medium.com/@CarrieGuss/…. Life saving stuff.Embowel
S
84

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!

Sleepy answered 13/1, 2012 at 0:48 Comment(8)
This is actually a very good tip, saved me a lot of times ;) And its way simpler than doing anything in git...Manslaughter
This is the only way to recover unstaged changes in files after the hard reset. Saved me too ;)Juliannejuliano
As an additional hint, some IDEs as eclipse also have the recent file history saved. That way, you might even be able to recover older changes after the editor was closed. That worked wonders for me.Splurge
This saved me today. Not major changes but still I was tired after lot of experimentation and made a thing worked until I messed up. I wonder if there is no "git" way of doing it! Reflog takes only to the commit, sad though. And I am using eclipse which doesn't save history if I close the IDE. But for a particular file, I opened that IDE and that was the major file to be done in my local changes. :PFilmdom
Nice, good suggestion, in the case of IntelliJ family (e.g. PhpStorm, WebStorm, RubyMine, PyCharm) you can right click a filename and choose "local history > show history" and also recover that way as well. Assuming the IDE was open and tracking local changes.Sashenka
Same here! I deleted the whole project without any commit at all by reset --hard and recovered whit the history of the main folder in WebStorm. Love it !Washburn
I don't see how this is a good answer. Imo this promotes laziness, just learn how to use git the right way and you won't have to be dependent on your text editor or Ctrl-ZIrma
To add to that, if you are using Visual Studio Code, there is a even more comprehensive file timeline stackoverflow.com/questions/45976869/…Parthenopaeus
L
67

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 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:

7c169bd master@{0}: reset: moving to HEAD~
3ae5027 master@{1}: commit: Changed file2
7c169bd master@{2}: commit: Some change
5eb37ca master@{3}: commit (initial): Initial commit

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.

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:

--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.

Lat answered 16/1, 2015 at 18:37 Comment(3)
One-liner worked for me, thank you, but I am just wondering what exactly that "@{1}" does..Syllabus
@StanB The documentation is here: git-scm.com/docs/git-rev-parse basically it refers to the first reflog entry on the current branch.Lat
Thanks for covering all the cases. I hadn't committed or added mine.Winfredwinfrey
T
45

Example of IRL case:

$ git fsck --lost-found

Checking object directories: 100% (256/256), done.
Checking objects: 100% (3/3), done.
dangling blob 025cab9725ccc00fbd7202da543f556c146cb119
dangling blob 84e9af799c2f5f08fb50874e5be7fb5cb7aa7c1b
dangling blob 85f4d1a289e094012819d9732f017c7805ee85b4
dangling blob 8f654d1cd425da7389d12c17dd2d88d318496d98
dangling blob 9183b84bbd292dcc238ca546dab896e073432933
dangling blob 1448ee51d0ea16f259371b32a557b60f908d15ee
dangling blob 95372cef6148d980ab1d7539ee6fbb44f5e87e22
dangling blob 9b3bf9fb1ee82c6d6d5ec9149e38fe53d4151fbd
dangling blob 2b21002ca449a9e30dbb87e535fbd4e65bac18f7
dangling blob 2fff2f8e4ea6408ac84a8560477aa00583002e66
dangling blob 333e76340b59a944456b4befd0e007c2e23ab37b
dangling blob b87163c8def315d40721e592f15c2192a33816bb
dangling blob c22aafb90358f6bf22577d1ae077ad89d9eea0a7
dangling blob c6ef78dd64c886e9c9895e2fc4556e69e4fbb133
dangling blob 4a71f9ff8262701171d42559a283c751fea6a201
dangling blob 6b762d368f44ddd441e5b8eae6a7b611335b49a2
dangling blob 724d23914b48443b19eada79c3eb1813c3c67fed
dangling blob 749ffc9a412e7584245af5106e78167b9480a27b
dangling commit f6ce1a403399772d4146d306d5763f3f5715cb5a    <- it's this one

$ git show f6ce1a403399772d4146d306d5763f3f5715cb5a

commit f6ce1a403399772d4146d306d5763f3f5715cb5a
Author: Stian Gudmundsen Høiland <[email protected]>
Date:   Wed Aug 15 08:41:30 2012 +0200

    *MY COMMIT MESSAGE IS DISPLAYED HERE*

diff --git a/Some.file b/Some.file
new file mode 100644
index 0000000..15baeba
--- /dev/null
+++ b/Some.file
*THE WHOLE COMMIT IS DISPLAYED HERE*

$ git rebase f6ce1a403399772d4146d306d5763f3f5715cb5a

First, rewinding head to replay your work on top of it...
Fast-forwarded master to f6ce1a403399772d4146d306d5763f3f5715cb5a.
Tug answered 15/8, 2012 at 7:1 Comment(2)
Dangling blob sounds like an AD&D monster!Tomi
Thanks @Stian Well explained! I would like to add for others finding this answer that if you have more than one "dangling" commit it's not sure that you want to do rebase on the last row :)Mavis
S
35

git reflog

  • Find your commit sha in the list then copy and paste it into this command:

git cherry-pick <the sha>

Subternatural answered 14/8, 2019 at 8:35 Comment(1)
git-cherry-pick - Apply the changes introduced by some existing commits. I think it's simple and very helpful in this contextGlovsky
S
27

If you are using a JetBrains IDE (anything IntelliJ based), you can recover even your uncommited changes via their "Local History" feature.

Right-click on your top-level directory in your file tree, find "Local History" in the context menu, and choose "Show History". This will open up a view where your recent edits can be found, and once you have found the revision you want to go back to, right click on it and click "Revert".

Spongin answered 16/8, 2019 at 22:17 Comment(2)
this feature is a life saver for those who are sloppy with git (like myself).Swanskin
you and jetbrains ide are my life saverFinitude
C
23

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.

Camden answered 27/8, 2008 at 3:45 Comment(3)
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"Crine
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.Larisa
@Crine (and Jorg) actually those 3 explanations, when taken together, help a lot - thxSpelling
R
20

Before answering lets add some background, explaining what is this HEAD.

First of all what is HEAD?

HEAD is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD at any given time. (excluding git worktree)

The content of HEAD is stored inside .git/HEAD and it contains the 40 bytes SHA-1 of the current commit.


detached HEAD

If you are not on the latest commit - meaning that HEAD is pointing to a prior commit in history its called detached HEAD.

enter image description here

On the command line it will look like this- SHA-1 instead of the branch name since the HEAD is not pointing to the the tip of the current branch

enter image description here


A few options on how to recover from a detached HEAD:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point you can create a branch and start to work from this point on.

# Checkout a given commit. 
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

You can always use the reflog as well.
git reflog will display any change which updated the HEAD and checking out the desired reflog entry will set the HEAD back to this commit.

Every time the HEAD is modified there will be a new entry in the reflog

git reflog
git checkout HEAD@{...}

This will get you back to your desired commit

enter image description here


git reset HEAD --hard <commit_id>

"Move" your head back to the desired commit.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • Note: (Since Git 2.7)
    you can also use the git rebase --no-autostash as well.


git revert <sha-1>

"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be commited while the original commit will remain in the history as well.

# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>

This schema illustrate which command does what.
As you can see there reset && checkout modify the HEAD.

enter image description here

Restorative answered 21/4, 2018 at 16:30 Comment(1)
It appears your git reset HEAD --hard <commit_id> example is taken from stackoverflow.com/questions/4114095/… - If that's the case, could you please edit in attribution?Fears
S
12

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.

Splurge answered 20/1, 2014 at 6:27 Comment(1)
+1. As mentioned in https://mcmap.net/q/12657/-stages-a-staged-file-in-git, git fsck --lost-found can help.Chalfant
L
6

I've just did a hard reset on wrong project. What saved my life was Eclipse's local history. IntelliJ Idea is said to have one, too, and so may your editor, it's worth checking:

  1. Eclipse help topic on Local History
  2. http://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F
Loverly answered 7/4, 2017 at 8:46 Comment(1)
Jetbrains CLion local history is superb and saved 2 hours work for me :)Stormproof
C
5

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.

Changeable answered 11/3, 2014 at 8:9 Comment(0)
J
5

Note: this answer is only valid if you use IDEs like IntelliJ

I recently faced a similar issue where I neither staged my changes nor committed them. There is an option of local history. I was able to revert changes from the local history of IntelliJ (ref).

Hope it helps someone.

Juliennejuliet answered 5/1, 2023 at 13:17 Comment(1)
This saved me. Worked using Android Studio. Was able to restore files accidentally deleted by Git by right clicking the nearest remaining folder and restoring from the IDE's history. Thanks!Tamartamara
M
4

My problem is almost similar. I have uncommitted files before I enter git reset --hard.

Thankfully. I managed to skip all these resources. After I noticed that I can just undo (ctrl-z for windows/linux cmd-shift-z for mac). 😊 I just want to add this to all of the answers above.

Note. Its not possible to undo unopened files.

Muimuir answered 13/3, 2020 at 10:53 Comment(4)
That's correct. Thanks for posting this, I could also recover my uncommitted changes this way.Dylane
In what application are you hitting ctrl-z and on what system?Washy
Thanks @Muimuir reading the answers above make it look as if I had no hope until I scroll down, your answer is as simple as it can be. I already lost hope of recovering uncommitted changes of recent 2 days work, and I totally didn't remember ctrl - z. I use vscode and this works perfect.Electrolysis
One more thing to note with undoing is that you would have to apply it to each file, also the file must be opened already in the case of vscodeElectrolysis
E
4

This has saved my life: https://medium.com/@CarrieGuss/how-to-recover-from-a-git-hard-reset-b830b5e3f60c

Basically you need to run:

for blob in $(git fsck --lost-found | awk ‘$2 == “blob” { print $3 }’); do git cat-file -p $blob > $blob.txt; done

Then manually going through the pain to re-organise your files to the correct structure.

Takeaway: Never use git reset --hard if you dont completely 100% understand how it works, best not to use it.

Embowel answered 20/3, 2020 at 2:54 Comment(1)
Someone put this in a repo (requires Python): github.com/pendashteh/git-recover-index Super useful, just ran it and searched through the files it created.Scarrow
S
4

git reflog and back to the last HEAD 6a56624 (HEAD -> master) HEAD@{0}: reset: moving to HEAD~3 1a9bf73 HEAD@{1}: commit: add changes in model generate binary

Skilling answered 28/8, 2020 at 19:40 Comment(0)
L
1

git reset --hard - you can use to revert one page and after that you can stash or pull everything from origin again

Ligature answered 24/6, 2021 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.