Search code examples
gitundogit-resetgit-addgit-stage

Is there any way to undo a "`git reset .`"? It 'reverted' all files - all edits have been lost from my working directory


I staged a grand number of files for commit.

Then I realized it was better to commit only two of the files, and then commit the remaining ones in a separate commit.

git reset <filename> unstages filename

I wanted to unstage everything,
then restage two files, and commit.
Then stage all remainging files and commit again.

As: "git add ." (adds all files to staging area)
and "git reset <filename>" (removes filename from staging area)
"git reset ." (seemed to make sense to unstage all files)

oops..!
That reverted my working directory to the last committed version,
- I lost ALL File Edits that I had made! :-(

Anyway to "undo" "git reset ." ??

I've not found any documentation on this.
In fact I do not find any documentation on "git reset ." at all.
My best guess is that git took the "." to be the value for an option, other than the filename option.

But is this undoable ?


Solution

  • Yes!, It turns out, You Can !!

    Here is why: git interprets git reset . as git reset --hard

    So that deleted all changes in my working directory, reverting everything to the state of my last commit.

    There is no built in way to recover the file edits I had lost.
    However, git add . saved a copy of each file that had those edits in them.
    We, just need to get a handle on where/how git saved the state of said files.

    In short, do perform the following steps:

    (1):
    git fsck --cache --unreachable $(git for-each-ref --format="%(objectname)") \ $(egrep commit all | cut -d ' ' -f 3) > stagedNotCommitted

    This will find and put a list of files that git has indexed (because they had been staged),
    but that have never been committed, into a file named stagedNotCommitted

    Since git does not know the file names for these files, stagedNotCommitted will be a listing of the indexed files' hashes. looking something like

     `369c722e8df1c83b6ebfc0dc2d426aa612535203
      63282280da679aa19d6a2a71e08bed8487f7e688
      6a540aa36ee558611528176dbf87ad8e39475222
      9c8ce87dd8aff2abc78d8a5dbe976473c6fea3de
      9e20a6530229dac42cb87dc0a7153edb4bad96b5
      abec86bc81f8b473e5ea8f0320589619d5e726b2
      b830a382cd30308782a1df12e553227100b47ba4
      c8bc4788fee301c8c88ed29739927689742c55bf
      f87c9f32da264e5e0b9de3d1818e291a687adab9`
      ...    
    

    (2):
    From here you can open each file in your text editor (I used Sublime), and save the ones you wish to recover under the correct name.

    The way I went about this was by saving each "unreachable blog" into a temp file as such:
    (you can use just the first few digits for each file)

    $ git show 89f45 > _02_89f45 $ git show 07f9c > _03_07f9c $ git show 23ad5 > _04_23ad5

    ...

    From there opening all these files in sublime was easy.

    Just re-save with the appropriate name.

    Done !! :-)

    Note, this only works because I had already Staged All the Files I wanted to recover.
    Had I not Staged (all) them, I'd outta luck. (or could only recover some of them.)

    For more information please visit the following links I found useful on StackOverflow:

    This one is Particularly Useful, with a great explanation!
    Undo git reset --hard with uncommitted files in the staging area

    Others:
    Good, well explained info:
    How can I undo git reset --hard HEAD~1?

    This one also has a post linking a plugin that claims to do it for you:
    Recovering added file after doing git reset --hard HEAD^

    Finally, here is an interesting table:
    https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/summary

    Command Scope Common use cases git reset Commit-level Discard commits in a private branch or throw away uncommited changes git reset File-level Unstage a file git checkout Commit-level Switch between branches or inspect old snapshots git checkout File-level Discard changes in the working directory git revert Commit-level Undo commits in a public branch git revert File-level (N/A)