Pergunta

Eu tive uma falha no disco rígido que resultou em alguns arquivos de um repositório Git ficar danificado. Ao executar git fsck --full eu recebo o seguinte resultado:

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

Eu tenho backups do repositório, mas o único backup que inclui o arquivo do pacote tem já danificado. Então eu acho que eu tenho que descobrir uma maneira de recuperar os objetos individuais de backups diferentes e de alguma forma Instrua Git para produzir um novo pacote com apenas objetos corretos.

Você pode por favor me dê sugestões como corrigir meu repositório?

Foi útil?

Solução

Em alguns backups anteriores, seus objetos ruins pode ter sido embalada em arquivos diferentes ou podem ser objetos soltos ainda. Assim, os objetos podem ser recuperados.

Parece que há alguns objetos ruins em sua base de dados. Então, você poderia fazê-lo da maneira manual.

Por causa de git hash-object, git mktree e git commit-tree não escrever os objetos porque eles são encontrados no pacote, em seguida, começar a fazer isso:

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

(Seus pacotes são movidos para fora do repositório, e descompactado novamente nele, só os bons objetos estão agora no banco de dados)

Você pode fazer:

git cat-file -t 6c8cae4994b5ec7891ccb1527d30634997a978ee

e verificar o tipo do objeto.

Se o tipo é blob:. Recuperar o conteúdo do arquivo a partir de backups anteriores (com git show ou git cat-file ou git unpack-file; então você pode git hash-object -w para reescrever o objeto em seu repositório atual

Se o tipo é uma árvore: você poderia usar git ls-tree para recuperar a árvore de backups anteriores; em seguida, git mktree para escrevê-lo novamente em seu repositório atual.

Se o tipo é cometer:. O mesmo com git show, git cat-file e git commit-tree

Claro, eu faria um backup sua cópia de trabalho original antes de iniciar este processo.

Além disso, dê uma olhada em Como recuperar corrompido Blob objeto .

Outras dicas

Banengusk estava me colocando no caminho certo. Para mais referência, eu quero postar os passos que tomou para corrigir o meu corrupção repositório. Eu estava bastante sorte de encontrar todos os objetos necessários, quer em embalagens mais velhos ou em backups do repositório.

# 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!

Tente os seguintes comandos no primeiro (re-executar novamente, se necessário):

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

E então você ainda tem os problemas, tente pode:

  • remover todos os objetos corruptos, por exemplo.

    fatal: loose object 91c5...51e5 (stored in .git/objects/06/91c5...51e5) is corrupt
    $ rm -v .git/objects/06/91c5...51e5
    
  • remover todos os objetos vazios, por exemplo.

    error: object file .git/objects/06/91c5...51e5 is empty
    $ find .git/objects/ -size 0 -exec rm -vf "{}" \;
    
  • verificar a relação da mensagem "quebrado" por:

    git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
    

    Esta vontade diz-lhe o arquivo do blob corrupto veio!

  • para recuperar arquivo, você pode ser muita sorte, e pode ser a versão que você já fez check-out na sua árvore de trabalho:

    git hash-object -w my-magic-file
    

    novamente, e se mostrar o SHA1 falta (4b945 ..) você está agora tudo feito!

  • assumindo que era uma versão mais antiga que foi quebrado, a maneira mais fácil de fazer isso é fazer:

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

    e que irá mostrar-lhe todo o log para esse arquivo (por favor, perceber que a árvore que você teve não pode ser a árvore de nível superior, então você precisa descobrir qual subdiretório foi em em seu próprio país), então você pode agora recriar o objeto falta com hash objeto novamente.

  • para obter uma lista de todas as refs com falta comete, árvores ou blobs:

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

    Pode não ser possível remover alguns desses refs usando o -d ramo regular ou comandos -d tag, uma vez que eles vão morrer se git percebe a corrupção. Portanto, use o git update-ref comando encanamento -d $ ref em vez. Note-se que em caso de agências locais, este comando pode deixar de configuração ramo obsoleto trás em .git / config. Ele pode ser excluído manualmente (olhar para o [ramo "$ ref"] seção).

  • Depois de todos refs são limpos, há ainda pode ser quebrado commits na reflog. Você pode limpar todos os reflogs usando git reflog expirar --expire = agora --all. Se você não quer perder todos os seus reflogs, você pode procurar os juízes individuais para reflogs quebrados:

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

    (Note a opção -g adicionado ao rev-list git.) Em seguida, use git reflog expirar --expire = agora $ ref em cada um deles. Quando todas as refs quebrados e reflogs se foram, executar git fsck --full, a fim de verificar se o repositório é limpo. objetos pendurados são Ok.


Abaixo, você pode encontrar o uso avançado de comandos que potencialmente pode causar perda de seus dados em seu repositório git se não for usado com sabedoria, então faça um backup antes de você acidentalmente fazer mais danos ao seu git. Tente em seu próprio risco se você sabe o que está fazendo.


Para puxar o ramo atual no topo do ramo a montante depois de baixá:

$ git pull --rebase

Você também pode tentar fazer check-out novo ramo e apagar o antigo:

$ git checkout -b new_master origin/master

Para encontrar o objeto corrompido no git para remoção, tente o seguinte comando:

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

Para OSX, o uso sed -E vez de sed -r.


Outra idéia é para descompactar todos os objetos de arquivos do pacote para regenerar todos os objetos dentro .git / objetos, de modo a tentar executar os seguintes comandos dentro de seu repositório:

$ 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

Se acima não ajudar, você pode tentar rsync ou copiar os objetos do git de outro repo, por exemplo.

$ 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

Para corrigir o ramo quebrado ao tentar check-out da seguinte forma:

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

Tente removê-lo e check-out de montante novamente:

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

No caso git você entrar em estado destacado, o checkout da master e fundir-se que o ramo separado.


Outra idéia é rebase do mestre existente de forma recursiva:

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

Veja também:

Aqui estão os passos que eu segui para recuperar um objeto blob corrupto.

1) Identificar blob corrupto

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

Corrupt blob é 241091723c324aed77b2d35f97a05e856b319efd

2) Mova blob corrupto para um lugar seguro (apenas no caso)

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

3) Obter pai de blob corrupto

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

haxixe Pai é 0716831e1a6c8d3e6b2b541d21c4748cc0ce7180 .

4) Obter nome do ficheiro correspondente ao blob corrupto

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

Ver este arquivo específico em um backup ou no repositório git a montante (no meu caso é dump.tar.gz ). Em seguida, copie-o em algum lugar dentro do seu repositório local.

5) Adicionar arquivo previamente corrompido no banco de dados git objeto

git hash-object -w dump.tar.gz

6) Celebrate!

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)

git checkout pode realmente escolher arquivos individuais a partir de uma revisão. Basta dar-lhe o hash e o nome do arquivo cometer. informações mais detalhadas aqui.

Eu acho que a maneira mais fácil de corrigir isso com segurança é reverter para o backup mais recente uncommited e, em seguida, seletivamente escolher arquivos não corrompidos de commits mais recentes. Boa sorte!

Aqui são duas funções que podem ajudar se o backup está corrompido, ou você tem alguns backups parcialmente danificados, bem como (isso pode acontecer se você faça backup os objectos corrompidos).

Executar tanto no repo que você está tentando recuperar.

aviso padrão: use apenas se você está realmente desesperada e você fez backup de seu repo (corrompido). Isto pode não resolve nada, mas pelo menos deve destacar o nível de corrupção.

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

e

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

Eu resolvi este problema adicionar alguma mudança como -A add git e git commit novamente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top