Git submódulo cabeça ‘referência não é uma tree’ erro

Eu tenho um projeto com um submódulo que está apontando para um commit inválido: o submódulo commit permaneceu local e quando eu tento buscá-lo de outro repo eu recebo:

$ git submodule update fatal: reference is not a tree: 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 Unable to checkout '2d7cfbd09fc96c04c4c41148d44ed7778add6b43' in submodule path 'mysubmodule' 

Eu sei o que o submódulo HEAD deve ser, existe alguma maneira que eu possa mudar isso localmente, sem empurrar a partir do 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 que tem cometer 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 ?

Não tenho certeza se estou sendo claro … aqui está uma situação semelhante que encontrei.

Assumindo que o repository do submódulo contém uma consolidação que você deseja usar (diferentemente do commit referenciado a partir do estado atual do superprojeto), existem duas maneiras de fazê-lo.

O primeiro requer que você já saiba o commit do submódulo que você deseja usar. Ele funciona de dentro para fora, ajustando diretamente o submódulo e atualizando o superprojeto. O segundo trabalha a partir do “outside, in”, encontrando o commit do superprojeto que modificou o submódulo e, em seguida, redefiniu o índice do superprojeto para se referir a um submódulo diferente.

De dentro para fora

Se você já sabe qual commit deseja usar o submódulo, cd para o submódulo, verifique o commit desejado, então git add e git commit volta no superprojeto.

Exemplo:

 $ git submodule update fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556 Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub' 

Ops, alguém fez um commit de superprojeto que se refere a um commit não publicado no submódulo sub . De alguma forma, já sabemos que queremos que o submódulo esteja em commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c . Vá lá e confira diretamente.

Checkout no Submódulo

 $ cd sub $ git checkout 5d5a3ee314476701a20f2c6ec4a53f88d651df6c Note: moving to '5d5a3ee314476701a20f2c6ec4a53f88d651df6c' which isn't a local branch If you want to create a new branch from this checkout, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b  HEAD is now at 5d5a3ee... quux $ cd .. 

Como estamos verificando um commit, isso produz um HEAD separado no submódulo. Se você quiser ter certeza de que o submódulo está usando um branch, então use git checkout -b newbranch para criar e finalizar um branch no commit ou checkout do branch que você quer (por exemplo, um com o commit desejado na ponta ).

Atualize o superprojeto

Um checkout no submódulo é refletido no superprojeto como uma mudança na tree de trabalho. Então, precisamos encenar a mudança no índice do super-projeto e verificar os resultados.

 $ git add sub 

Verifique os resultados

 $ git submodule update $ git diff $ git diff --cached diff --git c/sub i/sub index e47c0a1..5d5a3ee 160000 --- c/sub +++ i/sub @@ -1 +1 @@ -Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556 +Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c 

A atualização do submódulo ficou em silêncio porque o submódulo já está na confirmação especificada. O primeiro diff mostra que o índice e a worktree são os mesmos. O terceiro diff mostra que a única mudança preparada está movendo o submódulo para um commit diferente.

Commit

 git commit 

Isso confirma a input do submódulo corrigido.


De fora para dentro

Se você não tem certeza de qual commit deve usar no submódulo, pode ver o histórico do superprojeto para orientá-lo. Você também pode gerenciar a redefinição diretamente do superprojeto.

 $ git submodule update fatal: reference is not a tree: e47c0a16d5909d8cb3db47c81896b8b885ae1556 Unable to checkout 'e47c0a16d5909d8cb3db47c81896b8b885ae1556' in submodule path 'sub' 

Esta é a mesma situação acima. Mas desta vez vamos nos concentrar em consertá-lo a partir do superprojeto em vez de mergulhar no submódulo.

Encontre o commit errante do super-projeto

 $ git log --oneline -p -- sub ce5d37c local change in sub diff --git a/sub b/sub index 5d5a3ee..e47c0a1 160000 --- a/sub +++ b/sub @@ -1 +1 @@ -Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c +Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556 bca4663 added sub diff --git a/sub b/sub new file mode 160000 index 0000000..5d5a3ee --- /dev/null +++ b/sub @@ -0,0 +1 @@ +Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c 

OK, parece que correu mal no ce5d37c , por isso vamos restaurar o submódulo do seu pai ( ce5d37c~ ).

Alternativamente, você pode pegar o submódulo commit do texto do patch ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c ) e usar o processo “inside out” acima.

Checkout no super-projeto

 $ git checkout ce5d37c~ -- sub 

Isso redefiniu a input do submódulo de sub para o que estava em commit ce5d37c~ no superprojeto.

Atualize o Submódulo

 $ git submodule update Submodule path 'sub': checked out '5d5a3ee314476701a20f2c6ec4a53f88d651df6c' 

A atualização do submódulo foi OK (indica um HEAD separado).

Verifique os resultados

 $ git diff ce5d37c~ -- sub $ git diff $ git diff --cached diff --git c/sub i/sub index e47c0a1..5d5a3ee 160000 --- c/sub +++ i/sub @@ -1 +1 @@ -Subproject commit e47c0a16d5909d8cb3db47c81896b8b885ae1556 +Subproject commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c 

O primeiro diff mostra que sub é agora o mesmo em ce5d37c~ . O segundo diff mostra que o índice e a worktree são os mesmos. O terceiro diff mostra que a única mudança preparada é mover o submódulo para um commit diferente.

Commit

 git commit 

Isso confirma a input do submódulo corrigido.

tente isto:

 git submodule sync git submodule update 

Este erro pode significar que um commit está faltando no submódulo. Ou seja, o repository (A) possui um submódulo (B). A quer carregar B para que esteja apontando para um certo commit (em B). Se esse commit estiver faltando, você receberá esse erro. Uma vez causa possível: a referência ao commit foi enviada em A, mas o commit atual não foi empurrado de B. Então eu começaria lá.

Menos provável, há um problema de permissions, e o commit não pode ser obtido (possível se você estiver usando o git + ssh).

Certifique-se de que os caminhos do submódulo tenham boa aparência em .git / config e .gitmodules.

Uma última coisa para tentar – dentro do diretório do sub-módulo: git reset HEAD –hard

Possível causa

Isso pode acontecer quando:

  1. Submódulo (s) foram editados no local
  2. Submódulo (s) commitado (s), que atualiza o hash do submódulo sendo apontado para
  3. Submódulo (s) não pressionado (s).

Por exemplo, algo assim aconteceu:

 $ cd submodule $ emacs my_source_file # edit some file(s) $ git commit -am "Making some changes but will forget to push!" 

Deve ter submódulo empurrado neste momento.

 $ cd .. # back to parent repository $ git commit -am "updates to parent repository" $ git push origin master 

Como resultado, as confirmações ausentes não poderiam ser encontradas pelo usuário remoto porque ainda estão no disco local.

Solução

Informa a pessoa que modificou o submódulo para empurrar, ou seja,

 $ cd submodule $ git push 

Isso também pode acontecer quando você tem um submódulo apontando para um repository que foi rebaseado e o commit dado “sumiu”. Enquanto o commit ainda pode estar no repository remoto, ele não está em um branch. Se você não puder criar uma nova ramificação (por exemplo, não seu repository), você terá que atualizar o superprojeto para apontar para uma nova confirmação. Alternativamente, você pode enviar uma de suas cópias dos submódulos em outro lugar e, em seguida, atualizar o superprojeto para apontar para esse repository.

Eu recebi este erro quando fiz:

 $ git submodule update --init --depth 1 

mas o commit no projeto pai estava apontando para um commit anterior.
Excluindo a pasta do submódulo e executando

 $ git submodule update --init 

NÃO resolveu o problema. Eu deletei o repository e tentei novamente sem o sinalizador de profundidade e funcionou.

Esta resposta é para usuários do SourceTree com experiência de terminal limitado.

Abra o submódulo problemático dentro do projeto Git (super-projeto).

Buscar e garantir que “Buscar todas as tags” esteja marcado.

Rebase puxar seu projeto Git.

Isso resolverá o problema da “referência não é uma tree” em nove de dez vezes. Aquela 1 vez não, é uma correção terminal como descrito pela resposta principal.

Seu histórico de submódulos é preservado com segurança no submódulo git.

Então, por que não apenas excluir o submódulo e adicioná-lo novamente?

Caso contrário, você tentou editar manualmente o HEAD ou o refs/master/head no submódulo .git

Só para ter certeza, tente atualizar seus binários git .

O GitHub for Windows possui a versão git version 1.8.4.msysgit.0 que no meu caso foi o problema. A atualização resolveu isso.

No meu caso, nenhuma resposta acima resolve o problema, mesmo que sejam boas respostas. Então eu posto minha solução (no meu caso existem dois clientes git, cliente A e B):

  1. vá para o diretório do submódulo:

     cd sub 
  2. checkout para master:

     git checkout master 
  3. rebase para um código de commit que ambos clientes podem ver

  4. volte para o diretório dos pais:

  5. comprometer-se a dominar

  6. mude para o outro cliente, faça o rebase novamente.

  7. finalmente funciona bem agora! Talvez perca alguns commits mas funciona.

  8. FYI, não tente remover o seu submódulo, ele permanecerá .git/modules lá e não poderá ler este submódulo novamente, a menos que seja reativo local.

Para sincronizar o repository do git com a cabeça do submódulo, caso seja realmente o que você quer, descobri que remover o submódulo e, em seguida, lê-lo evita o uso do histórico. Infelizmente, a remoção de um submódulo requer hacking, em vez de ser um único comando git, mas factível.

Etapas que segui para remover o submódulo, inspiradas em https://gist.github.com/kyleturner/1563153 :

  1. Executar git rm – cacheado
  2. Exclua as linhas relevantes do arquivo .gitmodules.
  3. Exclua a seção relevante de .git / config.
  4. Exclua os arquivos submódulos agora não rastreados.
  5. Remova o diretório .git / modules /

Novamente, isso pode ser útil se tudo o que você quer é apontar a cabeça do submódulo novamente, e você não complicou as coisas, precisando manter a cópia local do submódulo intacta. Ele assume que você tem o submódulo “direito” como seu próprio repository, onde quer que seja a origem dele, e você só quer voltar a incluí-lo corretamente como um submódulo.

Nota: sempre faça uma cópia completa do seu projeto antes de se envolver nesses tipos de manipulação ou qualquer comando git além de simples commit ou push. Eu aconselho isso com todas as outras respostas também, e como uma diretriz geral.

Apenas tropeçou neste problema, e nenhuma dessas soluções funcionou para mim. O que acabou sendo a solução para o meu problema é muito mais simples: atualizar o Git. O meu foi 1.7.1, e depois que eu atualizei para 2.16.1 (mais recente), o problema foi embora sem deixar rasto! Acho que estou deixando aqui, espero que ajude alguém.