Error de 'referencia no es un árbol' en la cabeza del submódulo de Git


305

Tengo un proyecto con un submódulo que apunta a una confirmación no válida: la confirmación del submódulo permaneció local y cuando trato de recuperarlo de otro repositorio obtengo:

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

Yo sé lo que el submódulo CABEZA debe ser, ¿hay alguna manera de cambiar esta forma local, sin empujar desde el repositorio que hace han comprometerse 2d7cfbd09fc96c04c4c41148d44ed7778add6b43?

No estoy seguro si estoy siendo claro ... aquí hay una situación similar que encontré.


11
"fatal: la referencia no es un árbol" en referencia a los submódulos parece que generalmente significa que el compromiso del submódulo que el repositorio principal espera que aún no se haya presionado, o que esté arruinado de alguna otra manera. Para nosotros, este mensaje de error confuso se resolvió simplemente presionando un submódulo que alguien olvidó presionar.
Chris Moschini

1
@ChrisMoschini - Acabo de tener ese problema, y ​​esa fue mi "solución", presioné y saqué el repositorio principal, pero olvidé enviar mi último compromiso al repositorio del submódulo. ¡Gracias!
Rotem

Tal vez se olvidó de impulsar las últimas confirmaciones de submódulos
Hafenkranich el

Respuestas:


378

Suponiendo que el repositorio del submódulo contiene un compromiso que desea usar (a diferencia del compromiso al que se hace referencia desde el estado actual del superproyecto), hay dos formas de hacerlo.

El primero requiere que ya conozca la confirmación del submódulo que desea usar. Funciona desde adentro hacia afuera ajustando directamente el submódulo y luego actualizando el superproyecto. El segundo funciona desde el "afuera, adentro" al encontrar la confirmación del superproyecto que modificó el submódulo y luego restablecer el índice del superproyecto para referirse a una confirmación de submódulo diferente.

De adentro hacia afuera

Si ya sabe qué confirmación desea que use el submódulo, cden el submódulo, verifique la confirmación que desea, git addy luego git commitvuelva al superproyecto.

Ejemplo:

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

Vaya, alguien realizó una confirmación de superproyecto que se refiere a una confirmación no publicada en el submódulo sub. De alguna manera, ya sabemos que queremos que el submódulo esté en commit 5d5a3ee314476701a20f2c6ec4a53f88d651df6c. Ve allí y échale un vistazo directamente.

Pagar en el 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 <new_branch_name>
HEAD is now at 5d5a3ee... quux
$ cd ..

Como estamos revisando un commit, esto produce un HEAD separado en el submódulo. Si desea asegurarse de que el submódulo esté usando una rama, use git checkout -b newbranch <commit>para crear y pagar una rama en la confirmación o retirar la rama que desea (por ejemplo, una con la confirmación deseada en la punta).

Actualizar el superproyecto

Un pago en el submódulo se refleja en el superproyecto como un cambio en el árbol de trabajo. Por lo tanto, debemos organizar el cambio en el índice del superproyecto y verificar los resultados.

$ git add sub

Verifica los 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

La actualización del submódulo fue silenciosa porque el submódulo ya está en la confirmación especificada. La primera diferencia muestra que el índice y el árbol de trabajo son iguales. El tercer diferencial muestra que el único cambio por etapas es mover el subsubmódulo a una confirmación diferente.

Cometer

git commit

Esto confirma la entrada de submódulo arreglado.


De fuera hacia dentro

Si no está seguro de qué confirmación debe usar desde el submódulo, puede ver el historial en el superproyecto para guiarlo. También puede administrar el reinicio directamente desde el superproyecto.

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

Esta es la misma situación que la anterior. Pero esta vez nos centraremos en solucionarlo desde el superproyecto en lugar de sumergirnos en el submódulo.

Encuentra el compromiso errante del superproyecto

$ 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 salió mal ce5d37c, así que restauraremos el submódulo desde su padre ( ce5d37c~).

Alternativamente, puede tomar la confirmación del submódulo del texto del parche ( 5d5a3ee314476701a20f2c6ec4a53f88d651df6c) y utilizar el proceso anterior "adentro, afuera" en su lugar.

Pagar en el Superproyecto

$ git checkout ce5d37c~ -- sub

Esto restableció la entrada del submódulo para sublo que estaba en commit ce5d37c~en el superproyecto.

Actualice el submódulo

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

La actualización del submódulo salió bien (indica un HEAD separado).

Verifica los 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

La primera diferencia muestra que subahora es lo mismo en ce5d37c~. El segundo diferencial muestra que el índice y el árbol de trabajo son iguales. El tercer diferencial muestra que el único cambio por etapas es mover el subsubmódulo a una confirmación diferente.

Cometer

git commit

Esto confirma la entrada de submódulo arreglado.


En el enfoque "Afuera, adentro", ¿podría aclarar por qué "parece que salió mal en ce5d37c?" ¿Qué dedos ese como el malo cometer?
Garrett Albright

55
@Garrett: La suposición es e47c0auna confirmación que no existe en el repositorio local sub, pero los subpuntos del superproyecto apuntan a esa confirmación. Esto podría haber sucedido porque alguien más creó e47c0aen su copia de sub, actualizó su superproyecto para apuntar a esa confirmación y empujó el superproyecto sin empujar e47c0aal repositorio central / compartido para sub. Cuando nos retiramos de la compartida super-proyecto / centro obtenemos una confirmación de que los puntos suba e47c0a, pero no podemos “ver” que cometió. ce5d37ces sospechoso porque, en base a la diferencia, se introdujo e47c0a.
Chris Johnsen

Todavía se deja bastante vago dónde está el hash específico del subrepositorio principal que lo tiene como submódulo, y si se puede manipular directamente o no directamente al HEAD actual sub, sin depender de un estado anterior del padre repo, que no siempre puede ayudar.
matanster


187

prueba esto:

git submodule sync
git submodule update

2
Desafortunadamente, no para mí, uno de nuestros submódulos fue el objetivo del repositorio principal de git con un comando de agregar, ahora tiene problemas para deshacerlo
Daniel

99
A mí también me funcionó. Sin embargo, me encantaría saber por qué.
BenBtg

12
Resulta que hacer un git submodule synces necesario en escenarios donde la URL del control remoto para un submódulo dado ha cambiado. En nuestro caso, agregamos nuestro submódulo desde un repositorio público y luego cambiamos la URL a una bifurcación privada, y nos metimos en este encurtido particular.
Samscam

Por ejemplo: tenía un repositorio (A) configurado con un submódulo apuntando a mi repositorio github (B). Creé una rama en el repositorio A porque quería señalar B en el repositorio github de otra persona. Después de luchar un poco con eso y comprometer la rama, cambié mi repositorio A de nuevo a maestro y tuve este problema con el repositorio B. La solución de @Lonre Wang lo arregló.
fbicknel

2
Suponiendo que nadie REALMENTE se equivocó (en cuyo caso necesitaría una excelente respuesta de Chris Johnsen), la respuesta de Lonre Wang debería solucionar el problema, ... A MENOS QUE sus submódulos tengan submódulos propios (y el problema está dentro de un submódulo). En ese caso, necesita cd en el submódulo que tiene el submódulo con el problema y ejecutar los comandos anteriores. Tenga en cuenta que la actualización tiene una opción --recursive (actualización de submódulo git --recursive), pero la sincronización no; realmente tiene que ejecutar manualmente 'git submodule sync' dentro del submódulo que tiene el problemático sub (sub) módulo. Este fue mi problema;).
Carlo Wood

16

Este error puede significar que falta una confirmación en el submódulo. Es decir, el repositorio (A) tiene un submódulo (B). A quiere cargar B para que apunte a un determinado commit (en B). Si esa confirmación falta de alguna manera, obtendrá ese error. Una vez posible causa: la referencia al commit fue empujada en A, pero el commit real no fue empujado desde B. Entonces comenzaría allí.

Es menos probable que haya un problema de permisos, y el commit no se puede extraer (posible si está utilizando git + ssh).

Asegúrese de que las rutas de submódulo se vean bien en .git / config y .gitmodules.

Una última cosa para probar: dentro del directorio de submódulos: git reset HEAD --hard


3
Ya expliqué que en la pregunta ... la pregunta en sí era cómo resolverlo. Y ya se ha respondido con éxito hace casi dos años ... Los permisos no tienen nada que ver con esto.
Mauricio Scheffer

1
Lo dijiste, ciertamente no lo explicaste.
Daniel Tsadok

Mi punto es que esta respuesta no agrega ninguna información valiosa, la eliminaría.
Mauricio Scheffer

44
el "git reset HEAD --hard" también me ayudó ... nada más funcionó. También probé las soluciones anteriores, sin dados. ¡Gracias!
Virgil el

1
Cada hilo es su propio pequeño mundo en línea. Lo que dices te representa: no puedes esperar que las personas estudien tu historia personal para tratar de enmarcar tus comentarios en un contexto que te otorgue el respeto que deseas. Sea amable, sea respetuoso y no necesitará pedirle a la gente que comprenda sus peculiaridades personales. Si puede leer su comentario desde un contexto neutral, como lo haría un extraño, comprenderá mis críticas.
Stabledog el

10

Causa posible

Esto puede suceder cuando:

  1. Los submódulos se han editado en su lugar
  2. Submódulo (s) comprometidos, que actualiza el hash del submódulo al que se apunta
  3. Submódulo (s) no empujados .

Por ejemplo, algo así sucedió:

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

Debería haber submódulo empujado en este punto.

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

Como resultado, el usuario remoto no pudo encontrar las confirmaciones faltantes porque todavía están en el disco local.

Solución

Informa a la persona que modificó el submódulo para empujar, es decir

$ cd submodule
$ git push

6

Recibí este error cuando lo hice:

$ git submodule update --init --depth 1

pero el commit en el proyecto padre apuntaba a un commit anterior.

Eliminar la carpeta del submódulo y ejecutar:

$ git submodule update --init

NO resolvió el problema. Eliminé el repositorio e intenté nuevamente sin la bandera de profundidad y funcionó.

Este error ocurre en Ubuntu 16.04 git 2.7.4, pero no en Ubuntu 18.04 git 2.17, TODO encuentra la versión o confirmación de reparación exacta.


mi equipo ha abandonado desde entonces los submódulos en nuestro código demasiadas molestias jajaja
Platón

1
cual era tu alternativa
nuzzolilo

@nuzzolilo que agregamos username/repo#shaa package.json, una opción mucho más flexible es organizar su sistema con un conjunto de contenedores acoplables
Platón

3
Esto es muy molesto. --depth=1ahorra mucho ancho de banda cuando no necesito el historial de repositorios. Si alguien encuentra o sabe por qué sucede esto, me encantaría saberlo.
i336_

@ i336_ Aunque no puedo explicar por qué, he escrito un asistente de cmake que ayuda a mitigar el problema aquí: github.com/LMMS/lmms/blob/… . Utiliza un deinitenfoque que soluciona el problema la mayoría de las veces. Cuando se incluye con un sistema de compilación, el usuario final puede dejar que el sistema de compilación recupere los submódulos y abandone el recursivecomando roto por completo. Todavía hay escenarios en los que esto se rompe, como que el submódulo ha hecho un esfuerzo forzado y ha borrado la confirmación por completo.
tresf

5

Esto también puede suceder cuando tiene un submódulo que apunta a un repositorio que se modificó y la confirmación dada "desapareció". Si bien la confirmación aún puede estar en el repositorio remoto, no está en una rama. Si no puede crear una nueva rama (por ejemplo, no su repositorio), tiene que actualizar el superproyecto para señalar una nueva confirmación. Alternativamente, puede insertar una de sus copias de los submódulos en otro lugar y luego actualizar el superproyecto para que apunte a ese repositorio.


5

Es posible que su sucursal no esté actualizada, una solución simple, pero intente git fetch


2

Esta respuesta es para usuarios de SourceTree con experiencia limitada en git de terminal.

Abra el submódulo problemático desde el proyecto Git (superproyecto).

Obtenga y asegúrese de que 'Obtener todas las etiquetas' esté marcado.

Rebase saca tu proyecto Git.

Esto resolverá el problema de 'referencia no es un árbol' 9 de cada diez veces. Esa 1 vez no lo hará, es una solución terminal como se describe en la respuesta superior.


1

Su historial de submódulos se conserva de forma segura en el submódulo git de todos modos.

Entonces, ¿por qué no simplemente eliminar el submódulo y agregarlo nuevamente?

De lo contrario, ¿intentó editar manualmente el HEADo refs/master/headel submódulo?.git


1
Esto no funcionará, porque en algún lugar hay una referencia a 2d7cfbd09fc96c04c4c41148d44ed7778add6b43 que solo está en el repositorio local en otro lugar, pero no publicado
Mauricio Scheffer

1

Solo para estar seguro, intente actualizar sus gitarchivos binarios.

GitHub para Windows tiene la versión git version 1.8.4.msysgit.0que en mi caso fue el problema. La actualización lo resolvió.


1

En mi caso, ninguna de las respuestas anteriores resuelve el problema aunque sean buenas respuestas. Entonces publico mi solución (en mi caso hay dos clientes git, el cliente A y B):

  1. ir al directorio del submódulo:

    cd sub
    
  2. pago al maestro:

    git checkout master
    
  3. volver a crear un código de confirmación que ambos clientes puedan ver

  4. volver al directorio de los padres:

  5. comprometerse a dominar

  6. cambie al otro cliente, rebasevuelva a hacerlo .

  7. finalmente funciona bien ahora! Tal vez pierda un par de commits pero funciona.

  8. Para su información, no intente eliminar su submódulo, permanecerá .git/modulesallí y no podrá volver a leer este submódulo, a menos que sea uno reactivo local.


1

Para sincronizar el repositorio de git con la cabeza del submódulo, en caso de que sea realmente lo que desea, descubrí que quitar el submódulo y luego volver a leerlo evita los ajustes en el historial. Desafortunadamente, eliminar un submódulo requiere piratería en lugar de ser un solo comando git, pero factible.

Pasos que seguí para eliminar el submódulo, inspirados en https://gist.github.com/kyleturner/1563153 :

  1. Ejecute git rm --cached
  2. Elimine las líneas relevantes del archivo .gitmodules.
  3. Eliminar la sección relevante de .git / config.
  4. Elimine los archivos de submódulos ahora sin seguimiento.
  5. Eliminar el directorio .git / modules /

Nuevamente, esto puede ser útil si todo lo que quiere es apuntar a la cabeza del submódulo nuevamente, y no ha complicado las cosas al necesitar mantener intacta la copia local del submódulo. Se supone que tiene el submódulo "correcto" como su propio repositorio, donde sea que se encuentre, y solo desea volver a incluirlo correctamente como submódulo.

Nota: siempre haga una copia completa de su proyecto antes de participar en este tipo de manipulación o cualquier comando git más allá de la simple confirmación o inserción. También lo recomendaría con todas las otras respuestas, y como una guía general de git.


1

Simplemente me topé con este problema, y ​​ninguna de estas soluciones funcionó para mí. Lo que resultó ser la solución para mi problema es en realidad mucho más simple: actualizar Git. El mío era 1.7.1, y después de que lo actualicé a 2.16.1 (último), ¡el problema desapareció sin dejar rastro! Supongo que lo dejo aquí, espero que ayude a alguien.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.