Actualización de submódulo de Git

242

No tengo claro qué significa lo siguiente (de la documentación de actualización del submódulo Git ):

... hará que los submódulos HEAD se separen, a menos que --rebaseo --mergese especifique ...

¿Cómo --rebase/ --mergecambia las cosas?

Mi caso de uso principal es tener un montón de repositorios centrales, que incrustaré a través de submódulos en otros repositorios. Me gustaría poder mejorar estos repositorios centrales, ya sea directamente en su ubicación original o desde dentro de sus repositorios de incrustación (los que los usan a través de submódulos).

  • Desde estos submódulos, ¿puedo crear ramas / modificaciones y usar push / pull como lo haría en repositorios regulares, o hay cosas de las que hay que tener cuidado?
  • ¿Cómo avanzaría el commit de submódulo referenciado de say (etiquetado) 1.0 a 1.1 (aunque el jefe del repositorio original ya está en 2.0), o elegiría qué commit de ramificación se usa?
azul profundo
fuente
Sobre el tema de "cabeza separada", consulte también stackoverflow.com/questions/964876/head-and-orighead-in-git y stackoverflow.com/questions/237408/… para ver un ejemplo práctico (no relacionado con submódulos, pero aún así )
VonC
"no puede modificar el contenido del submódulo desde el proyecto principal": sí, es cierto. Y he editado mi respuesta para arrojar algo de luz sobre esa aparente contradicción (submódulo no modificable, que aún puede modificar desde el repositorio principal del proyecto)
VonC

Respuestas:

304

Esta página de GitPro resume muy bien la consecuencia de una actualización de submódulo git

Cuando ejecuta git submodule update, verifica la versión específica del proyecto, pero no dentro de una rama. Esto se denomina tener una cabeza separada; significa que el archivo HEAD apunta directamente a un commit, no a una referencia simbólica.
El problema es que generalmente no desea trabajar en un entorno de cabeza separada, porque es fácil perder los cambios .
Si realiza una actualización inicial de submódulos, confirme en ese directorio de submódulos sin crear una rama para trabajar y luego ejecute git submodule update nuevamente desde el superproyecto sin comprometerse mientras tanto, Git sobrescribirá sus cambios sin avisarle. Técnicamente, no perderá el trabajo, pero no tendrá una rama que lo señale, por lo que será algo difícil de recuperar.


Nota de marzo de 2013:

Como se menciona en " git submodule tracking latest ", un submódulo ahora (git1.8.2) puede rastrear una rama.

# add submodule to track master branch
git submodule add -b master [URL to Git repo];

# update your submodule
git submodule update --remote 
# or (with rebase)
git submodule update --rebase --remote

Ver " git submodule update --remotevsgit pull ".

La respuesta de MindTooth ilustra una actualización manual (sin configuración local):

git submodule -q foreach git pull -q origin master

En ambos casos, eso cambiará las referencias de submódulos (el gitlink , una entrada especial en el índice de repositorio principal ), y deberá agregar, confirmar y enviar dichas referencias desde el repositorio principal.
La próxima vez que clone ese repositorio principal, rellenará los submódulos para reflejar esas nuevas referencias SHA1.

El resto de esta respuesta detalla la característica clásica de submódulo (referencia a una confirmación fija , que es el punto central detrás de la noción de un submódulo).


Para evitar este problema, cree una rama cuando trabaje en un directorio de submódulos con git checkout -b work o algo equivalente. Cuando realice la actualización del submódulo por segunda vez, todavía revertirá su trabajo, pero al menos tiene un puntero al que volver.

Cambiar ramas con submódulos en ellas también puede ser complicado. Si crea una nueva rama, agrega un submódulo allí y luego vuelve a cambiar a una rama sin ese submódulo, aún tiene el directorio de submódulos como un directorio sin seguimiento:


Entonces, para responder a sus preguntas:

¿Puedo crear ramas / modificaciones y usar push / pull como lo haría en repositorios regulares, o hay cosas de las que tenga cuidado?

Puede crear una rama y hacer modificaciones.

ADVERTENCIA (del Tutorial de submódulos de Git ): siempre publique (empuje) el cambio de submódulo antes de publicar (empujar) el cambio en el superproyecto que hace referencia a él. Si olvida publicar el cambio de submódulo, otros no podrán clonar el repositorio.

¿Cómo avanzaría el commit de submódulo referenciado de say (etiquetado) 1.0 a 1.1 (aunque el jefe del repositorio original ya está en 2.0)

La página " Comprensión de submódulos " puede ayudar

Los submódulos de Git se implementan utilizando dos partes móviles:

  • el .gitmodulesarchivo y
  • Un tipo especial de objeto de árbol.

Estos juntos triangulan una revisión específica de un repositorio específico que se desprotege en una ubicación específica en su proyecto.


Desde la página del submódulo git

no puede modificar el contenido del submódulo desde el proyecto principal

100% correcto: no puede modificar un submódulo, solo consulte uno de sus commits.

Es por eso que, cuando modifica un submódulo desde el proyecto principal, usted:

  • necesita comprometerse y empujar dentro del submódulo (al módulo ascendente), y
  • luego suba en su proyecto principal y vuelva a confirmar (para que ese proyecto principal haga referencia al nuevo compromiso de submódulo que acaba de crear y empujar)

Un submódulo le permite tener un desarrollo de enfoque basado en componentes , donde el proyecto principal solo se refiere a confirmaciones específicas de otros componentes (aquí "otros repositorios Git declarados como submódulos").

Un submódulo es un marcador (commit) a otro repositorio de Git que no está vinculado por el ciclo principal de desarrollo del proyecto: él (el "otro" repositorio de Git) puede evolucionar independientemente.
Depende del proyecto principal elegir de ese otro repositorio cualquier compromiso que necesite.

Sin embargo, si desea, por conveniencia , modificar uno de esos submódulos directamente desde su proyecto principal, Git le permite hacerlo, siempre que primero publique esas modificaciones de submódulos en su repositorio original de Git y luego confirme su proyecto principal haciendo referencia a Una nueva versión de dicho submódulo.

Pero la idea principal sigue siendo: hacer referencia a componentes específicos que:

  • tener su propio ciclo de vida
  • tener su propio conjunto de etiquetas
  • tener su propio desarrollo

La lista de confirmaciones específicas a las que se refiere en su proyecto principal define su configuración (esto es de lo que se trata la Gestión de la Configuración , que abarca el mero Sistema de Control de Versiones )

Si un componente realmente pudiera desarrollarse al mismo tiempo que su proyecto principal (porque cualquier modificación en el proyecto principal implicaría modificar el subdirectorio, y viceversa), entonces ya no sería un "submódulo", sino un subtree merge (también presentado en la pregunta Transferencia de base de código heredado de cvs a repositorio distribuido ), vinculando la historia de los dos repositorios Git.

¿Ayuda eso a comprender la verdadera naturaleza de los submódulos de Git?

VonC
fuente
77
Guau. Esa larga explicación de algo que es principalmente así de simple debería ser suficiente para asustar a cualquier recién llegado para que se quede con su svn: externos. ;-)
conny
2
@conny: pero, como detallo en " ¿Por qué los submódulos git son incompatibles con svn externals? ", los submódulos son fundamentalmente diferentes y no compatibles svn:externals.
VonC
1
Lo siento, para responder a mi propia pregunta, reúno el CD en el submódulo y git checkout un sha, o git pull / fetch funcionará bien. Luego, confirmando la actualización en el repositorio local.
Henrik
2
@hced: También puedes golpear todos los submódulos a la vez usandogit submodule foreach
Dav Clark
1
.. todavía no lo entiendo. ¿Hay alguna explicación más fácil en la web en alguna parte?
eugene
135

Para actualizar cada submódulo, puede invocar el siguiente comando (en la raíz del repositorio):

git submodule -q foreach git pull -q origin master

Puede eliminar la opción -q para seguir todo el proceso.

MindTooth
fuente
15
Si acaba de ejecutar git submodule update --init --recursivedesde la raíz, los obtendrá de forma recursiva y los inicializará si aún no lo están.
Sam Soffes
10
@SamSoffes Eso tiene un propósito completamente diferente. La actualización de submódulos verificará los submódulos en la confirmación a la que apuntan actualmente (no necesariamente la última confirmación). La solución en la respuesta anterior actualiza la confirmación de cada submódulo al último HEAD de origen / maestro.
indragie
77
Mi nuevo método:git submodule update --rebase --remote
MindTooth
19

Para abordar la opción --rebasevs --merge.:

Supongamos que tiene el súper repositorio A y el submódulo B y desea trabajar en el submódulo B. Ha hecho su tarea y lo sabe después de llamar

git submodule update

está en un estado sin CABEZA, por lo que es difícil volver a realizar cualquier confirmación que haga en este momento. Entonces, has comenzado a trabajar en una nueva rama en el submódulo B

cd B
git checkout -b bestIdeaForBEver
<do work>

Mientras tanto, alguien más en el proyecto A ha decidido que la última y mejor versión de B es realmente lo que A merece. Usted, por costumbre, combina los cambios más recientes y actualiza sus submódulos.

<in A>
git merge develop
git submodule update

Oh no! Estás de nuevo en un estado sin cabeza nuevamente, probablemente porque B ahora está apuntando al SHA asociado con la nueva sugerencia de B, o algún otro commit. Si solo tuvieras:

git merge develop
git submodule update --rebase

Fast-forwarded bestIdeaForBEver to b798edfdsf1191f8b140ea325685c4da19a9d437.
Submodule path 'B': rebased into 'b798ecsdf71191f8b140ea325685c4da19a9d437'

Ahora que la mejor idea para B ha sido basada en el nuevo commit, y lo más importante, ¡todavía estás en tu rama de desarrollo para B, no en un estado sin cabeza!

( --mergeCombinará los cambios de beforeUpdateSHA a afterUpdateSHA en su rama de trabajo, en lugar de cambiar los cambios en afterUpdateSHA).

robinspb
fuente
7

Git 1.8.2 presenta una nueva opción --remote, que permitirá exactamente este comportamiento. Corriendo

git submodule update --rebase --remote

buscará los últimos cambios desde la parte superior en cada submódulo, los cambiará de base y verificará la última revisión del submódulo. Como dice la documentación :

--remoto

Esta opción solo es válida para el comando de actualización. En lugar de usar el SHA-1 grabado del superproyecto para actualizar el submódulo, use el estado de la rama de seguimiento remoto del submódulo.

Esto es equivalente a ejecutarse git pullen cada submódulo, que generalmente es exactamente lo que desea.

(Esto fue copiado de esta respuesta ).

Iulian Onofrei
fuente
Si decide responder una pregunta anterior que tiene respuestas bien establecidas y correctas, agregar una nueva respuesta al final del día puede no darle ningún crédito. Si tiene alguna información nueva distintiva, o está convencido de que las otras respuestas están todas equivocadas, agregue una nueva respuesta, pero 'otra respuesta' que proporciona la misma información básica mucho tiempo después de que se formuló la pregunta generalmente gana ' No te ganaré mucho crédito. No hay una explicación de lo que esto hace, ni siquiera un enlace a documentación externa (que no sería suficiente).
Jonathan Leffler
2
No es "otra respuesta más", ya que NINGUNA otra respuesta tiene este comando (prueba que estoy equivocado). Otras respuestas no funcionaron para mí, este comentario sí, así que decidí publicarlo como respuesta mientras le daba crédito al propietario original. Así que considere eliminar su voto negativo.
Iulian Onofrei
Hay un comentario de MindTooth de 2015 que dice que esto es lo que hacen ahora. No das ninguna explicación de lo que hace (aunque mencionas MindTooth, pero no hay una explicación real de lo que quieres decir con eso: incrustar URL, como en este comentario, ayudaría). No dices por qué es una buena idea. No das ninguna advertencia. En mi opinión, esta no es una respuesta útil porque plantea más preguntas de las que resuelve.
Jonathan Leffler
1
Con eso, quise decir que funciona en lugar de no funcionar. Créame, si más personas vieran esta respuesta, se alegrarían, porque funciona . Para cosas como esta, la mayoría de las personas solo quieren saber el comando que actualiza un submódulo git, no cómo se implementa.
Iulian Onofrei
¡Edité la respuesta para demostrar que estás equivocado, también, stackoverflow.com/questions/1979167/git-submodule-update/… !!!
Iulian Onofrei