94 votes

Comment récupérer les objets Git endommagés par une panne de disque dur ?

J'ai eu une panne de disque dur qui a endommagé certains fichiers d'un référentiel Git. En exécutant git fsck --full J'obtiens le résultat suivant :

error: .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack SHA1 checksum mismatch
error: index CRC mismatch for object 6c8cae4994b5ec7891ccb1527d30634997a978ee from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack at offset 97824129
error: inflate: data stream error (invalid code lengths set)
error: cannot unpack 6c8cae4994b5ec7891ccb1527d30634997a978ee from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack at offset 97824129
error: inflate: data stream error (invalid stored block lengths)
error: failed to read object 0dcf6723cc69cc7f91d4a7432d0f1a1f05e77eaa at offset 276988017 from .git/objects/pack/pack-6863e0a0e4b4ded6090fac5d12eba6ca7346b19c.pack
fatal: object 0dcf6723cc69cc7f91d4a7432d0f1a1f05e77eaa is corrupted

J'ai des sauvegardes du référentiel, mais la seule sauvegarde qui inclut le fichier pack l'a déjà endommagé. Je pense donc que je dois trouver un moyen de récupérer les objets individuels à partir de différentes sauvegardes et d'une manière ou d'une autre demander à Git de produire un nouveau pack avec uniquement les objets corrects.

Pouvez-vous s'il vous plaît me donner des conseils sur la façon de corriger mon dépôt ?

2 votes

Ça vient de m'arriver. Je ne veux pas m'embrouiller avec les objets git... j'ai donc cloné à nouveau le projet à partir du dépôt distant dans un nouveau dossier, puis j'ai simplement copié tous les fichiers de mes dépôts problématiques (à l'exception du fichier .git bien sûr) dans le repo fraîchement cloné... et a ensuite fait git status dans le nouveau repo... git détecte correctement toutes les modifications affectées à mes fichiers et je peux recommencer mon travail.

1voto

go2null Points 11

Voici deux fonctions qui peuvent vous aider si votre sauvegarde est corrompue, ou si vous avez également quelques sauvegardes partiellement corrompues (cela peut arriver si vous sauvegardez les objets corrompus).

Exécutez les deux dans le repo que vous essayez de récupérer.

Avertissement standard : à n'utiliser que si vous êtes vraiment désespéré et que vous avez sauvegardé votre repo (corrompu). Cela ne résoudra peut-être rien, mais devrait au moins mettre en évidence le niveau de corruption.

fsck_rm_corrupted() {
    corrupted='a'
    while [ "$corrupted" ]; do
        corrupted=$(                                  \
        git fsck --full --no-dangling 2>&1 >/dev/null \
            | grep 'stored in'                          \
            | sed -r 's:.*(\.git/.*)\).*:\1:'           \
        )
        echo "$corrupted"
        rm -f "$corrupted"
    done
}

if [ -z "$1" ]  || [ ! -d "$1" ]; then
    echo "'$1' is not a directory. Please provide the directory of the git repo"
    exit 1
fi

pushd "$1" >/dev/null
fsck_rm_corrupted
popd >/dev/null

et

unpack_rm_corrupted() {
    corrupted='a'
    while [ "$corrupted" ]; do
        corrupted=$(                                  \
        git unpack-objects -r < "$1" 2>&1 >/dev/null \
            | grep 'stored in'                          \
            | sed -r 's:.*(\.git/.*)\).*:\1:'           \
        )
        echo "$corrupted"
        rm -f "$corrupted"
    done
}

if [ -z "$1" ]  || [ ! -d "$1" ]; then
    echo "'$1' is not a directory. Please provide the directory of the git repo"
    exit 1
fi

for p in $1/objects/pack/pack-*.pack; do
    echo "$p"
    unpack_rm_corrupted "$p"
done

0voto

Dmitriy S Points 120

J'ai résolu ce problème en ajoutant quelques changements comme git add -A et git commit à nouveau.

0voto

Developer Points 149

La solution proposée par Daniel Fanjul semblait prometteuse. J'ai pu trouver ce fichier blob et l'extraire ("git fsck --full --no-dangling", "git cat-file -t {hash}", "git show {hash} > file.tmp") mais lorsque j'ai essayé de mettre à jour le fichier pack avec "git hash-object -w file.tmp", il a affiché le hachage correct MAIS l'erreur est restée.

J'ai donc décidé d'essayer une autre approche. Je pouvais simplement supprimer le dépôt local et tout télécharger à distance, mais certaines branches du dépôt local avaient 8 commits d'avance et je ne voulais pas perdre ces changements. Comme ce minuscule fichier mp3 de 6ko, j'ai décidé de le supprimer complètement. J'ai essayé plusieurs méthodes mais la meilleure était celle d'ici : https://itextpdf.com/en/blog/technical-notes/how-completely-remove-file-git-repository

J'ai obtenu le nom du fichier en exécutant cette commande " git rev-list --objects --all | grep {hash} ". Ensuite, j'ai fait une sauvegarde (il est fortement recommandé de le faire car j'ai échoué 3 fois) puis j'ai lancé la commande :

" java -jar bfg.jar --delete-files {nom du fichier} --no-blob-protection . "

Vous pouvez obtenir le fichier bfg.jar en cliquant ici. https://rtyley.github.io/bfg-repo-cleaner/ Donc, selon la documentation, je devrais exécuter cette commande ensuite :

"git reflog expire --expire=now --all && git gc --prune=now --aggressive"

Quand je l'ai fait, j'ai eu des erreurs à la dernière étape. J'ai donc tout récupéré à partir de la sauvegarde et cette fois, après avoir supprimé le fichier, j'ai effectué un checkout vers la branche (qui causait l'erreur), puis un check out vers la branche principale et seulement après avoir exécuté les commandes l'une après l'autre :

"git reflog expire --expire=now --all" "git gc --prune=now --aggressive"

Ensuite, j'ai remis mon fichier à son emplacement et j'ai comité. Cependant, comme de nombreux commits locaux ont été modifiés, je n'ai pas été en mesure de pousser quoi que ce soit vers le serveur. J'ai donc sauvegardé tout ce qui se trouvait sur le serveur (au cas où je me planterais), j'ai fait un check out sur la branche qui était affectée et j'ai lancé la commande " git push --force ".

Ce que j'ai compris de cette affaire ? GIT est génial mais tellement sensible... Je devrais avoir une option pour simplement ignorer un fichier... Fichier de 6kb Je sais ce que je fais. Je ne sais pas pourquoi "git hash-object -w" n'a pas fonctionné non plus =( Leçons apprises, pousser tous les commits, ne pas attendre, faire une sauvegarde du dépôt de temps en temps. Je sais aussi comment supprimer des fichiers du dépôt, si jamais j'en ai besoin =)

J'espère que cela fera gagner du temps à quelqu'un

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X