Como 'git pull' comeu meu dever de casa?

51

Eu me sinto como uma criança no escritório do diretor explicando que o cachorro comeu meu dever de casa na noite anterior, mas estou encarando um bug maluco de perda de dados no rosto e não consigo descobrir como isso aconteceu. Eu gostaria de saber como o git poderia comer todo o meu repositório! Eu coloquei git através do espremedor muitas vezes e nunca pisquei. Eu usei-o para dividir um repositório de 20 Gig Subversion em 27 git repos e filtrar o foo deles para desvendar a bagunça e nunca perdi um byte em mim. O reflog está sempre lá para voltar. Desta vez o tapete sumiu!

Do meu ponto de vista, tudo que fiz foi executar git pull e ele nuked meu repositório local inteiro. Não quero dizer que "estraguei a versão com check-out" ou "o ramo em que eu estava" ou algo assim. Quero dizer, a coisa toda se foi.

Aqui está uma captura de tela do meu terminal no incidente:

Deixe-me guiá-lo por isso. Meu prompt de comando inclui dados sobre o reit git atual (usando a implementação vcs_info do prezto) para que você possa ver quando o repositório git desapareceu. O primeiro comando é normal:

  » caleb » jaguar » ~/p/w/incil.info » ◼  zend ★ »
❯❯❯ git co master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

Lá você pode ver que eu estava na ramificação 'zend' e verifiquei o mestre. Por enquanto, tudo bem. Você verá no prompt antes do próximo comando que ele alternou com sucesso:

  » caleb » jaguar » ~/p/w/incil.info » ◼  master ★ »
❯❯❯ git pull
remote: Counting objects: 37, done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 37 (delta 25), reused 0 (delta 0)
Unpacking objects: 100% (37/37), done.
From gitlab.alerque.com:ipk/incil.info
 + 7412a21...eca4d26 master     -> origin/master  (forced update)
   f03fa5d..c8ea00b  devel      -> origin/devel
 + 2af282c...009b8ec verse-spinner -> origin/verse-spinner  (forced update)
First, rewinding head to replay your work on top of it...
>>> elapsed time 11s

E assim acabou. O marcador de tempo decorrido é emitido antes do próximo prompt, se mais de 10 segundos tiverem decorrido. O Git não deu nenhuma saída além do aviso de que estava rebobinando para reproduzir. Nenhuma indicação de que terminou.

O próximo prompt não inclui dados sobre o ramo em que estamos ou o estado do git.

Não percebi que tinha falhado Eu inconscientemente tentei executar outro comando git apenas para me dizer que eu não estava em um repositório git. Observe que o PWD não mudou:

  » caleb » jaguar » ~/p/w/incil.info »
❯❯❯ git fetch --all
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

Depois disso, uma olhada ao redor mostrou que eu estava em um diretório completamente vazio. Nada. Nenhum diretório '.git', nada. Vazio.

Meu git local está na versão 2.0.2. Aqui estão algumas dicas da minha configuração do git que podem ser relevantes para entender o que aconteceu:

[branch]
        autosetuprebase = always
        rebase = preserve
[pull]
        rebase = true
[rebase]
        autosquash = true
        autostash = true
[alias]
        co = checkout

Por exemplo, tenho git pull definido para sempre fazer um rebase em vez de uma mesclagem, para que parte da saída acima seja normal.

Eu posso recuperar os dados. Eu não acho que houvesse objetos git além de alguns stashes sem importância que não foram empurrados para outros repositórios, mas eu gostaria de saber o que aconteceu .

Eu verifiquei:

  • Mensagens no dmesg ou no diário do systemd. Nada nem remotamente relevante.
  • Não há indicação de falha no drive ou no sistema de arquivos (todos os LVM + LUKS + EXT4 parecem normais). Não há nada em perdido + encontrado.
  • não corri mais nada. Não há nada na história que eu não esteja mostrando acima, e nenhum outro terminal foi usado durante esse tempo. Não existem comandos rm flutuando que possam ter sido executados no CWD errado, etc.
  • Picar outro repositório git em outro diretório não mostra nenhuma anormalidade aparente executando git pull s.

O que mais eu devo procurar aqui?

    
por Caleb 24.07.2014 / 11:33

4 respostas

1

Sim, git minha lição de casa. Tudo isso.

Eu fiz uma imagem dd deste disco após o incidente e mexi com ele mais tarde. Reconstruindo a série de eventos dos logs do sistema, deduzo o que aconteceu foi algo assim:

  1. Um comando de atualização do sistema ( pacman -Syu ) foi emitido dias antes deste incidente.
  2. Uma indisponibilidade de rede estendida fez com que fosse necessário tentar novamente o download de pacotes. Frustrado com a falta de internet, eu coloquei o sistema para dormir e fui para a cama.
  3. Dias depois, o sistema foi ativado e começou a encontrar e fazer o download de pacotes novamente.
  4. O download do pacote terminou em algum momento pouco antes de eu estar mexendo com esse repositório.
  5. A instalação do sistema glibc foi atualizada após o git checkout e antes do git pull .
  6. O binário git foi substituído após o git pull iniciado e antes de ser concluído.
  7. E no sétimo dia, git descansou de todos os seus trabalhos. E deletou o mundo para que todo mundo tivesse que descansar também.

Eu não sei exatamente qual condição de corrida ocorreu que fez isso acontecer, mas a troca de binários no meio de uma operação certamente não é boa, nem uma condição testável / repetível. Normalmente, uma cópia de um binário em execução é armazenada na memória, mas git é estranho e alguma coisa sobre a maneira como ele reproduz versões de si mesmo que, com certeza, levaram a essa bagunça. Obviamente, deveria ter morrido em vez de destruir tudo, mas foi o que aconteceu.

    
por 01.08.2018 / 15:52
1

Com sorte, você pode corrigir isso com o seguinte comando:

git reset --hard ORIG_HEAD  

Quando possíveis alterações perigosas começam, o git armazena seu estado atual em ORIG_HEAD. Com ele você pode desfazer uma mesclagem ou rebase.

Manual do Git: Como desfazer uma mesclagem

    
por 23.08.2014 / 21:30
1

Possivelmente, ao falhar na definição do caminho do arquivo a ser excluído.

Seu case me lembrou um dia lindo que quando meu método caseiro remove(path) tentou remover a pasta raiz porque o parâmetro fornecido era uma string vazia que o sistema operacional corrigiu (!) como pasta raiz.

Isso pode ser um bug git similar. Tal que:

  1. O comando Rebase queria excluir um arquivo como remove(project_folder + file_path) (pseudo code)
  2. De alguma forma, file_path estava vazio no momento.
  3. Comando avaliado como algo como remove(project_folder)
por 29.08.2015 / 17:52
-1

Parece que alguém executou git push --force neste repo e você baixou essas alterações. Tente clonar o repositório de novo, que deve colocá-lo novamente em um estado de trabalho limpo.

    
por 21.08.2014 / 22:49