3

I've initialized git repo in existing project, staged all files and then without making initial commit decided to cleanup the index. Not sure why I thought it was a good idea, but I instantaneously typed git reset --hard (I cannot really say what I had in mind at the moment, maybe several sleepless nights took a toll). Now all files are gone...

Is it possible to recover at least some of it? I see that there are objects registered in .git/objects/.

jayarjo
  • 16,124
  • 24
  • 94
  • 138
  • 1
    possible duplicate of [In Git, how can I recover a staged file that was reverted prior to committing.](http://stackoverflow.com/questions/11094968/in-git-how-can-i-recover-a-staged-file-that-was-reverted-prior-to-committing) – Mureinik May 01 '15 at 14:14
  • `git reset` is probably the only guaranteed way to lose your work with git. It makes a permanent change to your working directory. – Vincent Ramdhanie May 01 '15 at 14:17
  • @Mureinik, I'm talking about hundreds of files, what you've referenced might be a solution for single file maybe or several max. – jayarjo May 01 '15 at 14:21
  • @Vincent Ramdhanie, what are thos .git/objects/ files then (a lot of them, almost 44mb), what do they hold? – jayarjo May 01 '15 at 14:22

1 Answers1

3

If you did a git add to stage the files before the git reset, then all the files, and the tree objects describing the directory hierarchy are in your object data base .git/objects, unless it's been long enough that garbage collection has kicked in, or you've run something like git gc on your own. However, reconstructing things is going to take a bit of work - git doesn't come pre-packaged with this functionality built in. Here's some hints:

  1. Use git cat-file -t HASH on each object in your database to identify the types of each object. Look for the ones that are tree objects. Note the object hashes are split to name the files in .git/objects. So an object with hash "db6689df4f8aae84d35df2e496158b2746bb0f1e" is actually stored at .git/objects/db/6689df4f8aae84d35df2e496158b2746bb0f1e, with the first two characters used as a subdirectory - you can reconstruct the object hashes easily with that in mind. If you have files in .git/objects/pack, then you might need to additionally run git verify-pack -v .git/objects/pack/pack-HASH.pack to get the list of objects contained in each pack file.
  2. For each tree object, use git cat-file -p HASH to find the original file name and hash for your files (also known as "blobs"). One of these trees will match what the root of your working directory looked like. Once you've identified your root tree object, you can
  3. run git ls-tree -r HASH to get a full list of all the file names and their respective hashes.
  4. For each file that you want to restore from the above list, you can run git show HASH > FILENAME to recreate the file - you will need to create the subdirectories by hand, though, first.

With that information, it shouldn't be too difficult to write a script that does the heavy lifting for you. Good luck!

EDIT: alternatively, once you've identified your root tree object, you can simply echo "commit for recovery" | git commit-tree HASH, which will create a commit and report to you the hash of that new commit. Then you can git checkout HASH to get the files back in the working directory, and git branch BRANCHNAME to create a branch pointing to that commit. You might also take a look at git tar-tree, if your version of git is old enough, or git archive.

twalberg
  • 59,951
  • 11
  • 89
  • 84
  • Haven't found a tree object, only blobs... I ended up with the script that was traversing all the files, identifying php or js (both having specific traits and namespaces in the header) files and reconstructing directory structure and names out of there. Was able to recover most part of required files. In any case git is great tool and you got a great answer! – jayarjo May 01 '15 at 19:38
  • 2
    I suppose if you just did `git add ...`, and none of those files were in a subdirectory, it's possible you don't have any tree objects. Then again, maybe trees don't get created until you do the `git commit`, and the info is just stored in the index (which you've already reset) until then... – twalberg May 01 '15 at 19:44
  • Lifesaving if you happen to be one of the few poor souls that managed to get themselves in this bind. – ijoseph Feb 18 '21 at 01:34