Aug 25, 2010

Find missing git ref

I was a fool this morning: I rsynced old source code from my macbook to my new thinkpad w510. I have been working on the new thinkpad since Tuesday, without a push to github (ye, fool again), so all recent works exist only on thinkpad. After the rsync, I found the last commit in my git repo is committed 2 days ago ..

After a period of a mix of jump/cry/smoke/hit walls with my head/... I calmed down. Git saves any new file after you commit, it also save the tree and commit as object files, then it modify the ref to point to the new commit file. Rsync only ruined my refs, overwrite them to point to the old commit file, but the new source file, tree, commit should be still there on my dear harddisk. If I can find the last commit file of yesterday, then modify the ref to that commit manually, I may get all my changes back!

First I need to list all object files related to the yesterday's last commit. A while later I find them with:

cd .git
find . -newer <the newest file in current corrupted repo> -type f | xargs ls -l | grep object | grep "Aug 25 19:09" | awk '{print $9}'

The result is like this:


The next step is to check the contents and find the commit in these object files. I tried with `git cat-file` first, but it just report "fatal: Not a valid object name 3fc43a817252e031f6d0c387930539b4c613bc" again and again, because the new object is not in the old repo really.

After a google around I found a one-liner python script to inspect the content of object file, that's what I need exactly:

python -c 'import sys,zlib; sys.stdout.write(zlib.decompress(open(sys.argv[1]).read()))' <path-to-object-file>

Next is easy: I just checked each object file manually, and found the lovely commit object file at the 9th try:

commit 232tree b1a080cda86596501ee5bd88181c89fae1d5f07d
parent 09f4a0cd1374d848bffffba6c02fa6830aea587a
author Jan <j@xxxxxxxx.xx> 1282734563 +0800
committer Jan <j@xxxxxxxx.xx> 1282734563 +0800

The file name of the commit is ./objects/bb/a640a7830fafa3d9ae352a2b060df600a4d5e7, so I just modified the content of refs/head/branch-name to bba640a7830fafa3d9ae352a2b060df600a4d5e7.

The last step is go back to the repo, clean the repo with 'git reset --hard' because the files are still in old revision. Then everything just come back!