Como consertar o repositório git corrompido?

104

Tentei clonar meu repositório, que mantenho na pasta One do Ubuntu, para uma nova máquina e consegui:

christopher@christopher-laptop:~/source/personal$ git clone ~/Ubuntu\ One\ Side\ Work/projects.git/
Cloning into 'projects'...
done.
fatal: unable to read tree 29a422c19251aeaeb907175e9b3219a9bed6c616
christopher@christopher-laptop:~/source/personal$ 

Então, tentei olhar para as muitas outras perguntas como esta que foram feitas aqui e a maioria delas diz para correr git fsck --fulle eu entendo isso quando tento fazer isso.

christopher@christopher-laptop:~/Ubuntu One Side Work/projects.git$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (447/447), done.
broken link from  commit 235ae1f48701d577d71ebd430344a159e5ba4881
              to  commit 984c11abfc9c2839b386f29c574d9e03383fa589
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    blob 25a742dff0a403b2b3884f2ffddf63eb45721fac
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    blob dd4e97e22e159a585b20e21028f964827d5afa4e
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    tree 29a422c19251aeaeb907175e9b3219a9bed6c616
broken link from    tree 632a9cf0ef9fccea08438b574e2f1c954f4ff08b
              to    tree 8084e8e04d510cc28321f30a9646477cc50c235c
broken link from    tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628
              to    blob a0daa0c1567b55d8de2b4d7a3bc010f58c047eab
broken link from    tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628
              to    blob e9052d35bfb6d30065b206fc43f4200a04d5281b
broken link from    tree 774b5b4157b4caae1c6cad96c8eaf5d4eba2c628
              to    blob 1a3a5e4dd2502ac121c22f743c4250e254a94eeb
broken link from    tree 4aa336dc1a5838e8918e03b85580069d83f4ad09
              to    tree 8cc55ec952dc192a233e062201d1e7e873ac3db0
broken link from    tree e5674a91a53e15575a1f3bf5786bc5cc719fb483
              to    blob 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51
broken link from    tree e5674a91a53e15575a1f3bf5786bc5cc719fb483
              to    blob ac033bf9dc846101320c96a5ce8aceb8c96ec098
broken link from    tree 252ab84542264e1589576b6ee51e7a31e580a0e2
              to    tree 2069041cd5950e529e2991d37b7290ec021d90d4
broken link from    tree 2d4964aa4d4f5d8c7228518ce72ef6a63f820c6d
              to    blob d83690e1b9a6bdd8a08754b38231799acefcb2ab
broken link from    tree c7192e82fc581bd6448bda1a25e8729bdac5f4ff
              to    blob 30d54d47ae82add1917ca173d42e58b396df580b
broken link from    tree 7c66306901fc71389623286936cef172d4ffe408
              to    blob bc7e05d705401273b1df4e939de0f540597c0931
broken link from    tree 0940f5fd227d4c84d6e6749d872db50a4522ae3a
              to    tree 923767594ac22023e824948d65622fe5b407d1a1
broken link from    tree 8eadcd2a971e8357d24f0d80f993d2963452209f
              to    blob 2598bde3dc8cb80ee49510b8159344004b88645f
broken link from    tree ffa302dd0d969172ef23caeefe856ab2f57a4e4d
              to    blob d6925fa431be1ac585bf9a481e98f75107a6e6fb
broken link from    tree 7045b8870a49ce30a2027537a96d73d162bda773
              to    blob 25688652dea26f61f576ca1b52b9d1a18fbfd01d
broken link from    tree 37e4705d34bd440ce681ae32ae9a180a13256d72
              to    tree 246f564d4cee53339b8a4244f3173b61caa518eb
missing blob d6925fa431be1ac585bf9a481e98f75107a6e6fb
missing blob ac033bf9dc846101320c96a5ce8aceb8c96ec098
missing tree 29a422c19251aeaeb907175e9b3219a9bed6c616
missing tree 8084e8e04d510cc28321f30a9646477cc50c235c
missing blob 30d54d47ae82add1917ca173d42e58b396df580b
missing tree 8cc55ec952dc192a233e062201d1e7e873ac3db0
missing blob e9052d35bfb6d30065b206fc43f4200a04d5281b
dangling tree 4b26e95db542c72ac4a22ec25abe38fb2de79752
missing blob d83690e1b9a6bdd8a08754b38231799acefcb2ab
missing blob 25a742dff0a403b2b3884f2ffddf63eb45721fac
missing tree 923767594ac22023e824948d65622fe5b407d1a1
missing blob 25688652dea26f61f576ca1b52b9d1a18fbfd01d
missing blob 2598bde3dc8cb80ee49510b8159344004b88645f
dangling tree 3a683869f1bb0c1634de75700c316b3b36570dbd
dangling blob 4098d30843380d798a811f1aa9a02994f0dbbb27
missing tree 2069041cd5950e529e2991d37b7290ec021d90d4
missing blob 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51
missing blob 1a3a5e4dd2502ac121c22f743c4250e254a94eeb
missing blob a0daa0c1567b55d8de2b4d7a3bc010f58c047eab
dangling tree 6c7b5162aa7a303fa3fe8dc393c5da564e309521
missing commit 984c11abfc9c2839b386f29c574d9e03383fa589
missing blob bc7e05d705401273b1df4e939de0f540597c0931
missing blob dd4e97e22e159a585b20e21028f964827d5afa4e
missing tree 246f564d4cee53339b8a4244f3173b61caa518eb
dangling commit a01f5c1e5315dc837203d6dee00d3493be9c5db9

Isso parece muito ruim. Quando eu faço um, git log | headeu entendo isso

christopher@christopher-laptop:~/Ubuntu One Side Work/projects.git$ git log | head
error: Could not read 984c11abfc9c2839b386f29c574d9e03383fa589
fatal: Failed to traverse parents of commit 235ae1f48701d577d71ebd430344a159e5ba4881
commit 2fb0d2d0643b445440f01b164f11ee9ee71fca48
Author: christopher <[email protected]>
Date:   Wed Aug 7 15:51:42 2013 -0400

    finishing chapter 7

Outras questões aqui disse para olhar ./git/refs/heads/master. É um repositório básico e refs/heads/existe, mas refs/heads/masternão existe . HEAD no repositório básico diz ref: refs/heads/masterembora

packed-refs diz isso embora

# pack-refs with: peeled 
2fb0d2d0643b445440f01b164f11ee9ee71fca48 refs/heads/master

Ainda outras perguntas sugeriram execução git refloge nenhuma saída aparece quando eu executo isso.

Então, eu realmente não tenho ideia do que fazer aqui. Qual estratégia deve ser tomada? É possível resetar a cabeça para este último commit em 7 de agosto

EDITAR:

Fazer um git log e ir para a parte inferior da tela de saída mostra o seguinte:

commit 996e03b949aea176238e3c7a8452700bbb987ac9
Author: christopher <christopher@christopher>
Date:   Wed Jul 3 23:00:44 2013 -0400

    many many changes
error: Could not read 984c11abfc9c2839b386f29c574d9e03383fa589
fatal: Failed to traverse parents of commit 235ae1f48701d577d71ebd430344a159e5ba4881

Isso parece estar impedindo o git prune de funcionar

TinyGrasshopper
fonte
3
Isso não ajuda muito, mas: não armazene repositórios Git no Dropbox ou em qualquer outro serviço de sincronização. O Git não foi construído para lidar com outro programa bloqueando e reescrevendo arquivos aleatoriamente enquanto está fazendo outra coisa.
milimoose
Relacionado: stackoverflow.com/q/18550073/1301972
Todd A. Jacobs
2
Quase todas as respostas assumem que se pode simplesmente clonar novamente de alguma origem remota incorruptível. Aqui está o problema ... E se você for a origem e estiver corrompido? Certo. Então, aqui: git-repairé um programa que será executado git fscke tentará consertar todos os problemas que encontrar. git-repair.branchable.com Parece bastante capaz, e embora você possa acabar tendo que copiar (se puder!) objetos de um backup (você tem um backup, certo?), deve economizar muito tempo ao salvando tudo o que pode e deixando o trabalho real, não muitas tarefas automatizáveis. Sem afiliação, etc.
sublinhado_d

Respostas:

110

Como alternativa à última opção do CodeGnome, se apenas o repositório local estiver corrompido e você souber o url do remoto, pode usar isso para reconfigurar seu .gitpara corresponder ao remoto (substituindo ${url}pelo url remoto):

mv -v .git .git_old &&            # remove old git
git init &&                       # initialise new repo
git remote add origin "${url}" && # link to old repo
git fetch &&                      # get old history
git reset origin/master --mixed   # force update to old history

Isso deixa sua árvore de trabalho intacta e afeta apenas a contabilidade do git.
Recentemente, também fiz um script bash para esse propósito (Apêndice A), que envolve um pouco de segurança em torno dessa operação.

Nota:

Se o seu repo tiver submódulos, esse processo irá bagunçá-los de alguma forma, e a única solução que encontrei até agora é excluí-los e, em seguida, usar git submodule update --init(ou recriar o repo, mas isso parece muito drástico).

Apêndice A - Script completo

#!/bin/bash

# Author: Zoey Llewellyn "Zobean" Hewll
#
# Usage: fix-git [REMOTE-URL]
#   Must be run from the root directory of the repository.
#   If a remote is not supplied, it will be read from .git/config
# 
# For when you have a corrupted local repo, but a trusted remote.
# This script replaces all your history with that of the remote.
# If there is a .git, it is backed up as .git_old, removing the last backup.
# This does not affect your working tree.
#
# This does not currently work with submodules!
# This will abort if a suspected submodule is found.
# You will have to delete them first
# and re-clone them after (with `git submodule update --init`)
#
# Error codes:
# 1: If a url is not supplied, and one cannot be read from .git/config
# 4: If the url cannot be reached
# 5: If a git submodule is detected


if [[ "$(find -name .git -not -path ./.git | wc -l)" -gt 0 ]] ;
then
    echo "It looks like this repo uses submodules" >&2
    echo "You will need to remove them before this script can safely execute" >&2
    echo "Then use \`git submodule update --init\` to re-clone them" >&2
    exit 5
fi

if [[ $# -ge 1 ]] ;
then
    url="$1"
else
    if ! url="$(git config --local --get remote.origin.url)" ;
    then
        echo "Unable to find remote 'origin': missing in '.git/config'" >&2
        exit 1
    fi
fi
url_base="$(echo "${url}" | sed -E 's;^([^/]*://)?([^/]*)(/.*)?$;\2;')"
echo "Attempting to access ${url_base} before continuing"
if ! wget -p "${url_base}" -O /dev/null -q --dns-timeout=5 --connect-timeout=5 ;
then
    echo "Unable to reach ${url_base}: Aborting before any damage is done" >&2
    exit 4
fi

echo
echo "This operation will replace the local repo with the remote at:"
echo "${url}"
echo
echo "This will completely rewrite history,"
echo "but will leave your working tree intact"
echo -n "Are you sure? (y/N): "

read confirm
if ! [ -t 0 ] ; # i'm open in a pipe
then
    # print the piped input
    echo "${confirm}"
fi
if echo "${confirm}"|grep -Eq "[Yy]+[EeSs]*" ; # it looks like a yes
then
    if [[ -e .git ]] ;
    then
        # remove old backup
        rm -vrf .git_old | tail -n 1 &&
        # backup .git iff it exists
        mv -v .git .git_old
    fi &&
    git init &&
    git remote add origin "${url}" &&
    git config --local --get remote.origin.url | sed 's/^/Added remote origin at /' &&
    git fetch &&
    git reset origin/master --mixed
else
    echo "Aborting without doing anything"
fi
Zoey Hewll
fonte
3
Espetacular, fiz um backup do meu projeto e tentei sua solução. Git foi corrompido bastante mal de alguma forma. Tentei sua solução e funcionou perfeitamente, muito obrigado.
kequc 01 de
2
não usei o script porque estou no Windows, mas esses comandos apenas salvaram minha pasta .git que estava mostrando um novo repositório para cada salvamento feito em qualquer arquivo rastreado (então acabei com cerca de 50 repositórios principais antes de tentar esta correção )
ciclomotor
1
Consegui restaurar minha .gitpasta depois de fazer isso. Eu descobri que git reset origin/master --hardera mais útil do que --mixed.
Felipe Alvarez
1
Ótimo. No caso de haver submúdulos que não contenham alterações, remova-os primeiro e depois execute o submódulo init para obtê-los novamente.
herm
1
@ w33haa Infelizmente, esta solução só é aplicável no caso de você ter um repositório remoto válido e acessível. Algumas das outras respostas tratam do caso de um controle remoto inacessível ou corrompido.
Zoey Hewll
53

TL; DR

Git realmente não armazena história da maneira que você pensa. Ele calcula o histórico em tempo de execução com base em uma cadeia de ancestrais. Se faltam blobs, árvores ou commits em seus ancestrais, você pode não conseguir recuperar totalmente seu histórico.

Restaurar objetos ausentes de backups

A primeira coisa que você pode tentar é restaurar os itens ausentes do backup. Por exemplo, veja se você tem um backup do commit armazenado como .git/objects/98/4c11abfc9c2839b386f29c574d9e03383fa589. Nesse caso, você pode restaurá-lo.

Você também pode querer olhar em git-verify-pack e git-unpack-objects no caso de o commit já ter sido empacotado e você deseja devolvê-lo a um objeto solto para fins de cirurgia de repositório.

Ressecção Cirúrgica

Se você não puder substituir os itens ausentes de um backup, poderá eliminar o histórico ausente. Por exemplo, você pode examinar seu histórico ou reflog para encontrar um ancestral do commit 984c11abfc9c2839b386f29c574d9e03383fa589. Se você encontrar um intacto, então:

  1. Copie seu diretório de trabalho Git para um diretório temporário em algum lugar.
  2. Faça um hard reset para o commit não corrompido.
  3. Copie seus arquivos atuais de volta para a árvore de trabalho do Git, mas certifique-se de não copiar a pasta .git de volta!
  4. Faça commit da árvore de trabalho atual e faça o seu melhor para tratá-la como uma confirmação comprimida de todo o histórico ausente.

Se funcionar, você perderá a história intermediária. Neste ponto, se você tem um log de histórico de trabalho, então é uma boa idéia podar seu histórico e reflogs de todos os commits e objetos inacessíveis.

Restaurações completas e reinicialização

Se o seu repositório ainda estiver quebrado, então esperamos que você tenha um backup ou clone não corrompido do qual possa restaurar. Caso contrário, mas seu diretório de trabalho atual contém arquivos válidos, então você sempre pode reinicializar o Git. Por exemplo:

rm -rf .git
git init
git add .
git commit -m 'Re-initialize repository without old history.'

É drástico, mas pode ser sua única opção se o histórico do seu repositório for realmente irrecuperável. YMMV.

Todd A. Jacobs
fonte
3
Acabei de me deparar com esse problema e queria apontá-lo, pois não está em sua resposta, mas meu problema era apenas um simples problema de permissão. error: Could not read abcdeMeu repo é gerenciado pelo GitLab e ele estava criando arquivos que meu usuário não conseguia ler. Um sudo chowndepois e eu estava pronto para ir.
Aust
6

Se você tiver um controle remoto configurado e não se preocupa / não quer perder algum código não enviado, você pode fazer:

git fetch && git reset --hard
user5169648
fonte
2
Em alguns casos, o git não permite que você busque se certos objetos estiverem corrompidos, então você precisa reinicializar seu repo primeiro.
Zoey Hewll
Isso não funcionou para mim quando eu tinha fatal: pack has 13 unresolved deltas.
Artem Russakovskii
5

Aqui está um script (bash) para automatizar a primeira solução por @CodeGnome para restaurar a partir de um backup (executado a partir do nível superior do repo corrompido). O backup não precisa ser concluído, ele só precisa ter os objetos ausentes.

git fsck 2>&1 | grep -e missing -e invalid | awk '{print $NF}' | sort -u |
    while read entry; do
        mkdir -p .git/objects/${entry:0:2}
        cp ${BACKUP}/objects/${entry:0:2}/${entry:2} .git/objects/${entry:0:2}/${entry:2}
    done
Campkeith
fonte
4

Antes de tentar qualquer uma das correções descritas nesta página, aconselho fazer uma cópia do seu repo e trabalhar apenas nesta cópia. Então, no final, se você puder consertá-lo, compare-o com o original para garantir que nenhum arquivo foi perdido no processo de reparo.

Outra alternativa que funcionou para mim foi redefinir o git head e index para seu estado anterior usando:

git reset --keep

Você também pode fazer o mesmo manualmente abrindo a GUI do Git e selecionando cada "Mudanças em estágios" e clicando em "Tirar o estágio da mudança". Quando tudo não estiver encenado, você agora deve ser capaz de compactar seu banco de dados, verificar seu banco de dados e confirmar.

Eu também tentei os seguintes comandos, mas eles não funcionaram para mim, mas podem ser para você, dependendo do seu problema exato:

git reset --mixed
git fsck --full
git gc --auto
git prune --expire now
git reflog --all

Finalmente, para evitar que esse problema de sincronização danifique seu índice git (o que pode acontecer com DropBox, SpiderOak ou qualquer outro disco em nuvem), você pode fazer o seguinte:

  1. Converta sua .gitpasta em um único arquivo git "agrupado" usando :,git bundle create my_repo.git --all então ele deve funcionar da mesma forma que antes, mas como tudo está em um único arquivo, você não correrá mais o risco de a sincronização danificar seu repositório git.
  2. Desabilite a sincronização instantânea : o SpiderOak permite que você defina o agendamento de verificação de alterações para "automático" (o que significa que é o mais rápido possível, monitorando as alterações dos arquivos graças às notificações do SO). Isso é ruim porque ele começará a carregar as alterações assim que você fizer uma alteração e, em seguida, fará o download da alteração, portanto, ele pode apagar as alterações mais recentes que você estava fazendo. Uma solução para corrigir esse problema é definir o atraso de monitoramento de alterações para 5 minutos ou mais. Isso também corrige problemas com aplicativos de anotações para salvar instantaneamente (como o Notepad ++).
gostoso
fonte
3

Se você está desesperado, pode tentar o seguinte:

git clone ssh://[email protected]/path/to/project destination --depth=1

Ele obterá seus dados, mas você perderá o histórico. Fui com tentativa e erro em meu repo e --depth=10funcionou, mas --depth=50me deu um fracasso.

alberto56
fonte
3

Tentei afastar os arquivos-objeto com 0 bytes e buscá-los novamente no controle remoto, e funcionou:

find . -type f -size 0 -exec mv {} /tmp \;
git fetch

Ele buscou os objetos ausentes do controle remoto e me permitiu continuar trabalhando sem reinicializar todo o repositório.

AlejandroVD
fonte
2

Eu estava enfrentando o mesmo problema, então substituí a pasta ".git" por uma versão de backup e ainda não estava funcionando porque o arquivo .gitconfig estava corrompido. O BSOD do meu laptop o corrompeu. Substituí-o pelo seguinte código e o sourcetree restaurou todos os meus repositórios.

[user]
name = *your username*
email = *your email address*
[core]
autocrlf = true
excludesfile = C:\\Users\\*user name*\\Documents\\gitignore_global.txt

Não sei se isso vai ajudar alguém, mas esta é apenas mais uma solução que funcionou para mim.

AspiringCanadian
fonte
2

Remova o índice e reinicie

rm -f .git/index
git reset
Ashfaq
fonte
2

Recentemente, experimentei problemas semelhantes usando o git versão 2.7.1 no Ubuntu 18.04.3. Aqui está como eu fiz:

sudo apt install git-repair
git-repair  # fix a broken git repository
or
git-repair --force  # force repair, even if data is lost
git fsck  # to verify it was fixed

Na maioria das vezes, o processo de recuperação foi bem-sucedido

Jonathan L
fonte
git-repair é de fato uma ferramenta muito útil. Isso me ajudou a recuperar um repositório. O problema com a maioria dos outros métodos é que você perde seus stashes, o que não era uma opção para mim.
Jan Rychter
1

No meu caso, estava criando o repositório a partir do código fonte já no meu pc e apareceu aquele erro. Excluí a pasta .git, fiz tudo de novo e funcionou :)

Carolina
fonte
1

Eu queria adicionar isso como um comentário na resposta incrível de Zoey Hewil acima, mas no momento não tenho representantes suficientes para fazer isso, então tenho que adicioná-lo aqui e dar crédito por seu trabalho: P

Se você estiver usando Poshgit e estiver se sentindo excepcionalmente preguiçoso, você pode usar o seguinte para extrair automaticamente sua URL de sua configuração git e tornar um trabalho fácil ainda mais fácil. Advertências padrão se aplicam sobre como testar isso em uma cópia / backup de seu repositório local primeiro, para o caso de explodir na sua cara.

$config = get-content .git\config
$url = $config -match " url = (?<content>.*)"
$url = $url.trim().Substring(6)
$url

move-item -v .git .git_old;
git init;
git remote add origin "$url";
git fetch;
git reset origin/master --mixed
Gesthemene
fonte
0

Maneira rápida se você tiver uma mudança em seu projeto atual e não quiser perdê-lo, mova seu projeto atual para algum lugar, clone o projeto do github para esta pasta e faça algumas alterações e tente fazer um commit novamente. Ou apenas exclua o repo e clone-o novamente, funcionou para mim.

certilremy
fonte
-2

Este comando funcionou para mim:

$ git reset --mixed 
Sem arrependimentos
fonte