Navegue por commits órfãos no Git

102

Meu repositório git de alguma forma ficou instável - carreguei o msysgit esta manhã e em vez de o nome do branch ser mostrado após o diretório atual, ele diz "((ref: re ...))", 'git status' relata tudo como um novo arquivo, 'git log' e 'git reflog' me dizem "fatal: revisão padrão inválida 'HEAD'" e assim por diante.

Fazer 'git reflog --all' ou 'gitk --all' mostra que o resto do repositório está intacto, mas parece que o branch em que eu estava trabalhando simplesmente desapareceu, o que explica por que HEAD parece não existir / apontar para qualquer coisa.

Eu sei que o git mantém controle de todos os tipos de informações, e estou assumindo que meus commits ficaram órfãos de alguma forma, então existe algum comando que vai me mostrar esses commits para que eu possa redefinir HEAD para eles?

EDIT: Oh querido. Eu descobri 'git fsck' e 'git fsck --full' reporta "fatal: objeto 03ca4 ... está corrompido". O que diabos posso fazer sobre isso?

EDIT: Oh querido, querido. Eu verifiquei outro branch e tentei recriar o branch original com o mesmo nome usando 'git checkout -b lostbranchname' e git diz "erro: não foi possível resolver referência refs / heads / lostbranchname: Sem erro, fatal: Falha para bloquear ref para atualização: Sem erro ". 'Nenhum erro' deve ser um erro particularmente desagradável. Portanto, parece que ainda está por aí, mas incapaz de ser usado e incapaz de ser morto.

EDIT: Super duper oh querido. Eu fiz um monte de desempacotamento, reembalagem e substituição de coisas como sugerido aqui: Como recuperar objetos Git danificados por falha no disco rígido? , mas agora estou recebendo outro hash relatado como corrompido, para algo tão inócuo como 'status git'. Acho que a coisa toda está bloqueada. Git é adorável e tudo, mas eu não deveria ter que lidar com esse tipo de coisa.

Ben Hymers
fonte
Em relação git checkout -b lostbranchname- se você só se preocupa com o nome do branch (não com o conteúdo dele), você pode excluí-lo (ou renomear) manualmente .git/refs/heads/lostbranchname- esperançosamente, isso resolverá o problema.
Antony Hatchkins
1
E você não tem um upstream para onde enviar essa pasta git?
Lakshman Prasad
1
Infelizmente não, na verdade é uma espécie de repositório substituto para um sistema de controle de origem inferior, estou apenas usando-o localmente para obter todos os recursos e sutilezas do git sem o incômodo do outro sistema. Mas pelo menos o outro sistema não se corrompe aleatoriamente. Ainda assim, isso significa que tudo que perdi foram minhas alterações desde a última vez que fiz check-in no outro sistema, que já recuperei. É hora de iniciar um novo repositório!
Ben Hymers
7
Eu hesitaria em dizer que o git fez você "lidar com esse tipo de coisa" ou que se corrompeu. Nada além de um backup pode ser completamente estável contra perda de dados.
Cascabel
1
Eu sei, estou (naturalmente) um pouco chateado por ter perdido minha linda história. Não é culpa do git, qualquer outro sistema se comportaria com os mesmos erros do sistema de arquivos.
Ben Hymers de

Respostas:

134

Em vez de deixar isso em aberto, acho que darei uma resposta à minha própria pergunta. Usar git reflog --allé uma boa maneira de navegar pelos commits órfãos - e usar os hashes SHA1 deles você pode reconstruir o histórico.

No meu caso, porém, o repositório foi corrompido, então isso não ajudou; git fsckpode ajudá-lo a encontrar e às vezes corrigir erros no próprio repositório.

Ben Hymers
fonte
3
Obrigado. Este é o único lugar em que encontrei essas informações ao tentar puxar uma solicitação de pull órfã no github. Resolveu meu problema.
SystemParadox
6
no caso de alguém querer tudo no gitk: [alias] orphank = !gitk --all --date-order ``git reflog | cut -c1-7``&(editar: imagine aqueles crases duplos em que os únicos - escapar não parece funcionar aqui)
mbx
1
Dica incrível @mbx! Muito útil poder ver os links entre commits órfãos graficamente!
Ben Hymers de
@BenHymers Seria legal se pudéssemos obter linhas pontilhadas para relações de commit do tipo "rebase / squash" também. Eu ainda não encontrei uma maneira de fazer isso.
mbx de
Eu não sabia sobre reflog quando escrevi a resposta acima. É uma ferramenta muito útil!
Jamey Hicks
17

Com git 2.9.x / 2.10 (Q3 2016), você não terá que usar git reflog --all mais,git reflog será o suficiente.

Ver commit 71abeb7 (03 jun 2016) de SZEDER Gábor ( szeder) .
(Incorporado por Junio ​​C Hamano - gitster- no commit 7949837 , 06 de julho de 2016)

reflog: continue caminhando o reflog últimos commits de root

Se um repositório contém mais de um commit root, então seu reflog HEAD pode conter múltiplos "eventos de criação", ou seja, entradas cujo valor "de" é sha1 nulo.
Listar tal reflog atualmente para prematuramente na primeira dessas entradas, mesmo quando o reflog ainda contém entradas mais antigas.
Isso pode assustar os usuários e fazê-los pensar que seu reflog ficou truncado após 'git checkout --orphan '.

Continue percorrendo o reflog passando por tais eventos de criação com base no "novo" valor da entrada do reflog anterior.

VonC
fonte
4

Um bom recurso do git é que ele detecta corrupção. No entanto, não inclui correção de erros para proteger contra corrupção.

Espero que você tenha enviado o conteúdo deste repositório para outra máquina ou que tenha backups para recuperar as partes corrompidas.

Não tenho nenhuma experiência com git no windows, mas nunca vi esse tipo de comportamento com git no Linux ou OS X.

Jamey Hicks
fonte
3

Normalmente acho a git reflogsaída confusa. É muito mais fácil para mim entender um gráfico de confirmação do git log --graph --reflog. Substituir o formato para mostrar apenas resumos de commits também pode tornar o gráfico mais fácil de seguir:

$ git alias graph "log --graph --all --format='%h %s%n        (%an, %ar)%d' --abbrev-commit
$ git graph --reflog

* f06abeb Add feature
|         (Sue Dakota, 4 days ago) (HEAD -> master)
* f126291 Fix the build
|         (Oski M. Wizard, 5 days ago) (origin/master, master)
* 3c4fb9c Break the build
|         (Alyssa P. Hacker, 5 days ago)
| * e3124bf fixup! More work for feature
| |         (Sue Dakota, 4 days ago)
| | * 6a7a52e Lost commit
| |/          (Sue Dakota, 4 days ago)
| * 69d9438 More work for feature
| |         (Sue Dakota, 2 weeks ago)
| * 8f69aba Initial work for feature
|/          (Sue Dakota, 3 weeks ago)
* d824fa9 Fix warnings from the linter
|         (Theo Ristudent, 4 weeks ago)
* 9f782b8 Fix tests flakes
|         (Tess Driven, 5 weeks ago)

Disto está claro que e3124bfe 6a7a52esão órfãos não referenciados, e há contexto de seus commits ancestrais.

Jamesdlin
fonte
Me salvou horas de trabalho perdido agora mesmo! excluiu acidentalmente um branch local que tinha commits não enviados, git reflog --allnão os mostra, com git log --graph --reflogeles eram muito visíveis ...
Adam.Er8