Fixing a Git Repository with Broken Links

Just the other day one of my Git repositories developed problems and did things like this:

bombe@scandium:~/git/repo> git describe next
error: Could not read 706f6f1ff3dadccab7b037736d5ebf4eeadf7ccd
fatal: No tags can describe 'b39a41ddb264bbc673d731b81897583796657eca'.

git fsck reported (among other things removed for brevity):

broken link from commit 73ba74461ca2dd1da89f322aa87035f710fe4865
to commit 706f6f1ff3dadccab7b037736d5ebf4eeadf7ccd

Fortunately, even though this commit was quite recent it was already pushed to a remote repository so the correct data had to be there. But how do I get it back?

I tried naïvely to simply remove the branch and refetch it from the remote repository but that didn’t change anything. Of course it didn’t, the broken objects would still be in Git’s object store, they are referenced from the reflog as well, and I didn’t try to fiddle around with the settings for git gc to get it to remove objects more recent than two weeks.

Browsing the list of all available commands I stumbled upon pack-objects and unpack-objects which according to their respective man pages would do what I need. I cloned the remote repository next to the broken repository and started my rescue operation, after creating a copy of my broken repository:

bombe@scandium:~/git/repo> (cd ../repo2; echo 706f6f1ff3dadccab7b037736d5ebf4eeadf7ccd | git pack-objects --stdout) | git unpack-objects
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Total 1 (delta 0), reused 1 (delta 0), pack-reused 0
Unpacking objects: 100% (1/1), 882 bytes | 441.00 KiB/s, done.

Well, that looked nice. Did it work? What does git fsck say?

broken link from commit 706f6f1ff3dadccab7b037736d5ebf4eeadf7ccd
to commit 0f2af3a9ceede2efed3f5a477aba1cbd7fe7f5c0

Well, that’s a success! The formerly missing/broken commit was fixed but now pointed in turn to another missing or broken commit. In my case I had to repeat above procedure a small number of times but finally git fsck was not reporting broken links anymore and every other command once again performed like I expected it to.