I have a situation with a corrupt object in a repository.
$ git push
...
fatal: loose object 95b6a826cadae849f4932a71d6735ab6ceb47cab (stored in .git/objects/95/b6a826cadae849f4932a71d6735ab6ceb47cab) is corrupt
...
And I know that this objet is a blob linked to by an old commit:
$ git fsck --full
Checking object directories: 100% (256/256), done.
broken link from tree 27e8e7d5b94c1dad5410a8204089828a167a0eaf
to blob 95b6a826cadae849f4932a71d6735ab6ceb47cab
I have done the classic steps to recover the blob from the FAQ but it seems there is no other copy of it anywhere that I can find (I am working alone and haven't push to the remote for a while so it's not there) so I can't recover it.
This blob is actually the first version of a file which has been modified a lot since then. I am fine losing the information about that version of the file. So I would like just to remove it from the commit that is pointing to it. How can I do that?
OK, I figured it out myself eventually.
Short version: I amended the commit pointing to the corrupt blob to remove it from the history.
Long version: I thought that since I knew what the file was, and just wanted to make it disappear from the commit, then I could just amend the old commit. I didn't really expect it to work, but eventually it did.
I have to point out that I removed the blob in .git/objects in trying previous things, and it is possibly important into why it worked.
First, i had to know what commit it was. For that I used the command
git log --raw --all --full-history -- subdir/my-file
I found the commit was named 966a46....
Then I did the steps to amend it. Since it was an old commit, I used
git rebase -- interactive 966a46^
My editor came in with one line for each commit, and I changed "pick" to "edit" in front of the commit I wanted to modify.
The command git status
showed me that the file I wanted to erase was modified:
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: subdir/my-file
I wanted to remove it from the commit, so I did rm subdir/my-file
. git status
then showed me:
# deleted: subdir/my-file
This looked promising. So I simply committed the amended commit and continued the rebase:
git commit --all --amend
git rebase --continue
But after having rebased a few commits it failed with this error:
error: could not apply 45c2315... did some fancy things
fatal: unable to read 95b6a826cadae849f4932a71d6735ab6ceb47cab
45c2315 was the first commit in which my file was modified after having been created. Since it didn't find the previous version of the file, it just failed.
git status
showed me, among other things:
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# deleted by us: subdir/my-file
I'm actually not sure what it means, but this commit was supposed to be the first in which the file would appear, after the fix. So I didn't want it to be deleted, but on the contrary, added to the commit! So I did
git add subdir/my-file
And surely git status
showed it as a "new file".
Then I did git rebase --continue
and everything went good, and the rebase was a success.
git push
went then smoothly instead of failing about the broken blob.
But there were still a problem, because git fsck
was still failing:
$ git fsck --full
Checking object directories: 100% (256/256), done.
broken link from tree 27e8e7d5b94c1dad5410a8204089828a167a0eaf
to blob 95b6a826cadae849f4932a71d6735ab6ceb47cab
And git gc
failed too, when I asked him to prune everything. So I figured out the best course of action was, since I had successfully pushed before, to clone everything back in a new repository and work from there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With