How to Recover After I Execute :Git Reset --Hard Head

How to recover after i execute :git reset --hard HEAD

If you didn't already commit your local changes (or at least stage them via git add, they're gone. git reset --hard is a destructive operation for uncommitted changes.

If you did happen to stage them, but didn't commit them, try git fsck --lost-found and then search through the contents of .git/lost-found - it will contain all of the objects that aren't referenced by a known commit, and may include versions of files that were staged.

Recover initial files after git reset --hard HEAD~

get the revision of the commit using git reflog and then reset to it:

git reset --hard the-id-of-the-commit-from-reflog

How do I undo a git reset --hard ~HEAD followed by git reset ORIG_HEAD?

By using git reflog, you can see all the commits your HEAD has been on recently. You can then use the commit-ish HEAD@{N} to come back to a previousy visited commit.

As you seem to have changed your HEAD 4 times, you should try git reset --hard HEAD@{4}.

Warning: if you try and don't succeed, it will change your reflog history as you moved your HEAD one more time, so run git reflog after each failed attempt and use the git message to identify the right commit.

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

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.

restore - git reset --hard HEAD^

Use the reflog to recover the sha1 of the previous HEAD. In particular, the article reflog, your safety net will be particularly relevant to you. From that article:

The most common usage of this command is that you’ve just done a git reset and moved your HEAD back a few commits. But oops, you need that bit of code you left in the second commit. Crap. Now what?

Once you have found the sha1 of the commit you want to go back to, use something like:

git reset --hard 0a1b2c

Recover from losing uncommitted changes by git reset --hard

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

How do i recover my storyboards after git reset --hard HEAD^?

You note in a comment that you did a git stash

This is a crucial bit of information, which changes everything. Fortunately, it also makes recovering much easier. In particular it means that your missing files are not "dangling blobs" and do have their original names saved. (Note, by the way, that git stash means git stash save; I'll use the longer form below to distinguish it from other git stash commands.)

The simplest way to recover is to use git stash branch. Pick a new branch name, one that you do not yet have. For illustration I will use saveme, which is a terrible name and you should choose a better one.

git stash branch saveme

This will take your existing git stash, create a new branch using the commit that was current when you ran git stash save. It will then restore your index (staging area) to the way it was at the time you ran git stash save, and restore your work-tree to the way it was at the time you ran git stash save. You can now commit the index:

git commit -m 'save index as a commit'

and then commit the rest of the work-tree if there is anything else to commit:

git add --all
git commit -m 'save everything else as a commit too'

I will add, at the end of this answer (in another edit), a pictorial diagram of what happens with this entire sequence, starting from the first git adds and going through the git stash save and git reset --hard HEAD^ and on to the final git stash branch.


There is one caveat: your index and work-tree must be clean to use git stash branch. If you have uncommitted work, you probably should commit it now, or throw it all out with git reset --hard. Of course, either one has consequences:

  • If you run another git stash save, the earlier saved stash gets "pushed up" from stash@{0} to stash@{1}. You will then have to use:

    git stash branch saveme stash@{1}

    to convert that stash to a branch.

  • If you choose to use git reset --hard, you lose any uncommitted work you have, so be sure that this is OK.

Pictorial diagram

Let's take a look at a hypothetical terminal session, and see what happens with your commits and branches as you work.

$ cd my-git-project

At this point, you are in a Git work-tree. The work-tree is where your files are in their normal form, that the rest of the computer (and you) can work with, instead of their Git-only form, where Git saves every version of every file you or anyone else has ever committed. You are on some branch—let's say master, just for concreteness. This branch has some set of commits, ending in what Git calls the tip commit of that branch. The branch name remembers the hash ID of this tip commit:

...--F--G--H   <-- master

Each uppercase letter represents a normal, ordinary commit. (In other words, these stand in for the incomprehensible hash IDs that are the actual names of each commit.) Commit H is the latest one. If your index / staging area and work-tree are "clean", the files in them match those in commit H.

Now you make some changes, and stage some or all of them:

$ ... edit some files ...
$ git add file1 file2 ...

The staging area, aka index, is now not "clean": it no longer matches commit H. Instead, it has copies of the edited and added files.

Your work-tree may or may not match your index. If it does match your index, and if you were to run git commit, Git would make a new commit out of your index (that's what the index / staging-area is for, mainly: to build the next commit), and then your index would match your commit and be clean. If your work-tree matches your index, that too would then be clean. This would look like:

...--F--G--H--I   <-- master

where I is the new commit, made from your index.

Instead, though, you ran git stash save. What this does is make two commits, neither of which is on the branch:

...--F--G--H   <-- master
|\
i-w <-- stash

The first (lowercase i) commit is the same commit that git commit would have made. It's just not on branch master; it's part of this two-commit "stash bag". The second commit, w, is peculiar: it looks to the rest of Git like a merge commit, but in fact it's just a commit of your work-tree state, even if that's the same as the index state in i.

After making these two stash-bag commits, git stash resets (cleans) your index and work-tree, a la git reset --hard HEAD. So now your index and work-tree match commit H again.

Next, you say you ran git reset --hard HEAD^. This does three things: it resets the index and work-tree state to the state of the selected commit, which is the one just before H; and it makes the name master point to the selected commit as well. So now your repository looks like this:

...--F--G   <-- master
\
H [remembered in reflogs, *and* preserved via the stash]
|\
i-w <-- stash

Note that the stash-bag is still there, and still find-able by the name stash. The two stash-bag commits remember commit H by its hash ID. Meanwhile, the name master now remembers the hash ID for commit G instead—and your index and work-tree are "clean", i.e., match that for G.

If you now run git stash branch saveme, this is what Git does in terms of commits:

...--F--G   <-- master
\
H <-- saveme
|\
i-w [abandoned]

The index is re-loaded from the i commit, and the work-tree is re-loaded from the w commit. If you now run git commit you get:

...--F--G   <-- master
\
H--I <-- saveme

since Git saves the index as a new commit I. The work-tree remains unchanged; if it's clean with respect to I, it's now all clean, and if not, you can git add any remaining changes and commit them:

...--F--G   <-- master
\
H--I--J <-- saveme

and now everything is saved permanently (or until you delete the saveme branch) in plain, ordinary commits that you can work with in the usual ways. Note that commit H, which you threw into the recycling bin with git reset --hard HEAD^, has come back on the new branch.


Original answer

I should also add that I had only added the storyboards to the stage and hadn't committed them yet at the time of the reset ...

This makes things harder, because:

... so today I was using the git reflog command

git reflog looks only at abandoned commits.

... in hopes that they were in the lost and found.

They may still be! The "lost and found" is separate from the reflogs.

I had read that the garbage collection doesn't happen for a month so I don't think (I hope) they're just gone

The 30-day grace period is specifically for commit objects that are remembered in reflogs, which these are not. However, all objects get a 14-day grace period. The clock starts at the time you git add the file to the staging area. (Even once the clock runs out, it takes a later git gc --auto to make the files go away, but it's hard to know when that will happen.)

Actually finding your files is a bit trickier. Run:

git fsck --lost-found

which, as the documentation says:

--lost-found

    Write dangling objects into .git/lost-found/commit/ or
    .git/lost-found/other/, depending on type. If the object is a blob,
    the contents are written into the file, rather than its object
    name.

Since you did git add these files, and they presumably never were in any commit, they will be "dangling" objects of type "blob". The git fsck command will print a bunch of incomprehensible hash names. You can then change into the .git/lost-found/other/ directory and examine all the files there, which all have these hash names. In amongst all these files, the contents you git added will appear.

For each such file, figure out whether it should be saved away under which sensible file name, and move the file out of the lost-found/other area to one of that name, and you have that file back.

How do I undo a `git reset --hard HEAD~1`?

You can revert ant code you have in your local git folder, whether its was committed or not.

What can be recovered:

  • All commited changes
  • All added items (git add without git commit)
  • All loose blobs (dangling files)

What can't be recovered:

  • Deleted files from the local file system. (You can recover those by using 3rd party tool which scan your drive and recover them)

How to recover:
First run git reflog ro git log -g to verify what did you clean. Then checkout the commit that you wish to recover.

Now you have to recover added but uncommited files. To find those files run git fsck and it will print out the dangling files. use git cat-file -p <SHA1> to print them out to screen and then recover them.

git log -g will display the reflog entry for each of your commit.

Good luck.



Related Topics



Leave a reply



Submit