OK, alla fine ho capito.
Versione breve: ho modificato il commit puntando al blob corrotto per rimuoverlo dalla cronologia.
Versione lunga: ho pensato che dal momento che sapevo cosa fosse il file e volevo solo farlo sparire dal commit, allora potevo semplicemente modificare il vecchio commit. Non mi aspettavo davvero che funzionasse, ma alla fine lo ha fatto.
Devo precisare che ho rimosso il blob in .git/objects nel provare cose precedenti, ed è probabilmente importante il perché ha funzionato.
In primo luogo, ho dovuto sapere che cosa è stato commettere. Per questo ho usato il comando
git log --raw --all --full-history -- subdir/my-file
ho trovato il commit è stato chiamato 966a46 ....
poi ho fatto i passi per modificarlo. Dal momento che era un vecchio commit, ho usato
git rebase -- interactive 966a46^
Il mio editore è entrato con una riga per ogni commit, e ho cambiato "pick" a "modifica" di fronte al commesso ho voluto modificare.
Il comando git status
mi ha mostrato che il file ho voluto cancellare è stata modificata:
# 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
ho voluto rimuoverlo dal commettere, così ho fatto rm subdir/my-file
. git status
poi mi ha mostrato:
# deleted: subdir/my-file
Questo sembrava promettente. Così ho semplicemente commesso l'modificato commettere e ha continuato il rebase:
git commit --all --amend
git rebase --continue
Ma dopo aver ricalcolato pochi commette è venuto a mancare con questo errore:
error: could not apply 45c2315... did some fancy things
fatal: unable to read 95b6a826cadae849f4932a71d6735ab6ceb47cab
45c2315 è stato il primo commit in cui la mia file è stato modificato dopo essere stato creato. Dal momento che non ha trovato la versione precedente del file, ha appena fallito.
git status
mi ha mostrato, tra le altre cose:
# 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
io non sono realmente sicuro che cosa significa, ma questo commit doveva essere il primo in cui sembrerebbe il file, dopo la correzione. Quindi non volevo che fosse cancellato, ma al contrario, aggiunto al commit! Così ho fatto
git add subdir/my-file
E sicuramente git status
mostrato come un "nuovo file".
Poi ho fatto git rebase --continue
e tutto è andato bene, e il rebase è stato un successo.
git push
è andato poi in modo regolare invece di fallire sul blob rotto.
Ma c'erano ancora un problema, perché git fsck
era ancora in mancanza:
$ git fsck --full
Checking object directories: 100% (256/256), done.
broken link from tree 27e8e7d5b94c1dad5410a8204089828a167a0eaf
to blob 95b6a826cadae849f4932a71d6735ab6ceb47cab
E git gc
fallito anche, quando gli ho chiesto di potare tutto. Quindi ho capito che la migliore linea d'azione era, dal momento che avevo spinto con successo, per clonare tutto in un nuovo repository e lavorare da lì.
Prova a guardare alcune delle soluzioni qui: http://stackoverflow.com/q/4254389/1031900 –
Questa domanda riguarda un albero danneggiato, che è un po 'diverso. Nessuna di queste risposte può aiutarmi, purtroppo. Ho intenzione di provare alcune cose e lo posterò qui se funzionano. –