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

j'ai eu une défaillance du disque dur qui a causé des dommages à certains fichiers d'un dépôt Git. Lors de l'exécution de git fsck --full j'obtiens la sortie suivante:

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 dépôt, mais la seule sauvegarde qui inclut le fichier pack l'a déjà endommagé. Donc je pense que je dois trouver un moyen de récupérer les objets individuels à partir de différentes sauvegardes et d'une certaine façon donner des instructions à Git pour produire un nouveau paquet avec seulement des objets corrects.

pouvez-vous me donner des conseils sur la façon de corriger mon dépôt?

86
demandé sur Christian 2009-04-29 13:21:03

7 réponses

dans certaines sauvegardes précédentes, vos mauvais objets peuvent avoir été emballés dans des fichiers différents ou peuvent être encore des objets en vrac. Pour que vos objets puissent être récupérés.

il semble qu'il y ait quelques mauvais objets dans votre base de données. Donc, vous pourriez faire de la façon manuelle.

à cause de git hash-object , git mktree et git commit-tree n'écrivez pas les objets parce qu'ils se trouvent dans le paquet, alors commencez à faire ceci:

mv .git/objects/pack/* <somewhere>
for i in <somewhere>/*.pack; do
  git unpack-objects -r < $i
done
rm <somewhere>/*

(Vos paquets sont retirés du dépôt, et déballés à nouveau; seuls les bons objets sont maintenant dans la base de données)

Vous pouvez le faire:

git cat-file -t 6c8cae4994b5ec7891ccb1527d30634997a978ee

et vérifiez le type de l'objet.

si le type est blob: récupérer le contenu du fichier à partir de sauvegardes précédentes (avec git show ou git cat-file ou git unpack-file ; alors vous pouvez git hash-object -w pour réécrire l'objet dans votre dépôt courant.

si le type est tree: vous pouvez utiliser git ls-tree pour récupérer l'arbre des sauvegardes précédentes; puis git mktree pour l'écrire à nouveau dans votre dépôt courant.

si le type est commit: la même chose avec git show , git cat-file et git commit-tree .

bien sûr, je voudrais sauvegarder votre copie de travail originale avant de commencer ce processus.

aussi, jetez un oeil à Comment récupérer L'objet corrompu Blob .

78
répondu Daniel Fanjul 2013-05-30 22:04:39

Banengusk me mettait sur la bonne voie. Pour de plus amples informations, je tiens à signaler les mesures que j'ai prises pour corriger la corruption de mon dépôt. J'ai eu la chance de trouver tous les objets nécessaires dans des paquets plus anciens ou dans des sauvegardes de dépôt.

# Unpack last non-corrupted pack
$ mv .git/objects/pack .git/objects/pack.old
$ git unpack-objects -r < .git/objects/pack.old/pack-012066c998b2d171913aeb5bf0719fd4655fa7d0.pack
$ git log
fatal: bad object HEAD

$ cat .git/HEAD 
ref: refs/heads/master

$ ls .git/refs/heads/

$ cat .git/packed-refs 
# pack-refs with: peeled 
aa268a069add6d71e162c4e2455c1b690079c8c1 refs/heads/master

$ git fsck --full 
error: HEAD: invalid sha1 pointer aa268a069add6d71e162c4e2455c1b690079c8c1
error: refs/heads/master does not point to a valid object!
missing blob 75405ef0e6f66e48c1ff836786ff110efa33a919
missing blob 27c4611ffbc3c32712a395910a96052a3de67c9b
dangling tree 30473f109d87f4bcde612a2b9a204c3e322cb0dc

# Copy HEAD object from backup of repository
$ cp repobackup/.git/objects/aa/268a069add6d71e162c4e2455c1b690079c8c1 .git/objects/aa
# Now copy all missing objects from backup of repository and run "git fsck --full" afterwards
# Repeat until git fsck --full only reports dangling objects

# Now garbage collect repo
$ git gc
warning: reflog of 'HEAD' references pruned commits
warning: reflog of 'refs/heads/master' references pruned commits
Counting objects: 3992, done.
Delta compression using 2 threads.
fatal: object bf1c4953c0ea4a045bf0975a916b53d247e7ca94 inconsistent object length (6093 vs 415232)
error: failed to run repack

# Check reflogs...
$ git reflog

# ...then clean
$ git reflog expire --expire=0 --all

# Now garbage collect again
$ git gc       
Counting objects: 3992, done.
Delta compression using 2 threads.
Compressing objects: 100% (3970/3970), done.
Writing objects: 100% (3992/3992), done.
Total 3992 (delta 2060), reused 0 (delta 0)
Removing duplicate objects: 100% (256/256), done.
# Done!
38
répondu Christian 2014-01-07 12:05:20

essayez d'abord les commandes suivantes (relancez si nécessaire):

$ git fsck --full
$ git gc
$ git gc --prune=today
$ git fetch --all
$ git pull --rebase

et puis vous avez encore les problèmes, essayez peut:

  • supprimer tous les objets corrompus, p.ex.

    fatal: loose object 91c5...51e5 (stored in .git/objects/06/91c5...51e5) is corrupt
    $ rm -v .git/objects/06/91c5...51e5
    
  • supprimer tous les objets vides, p.ex.

    error: object file .git/objects/06/91c5...51e5 is empty
    $ find .git/objects/ -size 0 -exec rm -vf "{}" \;
    
  • vérifier un" lien brisé "message par:

    git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
    

    ce testament vous dit de quel fichier provient le blob corrompu!

  • pour récupérer le fichier, vous pourriez être vraiment chanceux, et il se peut que ce soit la version que vous avez déjà vérifié dans votre arbre de travail:

    git hash-object -w my-magic-file
    

    encore une fois, et si elle affiche le SHA1 manquant (4b945.. vous êtes maintenant tout fait!

  • en supposant que c'était une version plus ancienne qui a été cassée, la façon la plus simple de le faire est de faire:

    git log --raw --all --full-history -- subdirectory/my-magic-file
    

    et cela vous montrera tout le log pour ce fichier (s'il vous plaît se rendre compte que l'arbre que vous aviez peut ne pas être l'arbre de haut niveau, donc vous avez besoin de comprendre dans quel sous-répertoire il était sur votre propre), alors vous pouvez maintenant recréer l'objet manquant avec l'objet de hachage à nouveau.

  • pour obtenir une liste de tous les réf avec les commits, arbres ou blobs manquants:

    $ git for-each-ref --format='%(refname)' | while read ref; do git rev-list --objects $ref >/dev/null || echo "in $ref"; done
    

    il ne sera peut-être pas possible de supprimer certains de ces renvois en utilisant les commandes régulières branch-d ou tag-d, car ils mourront si git remarque la corruption. Alors utilisez la commande de plomberie git update-ref-D $ref à la place. Notez que dans le cas de branches locales, cette commande peut laisser la configuration des branches périmées derrière in .git / config. Il peut être supprimé manuellement (voir la [direction "$ref] l'article).

  • après tous les réf sont propres, il peut encore être brisé s'engage dans le reflog. Vous pouvez effacer tous les reflogs en utilisant git reflog expire -- expire=now --all. Si vous ne voulez pas perdre tous vos reflogs, vous pouvez rechercher les références individuelles pour les reflogs cassés:

    $ (echo HEAD; git for-each-ref --format='%(refname)') | while read ref; do git rev-list -g --objects $ref >/dev/null || echo "in $ref"; done
    

    (noter l'option-g ajoutée à git rev-list.) Puis, utilisez git reflog expire --expire=maintenant $ ref sur chacun de ceux-ci. Une fois que tous les réf et reflogs ont disparu, Lancez git fsck --full afin de vérifier que le dépôt est propre. Les objets pendants sont Ok.


ci-dessous, vous pouvez trouver l'utilisation avancée des commandes qui peuvent causer la perte de vos données dans votre dépôt git si elles ne sont pas utilisées à bon escient, alors faites une sauvegarde avant de faire accidentellement d'autres dommages à votre git. Essayez de prendre vos propres risques si vous savez ce que vous faites.


pour tirer la branche courante sur le dessus de la branche en amont après fetching:

$ git pull --rebase

vous pouvez également essayer de vérifier la nouvelle branche et supprimer l'ancienne:

$ git checkout -b new_master origin/master

pour trouver l'objet corrompu dans git pour suppression, essayer la commande suivante:

while [ true ]; do f=`git fsck --full 2>&1|awk '{print }'|sed -r 's/(^..)(.*)/objects\/\//'`; if [ ! -f "$f" ]; then break; fi; echo delete $f; rm -f "$f"; done

pour OSX, utilisez sed -E au lieu de sed -r .


une autre idée est de déballer tous les objets des fichiers pack pour les régénérer tous des objets à l'intérieur .git / objects, essayez donc d'exécuter les commandes suivantes dans votre dépôt:

$ cp -fr .git/objects/pack .git/objects/pack.bak
$ for i in .git/objects/pack.bak/*.pack; do git unpack-objects -r < $i; done
$ rm -frv .git/objects/pack.bak

Si ci-dessus n'aide pas, vous pouvez essayer de rsync ou de copier les objets git à partir d'une autre pension, par exemple

$ rsync -varu git_server:/path/to/git/.git local_git_repo/
$ rsync -varu /local/path/to/other-working/git/.git local_git_repo/
$ cp -frv ../other_repo/.git/objects .git/objects

pour réparer la branche cassée lors de la vérification comme suit:

$ git checkout -f master
fatal: unable to read tree 5ace24d474a9535ddd5e6a6c6a1ef480aecf2625

essayer de l'enlever et de vérifier en amont à nouveau:

$ git branch -D master
$ git checkout -b master github/master

dans le cas où git vous obtenir dans l'état de détachement, vérifiez le master et fusionner en elle la branche détachée.


une autre idée est de reformuler le maître existant récursivement:

$ git reset HEAD --hard
$ git rebase -s recursive -X theirs origin/master

Voir aussi:

14
répondu kenorb 2017-05-23 11:55:01

Voici les étapes que j'ai suivies pour récupérer d'un objet corrompu blob.

1) Identifier les blobs corrompus 151970920"

git fsck --full
  error: inflate: data stream error (incorrect data check)
  error: sha1 mismatch 241091723c324aed77b2d35f97a05e856b319efd
  error: 241091723c324aed77b2d35f97a05e856b319efd: object corrupt or missing
  ...

corrompu blob is 241091723c324aed77b2d35f97a05e856b319efd

2) Déplacer corrompu blob à un endroit sûr (juste au cas)

mv .git/objects/24/1091723c324aed77b2d35f97a05e856b319efd ../24/

3) obtenir parent de corrompu blob

git fsck --full
  Checking object directories: 100% (256/256), done.
  Checking objects: 100% (70321/70321), done.
  broken link from    tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
              to    blob 241091723c324aed77b2d35f97a05e856b319efd

hash Parent est 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180 .

4) de nom de fichier correspondant à corrompre blob

git ls-tree 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180
  ...
  100644 blob 241091723c324aed77b2d35f97a05e856b319efd    dump.tar.gz
  ...

trouver ce fichier particulier dans une sauvegarde ou dans le dépôt git amont (dans mon cas, c'est dump.tar.GZ ). Ensuite, Copiez-le quelque part dans votre dépôt local.

5) Ajouter un fichier déjà corrompu dans la base de données d'objets git

git hash-object -w dump.tar.gz

6) Célébrez!

git gc
  Counting objects: 75197, done.
  Compressing objects: 100% (21805/21805), done.
  Writing objects: 100% (75197/75197), done.
  Total 75197 (delta 52999), reused 69857 (delta 49296)
2
répondu Jonathan Maim 2015-10-30 03:51:51

git checkout peut en fait sélectionner des fichiers individuels à partir d'une révision. Donnez - lui le hachage de propagation et le nom du fichier. Plus d'informations ici.

je suppose que la meilleure façon de corriger cela en toute sécurité est de revenir à la plus récente sauvegarde non engagée et puis sélectionner sélectivement les fichiers non corrompus à partir de nouvelles propagations. Bonne chance!

1
répondu Tim Lin 2009-04-29 10:01:13

voici deux fonctions qui peuvent aider si votre sauvegarde est corrompue, ou vous avez quelques sauvegardes partiellement corrompues ainsi (cela peut se produire si vous sauvegardez les objets corrompus).

exécutez les deux dans la pension que vous essayez de récupérer.

avertissement Standard: utilisez seulement si vous êtes vraiment désespéré et que vous avez sauvegardé votre (corrompu) repo. 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/.*)\).*::'           \
        )
        echo "$corrupted"
        rm -f "$corrupted"
    done
}

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

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

et

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

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

for p in /objects/pack/pack-*.pack; do
    echo "$p"
    unpack_rm_corrupted "$p"
done
1
répondu go2null 2015-11-07 22:34:04

j'ai résolu ce problème pour ajouter un changement comme git add-a et git commit à nouveau.

0
répondu Dmitriy S 2017-03-27 18:38:33