604

Is there any way to recover uncommitted changes to the working directory from a git reset --hard HEAD?

Peter Majeed
  • 5,269
  • 2
  • 30
  • 52
Jacob Lyles
  • 9,220
  • 7
  • 30
  • 29
  • 66
    I'd recommend unlearning `git reset`. You don't need that command and it's dangerous, so don't use it. To return branch to previous commit either `git rebase -i` and drop the commits you don't want or `git checkout` (detaches head) followed by `git branch -M` to move the branch tip. The first will refuse to run with local changes and the later will run only if locally modified files don't differ between the revisions. – Jan Hudec Apr 26 '11 at 09:10
  • @Jan Suppose you do a git add --patch, and then realize you have staged some hunks that you didn't intend to. How do you recover from that (ie, clear the staging area) without reset? – William Pursell Apr 27 '11 at 12:12
  • If you need to reset changes. it might be a good idea to use `git stash` – chrisjlee May 02 '11 at 17:37
  • 25
    @Jan I don't believe that. There are perfectly legitimate reasons to use reset. – spaaarky21 Feb 07 '13 at 16:53
  • 5
    @spaaarky21: Yes, there are. But `git reset --hard somewhere` is one of few really dangerous git commands. – Jan Hudec Feb 08 '13 at 13:01
  • 12
    @Jan I agree but it being dangerous doesn't mean you shouldn't use it. Just know what you are doing and be careful. :) – spaaarky21 Feb 08 '13 at 16:47
  • 3
    Not related to [Undoing a git reset --hard HEAD~1](http://stackoverflow.com/questions/5473/undoing-a-git-reset-hard-head1), because here the original poster is trying to recover uncommitted changes. –  Jul 21 '13 at 14:55
  • See also [Recovering added file after doing git reset --hard HEAD^](http://stackoverflow.com/q/1108853/456814). –  May 19 '14 at 03:38
  • See also [Accidentally reverted to master, lost uncommitted changes](http://stackoverflow.com/q/7147680/456814). –  May 19 '14 at 03:39
  • Actually sometimes I think it would be better if git developers would add option to temporary store everything unstaged/uncommited before git `reset --hard` to avoid such problems. – Predelnik Aug 05 '14 at 09:56
  • I also found myself in front of this problem several times, and the salvation came from using the Local History of my IDE, if yours has this feature. Definitely I should stop using this undoable command. – iulial Feb 15 '17 at 09:14
  • @Predelnik That's exactly what `git stash save` does. – William Pursell Jun 16 '17 at 02:19
  • @JanHudec People really should not be saying that you should use "git reset" when you want to go back to a previous commit, then! – Michael Sep 05 '17 at 18:45
  • @Michael, indeed. To go back to previous commit, you can say `git checkout -B master master^` (replace `master` with current branch name) and you won't risk losing uncommitted state. The mixing of two functions—undoing changes and moving branch tip—in `git reset` are unfortunate. Git normally provides pretty good safety net in the form of reflog, but reset is a glaring hole in it. – Jan Hudec Sep 06 '17 at 06:15
  • Sometimes it's dangerous to _not_ use `git reset --hard`. For instance, when pushing to a remote repo (especially a forced push), I always do a hard reset to the remote branch and then make any desired changes before pushing, in order to ensure that _only_ my desired changes go out. – Dane Powell Oct 18 '17 at 15:04
  • Just leaving this here, it can sounds dumb but I'm using VSCode and I haven't closed it after my failed `git reset --hard`. Fortunately VSCode was able to retrieve me the previous versions with Ctrl+Z. Hope it can save someone's day :) – bviale Dec 06 '17 at 14:24
  • Not using git reset is not about it not being useful or dangerous on itself. What happened to me occasionally was to have it on my terminal history, and hitting up twice without noticing, then resetting instead of compiling. So at least do it in a separate terminal :) – RSinohara Mar 01 '18 at 13:45
  • I've just discovered that the new `git restore` needs to be added to the list of "dangerous" git commands, having just lost a chunk of uncommitted changes while intending to simplly unstage them from a partial commit. It seems to have the same behavior as `git reset --hard`, but the latter at least has the common decency to require the `--hard` switch to make you think hard before hitting Return. – Myk Willis Jan 10 '20 at 01:06

18 Answers18

656

answer from this SO

$ git reflog show

4b6cf8e (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to origin/master
295f07d HEAD@{1}: pull: Merge made by the 'recursive' strategy.
7c49ec7 HEAD@{2}: commit: restore dependencies to the User model
fa57f59 HEAD@{3}: commit: restore dependencies to the Profile model
3431936 HEAD@{4}: commit (amend): restore admin
033f5c0 HEAD@{5}: commit: restore admin
ecd2c1d HEAD@{6}: commit: re-enable settings app

# assuming you want to get back to 7c49ec7 (restore dependencies to the User model)

$ git reset HEAD@{2}

You got your day back! :)

ken
  • 12,377
  • 6
  • 39
  • 34
  • 52
    Just to add to this answer this would help people who actually had committed changes that were thrown away via hard reset. – murki Aug 05 '14 at 18:18
  • 11
    Great - but in my case the files were gone completely. Using `git checkout HEAD@{19}` allowed me to check out the lost files in a detached state. Then used `git checkout -b new-branch-name` to add them back to the repo in "attached" state. – NightOwl888 Oct 02 '16 at 19:29
  • @NightOwl888: Git newbie here and I had the same problem that my files were still gone. Could you explain in more detail how you have recovered your files into an "attached" state (or could you explain what that actually means)? Thank you so much! – OhDaeSu Nov 14 '16 at 18:30
  • 3
    @user3385759 - In Git, when you use the checkout command on anything that is not a branch, it will go into a special "detached head" mode. This means you are not actually pointing at a branch, but you can view what was checked in at the state of the entity (in this case a reflog entry). From that state, you can turn it into a "real" branch that you can go back to again by using `git checkout -b new-branch-name`. The book [Pragmatic Version Control Using Git](https://pragprog.com/book/tsgit/pragmatic-version-control-using-git) is good at explaining Git in simple terms. – NightOwl888 Nov 14 '16 at 19:53
  • @ken can you explain the syntax of `git reset HEAD@{2}` please? – Tim Randall Sep 22 '21 at 13:28
  • 3
    ken and @NightOwl888 you guys just saved three days of my life! Wish you happiness and prosperity! – Daniiar Abdiev Nov 27 '21 at 13:09
  • @TimRandall HEAD@{2} actually kept the commit HEAD of `7c49ec7 (restore dependencies to the User model)`. So we make the assumption that was the commit accidentally thrown away and you want to get it back. This can be done via `git reset HEAD@{2}` – ken Nov 30 '21 at 04:05
  • This worked great. Fortunately my changes were committed in local. Saved me a lot of tine. – Ayush Sood Mar 29 '22 at 19:02
582

You cannot get back uncommitted changes in general.

Previously staged changes (git add) should be recoverable from index objects, so if you did, use git fsck --lost-found to locate the objects related to it. (This writes the objects to the .git/lost-found/ directory; from there you can use git show <filename> to see the contents of each file.)

If not, the answer here would be: look at your backup. Perhaps your editor/IDE stores temp copies under /tmp or C:\TEMP and things like that.[1]

git reset HEAD@{1}

This will restore to the previous HEAD

[1] vim e.g. optionally stores persistent undo, eclipse IDE stores local history; such features might save your a**

Ben Wheeler
  • 5,941
  • 2
  • 43
  • 55
sehe
  • 350,152
  • 45
  • 431
  • 590
  • 22
    Eclipse's local history - and in addition, since some changes were older than 6 days, my Time Machine backup of Eclipse's local history! For some reason the Time Machine backup of the folder managed by git did not contain my previous changes. – christianbrodbeck May 31 '12 at 04:31
  • Here is the link for instructions as to how to recover files from Eclipse backup. https://wiki.eclipse.org/FAQ_Where_is_the_workspace_local_history_stored%3F – Ratnakar Malla Jul 22 '15 at 17:21
  • 1
    Luckily I have TimeMachine set up to backup every hour so I was able to scoop the files out of the last backup. It doesn't recover hidden files so far as I can tell so you should copy the files over directly from the filesystem. – gillytech Apr 13 '17 at 20:18
  • It doesn't make sense why git can't just backup uncommitted changes during a reset, even temporarily. This is an entirely preventable problem. Is there a feature for this? – steventrouble Apr 24 '17 at 21:49
  • 15
    The IDE (IntelliJ) stored the changes locally which saved the day. Thanks for the tip! – progonkpa Jun 19 '17 at 20:16
  • PHPStorm 2017.2: right click in editor -> Local History -> Show History. But now that I almost had to learn the hard way, I think I'll follow @JanHudec's suggestion of favouring alternatives over `git reset` whenever possible. – LinusR Nov 21 '17 at 13:50
  • I just got saved by PhpStorm's local history – Sudar Apr 17 '18 at 04:53
  • 2
    `git reset HEAD@{1}` caused an error in powershell terminal resulting `error: unknown switch ``e'` The way around this is escaping the curly braces with single quotes like this: `git reset 'HEAD@{1}'` because curlies have a different meaning for powershell – Batu Dec 17 '18 at 02:13
  • re `vim` and `eclipse`: great suggestion. i have personally used both `vim` and `eclipse` to recover old code that was not in `git` repo. `eclipse` is especially useful with it's `local history` feature b/c i think it updates every save you do. – Trevor Boyd Smith Jan 08 '19 at 13:39
  • As a note, `git log HEAD@{1}` will also *show* the lost commits, to review before you reset to them. – JJ Brown Jan 17 '19 at 20:29
  • 9
    Indeed local history in Eclipse (Intellij in my case) save my day in recovering unstrage changes, doc here for Intellij : https://blog.jetbrains.com/idea/2008/01/using-local-history-to-restore-deleted-files/ – Richard Jan 25 '19 at 22:16
  • Just to complete the `git show` -- `cd .git/lost-found/commit; ls; git show abc123... > ~/rescue.patch`, then work through the patch using `git apply`. –  Jun 06 '19 at 08:35
  • So in `lost-found` I got a single file `other\SOME_HASH`. Turns out it is a git tree. I could see its contents running `git ls-tree -r SOME_HASH`. And restore all the files from it (requires git 2.23, `restore` command is new) with `git restore -s SOME_HASH -W -S .` – LOST Oct 25 '19 at 05:30
  • After code a half day, I decide to `git add .` and then I suddenly do a `git reset --hard HEAD`, and then I do `git status`, I found nothing, My GOD. you give me second chance to live in the world :) – Frank AK Jun 23 '20 at 08:56
  • 1
    Shell snippet to review any files that were added to the staging area but never committed: `for fname in $(ls .git/lost-found/other/); do echo $fname:; cat .git/lost-found/other/$fname; read -n 1 -p "Continue?"; echo; done` – ncoghlan Sep 16 '20 at 08:08
348

I accidentally ran git reset --hard on my repo today too while having uncommitted changes too today. To get it back, I ran git fsck --lost-found, which wrote all unreferenced blobs to <path to repo>/.git/lost-found/. Since the files were uncommitted, I found them in the other directory within the <path to repo>/.git/lost-found/. From there, I can see the uncommitted files using git show <filename>, copy out the blobs, and rename them.

Note: This only works if you added the files you want to save to the index (using git add .). If the files weren't in the index, they are lost.

Ben Wheeler
  • 5,941
  • 2
  • 43
  • 55
Justin
  • 3,804
  • 2
  • 13
  • 15
  • 4
    I got just files with commit references in `lost-found`. But I could then do `git show` to get contents. – Mitar Sep 17 '13 at 04:28
  • 12
    Just to save anyone time `#!/bin/bash cd PATH_TO_PROJECT/.git/lost-found/other FILES=* COUNTER = 0 for f in $FILES do echo "Processing $f file..." git show $f > "PATH_TO_RECOVERY_DIRECTORY/$COUNTER.m" let COUNTER=COUNTER+1 done` – rwolst Oct 22 '14 at 14:08
302

Yes, YOU CAN RECOVER from a hard reset in git.

Use:

git reflog

to get the identifier of your commit. Then use:

git reset --hard <commit-id-retrieved-using-reflog>

This trick saved my life a couple of times.

You can find the documentation of reflog HERE.

Gabe
  • 6,019
  • 5
  • 38
  • 87
  • 16
    So far, I think this is the best and most concise answer. It may seem counter intuitive to recover from `git reset --hard` using another `git reset --hard` but if you don't use the `--hard` switch, you'll be left with entries in your workspace that would effectively revert the work you just recovered. – Ryan H. Mar 17 '17 at 17:07
  • 4
    Works like a charm! The previous answer (https://stackoverflow.com/questions/5788037/recover-from-git-reset-hard/24236065#24236065) did not work for me. – codemax Nov 29 '17 at 10:12
  • 1
    Damn, I used `git show 67db6072093a119fef0cfe946191e09d861360d5 > path-to-file` but using `git reset --hard ` would have saved me some tedium. At least I know for next time (I hope there will never be a next time). – Nick Bolton Jul 27 '18 at 13:37
  • 10
    This answer is not correct. This approach only recovers previously **committed** changes. It will not be able to restore **uncommitted** changes (which is what this question is about). – Alderath May 21 '19 at 08:56
  • 1
    That's why the accepted answer starts with "You cannot get back **uncommitted** changes in general". I thought this might still be useful to some though. :) – Gabe May 21 '19 at 14:15
  • 2
    This solutions works for me. I made a hard reset and then when I use `git log` I didn't see the id of the commit. With `git reflog` I could see the commit ID – dboscanv Aug 23 '19 at 14:19
  • That's the right solution for the committed changes. Thanks, @Gabe! – Oltion Driza Jan 06 '22 at 11:05
76

While I was working on a local project, I wanted to move it to GitHub and then created a new repository. While I was trying to add all these files to the new repository with .gitignore, I accidentally added a wrong file and then tried to clear it.

I ran git reset --hard origin/master

Then all of my local files deleted because the repo was empty. I thought everything was gone.

This worked for me:

git reflog show
git reset HEAD@{1} 
git push 
Zoe stands with Ukraine
  • 25,310
  • 18
  • 114
  • 149
Orcun
  • 943
  • 1
  • 9
  • 14
56

If you use something like IntelliJ:

On the context menu, choose Local History, and click Show History on the submenu:

The local history view for a project or folder shows you everything that you have done during the last few days. In the Action column of the lower part of the dialog box, select the action you want to roll back. [...] So doing, the upper part of the dialog box shows the tree view of changed files. If you want to restore the deleted file only, regardless of the other changes that have been done since then, you can select the file Lost.txt in the tree view and click the Revert button.

http://blog.jetbrains.com/idea/2008/01/using-local-history-to-restore-deleted-files/

This just got my arse out the fire!

isherwood
  • 52,576
  • 15
  • 105
  • 143
JonathanTien
  • 1,336
  • 1
  • 11
  • 11
  • 3
    This is by far the best answer for IntelliJ users! Thank you so much, this worked perfectly. I tried every other solution and none of them worked well. `git reflog` didn't work because I didn't commit the changes. `git fsck --lost-found` worked for staged files but not all of them were staged. IntelliJ's Local History perfectly recovered my unsaved files, I'm so grateful for this feature – Denes Papp May 29 '20 at 23:41
47

I just did git reset --hard and lost all my uncommitted changes. Luckily, I use an editor (IntelliJ) and I was able to recover the changes from the Local History. Eclipse should allow you to do the same.

warvariuc
  • 53,721
  • 35
  • 166
  • 222
user1147827
  • 471
  • 4
  • 2
22

By definition, git reset --hard will throw away uncommitted changes without any way for Git to recover them (your backup system may help, but not Git).

Actually, there are very few cases where git reset --hard is a good idea. In most cases, there's a safer command to do the same thing:

  • If you want to throw away your uncommitted changes, then use git stash. It will keep a backup of these changes, which will expire after some time if you run git gc. If you're 99.9% sure you'll never need these changes back, then git stash is still your friend for the 0.1% case. If you're 100% sure, then git stash is still your friend because these 100% have a measurement error ;-).

  • If you want to move your HEAD and the tip of the current branch in history, then git reset --keep is your friend. It will do the same thing as git reset --hard, but will not discard your local changes.

  • If you want to do both, then git stash && git reset --keep is your friend.

Teach your fingers not to use git reset --hard, it will pay back one day.

Matthieu Moy
  • 13,111
  • 3
  • 36
  • 62
  • so if one does `git stash && git reset --hard` that would wipe out any stashed content is that right? – jxramos Oct 09 '18 at 16:48
  • 1
    No, `git reset --hard` doesn't discard the stash. `git stash` is a replacement for `git reset --hard` in the sense that it removes uncommited changes from your worktree, except that it keeps them safe instead of discarding them permanently. – Matthieu Moy Oct 09 '18 at 20:05
  • or just commit your changes before you reset hard and they will still be in your local repo – ThaJay Dec 05 '18 at 12:53
15

This is what I usually do if I lose some changes.

git reflog
git checkout <commit id> // now you are in where you want but you cannot push from detached branch to master
manually copy and paste changes from detached branch to master or working branch
git reset --hard HEAD // if needed
git add ... > git commit ... > git push ...

to move the pointer back to your previous commits but keeping the changes you made so far in your latest commits checkout git reset --soft dadada

DragonKnight
  • 1,505
  • 1
  • 19
  • 28
11

The information is lost.

Since you did not commit, your .git never stored this information. So, basically git cannot recover it for you.

But, If you just did git diff, there is a way you can recover using the terminal output with the following 3 simple steps.

  1. scroll your terminal and look for the o/p of git diff. Save the o/p in a file called diff.patch
  2. Search & Replace all 7 spaces and 8 spaces with tab(\t) character and save the changes.
  3. Go into your git repository. Apply the diff.patch (patch -p1 < diff.patch)

Note: While you are copying the data from terminal to a file, be careful and clearly see that the data is continuous output and did not contain any redundant data(due to pressing up and down arrows). Otherwise you might mess it up.

Zoe stands with Ukraine
  • 25,310
  • 18
  • 114
  • 149
Sandeep
  • 17,036
  • 13
  • 64
  • 103
11

I ran into same issue and I was almost going insane....initially I committed the project and merged. Later when I try running git push --set-upstream origin master I was getting this error

  fatal: refusing to merge unrelated histories

so I ran git reset --hard HEAD and it deleted a 3 weeks project but these few commands below save the day:

git reset HEAD@{1}         //this command unstage changes after reset
git fsck --lost-found      //I got the dangling commit fc3b6bee2bca5d8a7e16b6adaca6a76e620eca4b
git show <dangling commit something like-> fc3b6bee2bca5d8a7e16b6adaca6a76e620eca4b>
git rebase fc3b6bee2bca5d8a7e16b6adaca6a76e620eca4b
Zoe stands with Ukraine
  • 25,310
  • 18
  • 114
  • 149
Slycreator
  • 837
  • 10
  • 14
8

IntelliJ has a temporary folder accessible through the history command:

  1. Select the folder to revert files from in your navigation pane
  2. Double tap the Shift key (shift-shift)
  3. In the input box that pops up type Local History and press Enter
  4. Select Show History
  5. Now you can revert to the version you need.
isherwood
  • 52,576
  • 15
  • 105
  • 143
Lucian Enache
  • 2,370
  • 5
  • 33
  • 58
7

If you luckily had the same files opened on another editor (eg. Sublime Text) try a ctrl-z on those. It just saved me..

Gabe
  • 6,019
  • 5
  • 38
  • 87
4

I found out the hard way that any uncommitted files before a git reset --hard <commit> gets removed from git history. However, I was lucky enough to have kept my code editor session open during the entire time I was pulling my hair out, that I discovered that a simple control + z in each of the affected files returned the state of the file back to the version before Git so obligingly reset everything I didn't ask it to specifically. Hooray!!

Friendly-Robot
  • 1,104
  • 12
  • 22
2

(answer suitable for a subset of users)

If you're on (any recent) macOS, and even if you're away from your Time Machine disk, the OS will have saved hourly backups, called local snapshots.

Enter Time Machine and navigate to the file you lost. The OS will then ask you:

The location to which you're restoring "file.ext" already contains an
item with the same name. Do you want to replace it with the one you're
restoring?

You should be able to recover the file(s) you lost.

Calaf
  • 8,925
  • 11
  • 53
  • 110
0

If you're developing on Netbeans, look between the file tabs and the file edit area. There is a "Source" and "History". On "History" you'll see changes made using version control (git/other), but also changes made locally. In this case, local changes could save you.

Pedro Alvares
  • 389
  • 3
  • 8
-1

For later you can use VSCode with ext: GitLens - Git supercharged so you can reverse your code with this extensions

SangLe
  • 89
  • 5
-2

You can only recover staged (git add) changes that you have lost.

you can recover easily by running this command

step:1 Go to project root directory and then run this command

npx git-recover

step:2 enter recovery directory path like

/Users/apple/RecoveryDirectory

you will get lost file in RecoveryDirectory

enter image description here

Muhammad Numan
  • 17,689
  • 4
  • 42
  • 65