How to recover broken/partially deleted git repository

data-recoverygit

I accidently ran an rm -r on my .git directory. Luckly rm stopped when it got to a write-protected file, but I've still lost several things in my .git.

Files I still have:

FETCH_HEAD
ORIG_HEAD
config
gitk.cache
logs/
objects/

Files I've lost:

HEAD
description
hooks/
index
info/
packed-refs
refs/

From what I can tell, the only things I've lost that I can't re-clone are the changes in my staging area and my refs. I'm prepared to lose my staging changes but I really need to recover my HEAD and my branches. Is there a way to do this? Say, by finding commits that have no children, checking them out to see what they are and creating branches for them? At the moment git doesn't even recognise my repository as a repository anymore though.

Best Answer

All of the commits and the files that they reference would be stored as objects in the objects directory. Git creates those as read-only, so they should all still be present.

To recover, I'd advise creating a new, empty repository and copying the contents of your broken repository's objects directory into that of the new one. That should get you to a point where git will at least recognize that it's a repository and it will have all of your objects. Working with a copy will also help to avoid causing even more damage while trying to fix things.

Shell commands to create the temporary repository and copy over the objects:

git init /tmp/recovery
cd /tmp/recovery
cp -r /path/to/broken/repo/.git/objects .git

Once that is done, you could use git fsck to get a list of objects that aren't referenced by anything. This should include all of the branch heads, but it would also include any commits that were made obsolete by git commit --amend or by rebasing.

Since you still have the logs directory that is likely to be an even bigger help. There should be a logs/refs/heads/<branch> file for each branch that you had. The second column of the last line will contain the ID of the commit which was at the head of that branch when the deletion was done. There should also be logs/HEAD with the same information for where the HEAD was, but unless you'd been working with a detached HEAD it's probably better to just recover the branches and then checkout a branch normally.

For each branch that you want to restore you can run:

git branch <name> <commit_id>

Once you've restored the branches you can copy over the config file, and you should be fairly close to where you were as of the latest commit.

Related Question