¿Cómo se implementa la function de submodules internamente si utiliza la twig de seguimiento?

Estoy leyendo este excelente artículo sobre submodules que explica que el submodule se guarda como un tipo especial de file en el tree de commit del repository principal:

[/tmp/git/super(master)]$ git ls-files --stage 100644 831cdc0dc1b88e69aa9943cf09907ae1bcd031fc 0 .gitmodules 160000 85ab8ba4edf9168ab051ded7ddbbe20861b71528 0 ProjectA <-------- 100644 16f5c2d3aa9656fc424352e4cfaa2523c809778b 0 super.txt 

donde 85ab8ba4edf9168ab051ded7ddbbe20861b71528 es el hash de la confirmación en el repository de foreign / submodule.

Si utilizo el enfoque con una twig de seguimiento:

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

¿Cómo funciona internamente?

Según entiendo:

  • la twig de seguimiento se configura en el repository clonado del submodule
  • la twig de seguimiento se agrega a .gitmodules

Pero, ¿qué ocurre con el file especial que hace reference a la confirmación? ¿Aún retiene el hash de confirmación del submodule?

¿La function de seguimiento de la twig solo afecta el comportamiento cuando ejecuto

 git submodule update --remote 

¿en que comtesting la twig de seguimiento del submodule y comtesting la nueva confirmación y actualiza el índice del depósito maestro?

Antecedentes (no dude en saltar a la siguiente sección)

Lo principal que debe recordar sobre los submodules es que siempre hay dos Gits involucrados en el punto donde el submodule se une al superproyecto.

El superproyecto tiene un mínimo de tres piezas de información. Dos están en .gitmodules :

  • la ruta completa, por ejemplo, path/to/ProjectA (si el submodule está abajo en algún set de subdirectorys) o simplemente ProjectA (si el submodule reside en el nivel superior); y
  • la URL, para que Git pueda ejecutar git clone ... para get el submodule después de haber clonado el superproyecto (pero no sus submodules).

El índice (como se ve en git ls-files --stage tiene dos elementos de información:

  • la ruta completa, por ejemplo, path/to/projectA (que debe coincidir con la input de .gitmodules ); y
  • el hash de confirmación que desea, por ejemplo, 85ab8ba4edf9168ab051ded7ddbbe20861b71528 .

Dado que estas superposiciones, es obvio que puedes salirte de synchronization: si cambias el path, las cosas se ponen un poco raras.

El submodule en sí es un repository de Git. Eso significa que además de commits , tiene HEAD , branches, tags, etc. Los contenidos de HEAD representan el compromiso actual . Inicialmente, cuando el superproyecto controla todo, se le dice al Git del submodule: Separe HEAD revisando una confirmación específica mediante ID de hash , por ejemplo, 85ab8ba4edf9168ab051ded7ddbbe20861b71528 .

Sin embargo, puedes ir al submodule y ver el nombre de una sucursal o una label diferente. Puede ejecutar git fetch para get confirmaciones del submétodo Git's usptream , que no está relacionado con el superproyecto. En resumen, puede hacer cualquier cosa que pueda hacer en cualquier antiguo repository de Git.

Pero una vez que lo haces, las cosas no están sincronizadas: la ID de confirmación que HEAD resuelve puede no coincidir con la ID de confirmación almacenada en el superproyecto.

Usar nombres de twigs con submodules

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

… la twig de seguimiento se agrega a .gitmodules

Sí. Ahí está, esperando su próximo command:

 git submodule update --remote 

que lo saca de allí (o en otro lugar 1 ) y hace que el Git maneje el submodule ejecutado:

 git fetch [potential additional options] 

seguido por uno de git merge , git rebase , o git checkout , dependiendo de más banderas y opciones y configuraciones. Los arguments pasados ​​al siguiente command también dependen de más indicadores y opciones y configuraciones.

Una vez hecho esto, es probable que el submodule tenga algún otro compromiso verificado. Es decir, git rev-parse HEAD , ejecuta en el submodule, nombra algo distinto a 85ab8ba... Entonces, su súperproyecto y subproyecto no están sincronizados: su superproyecto llama al compromiso 85ab8ba... específicamente, pero su submodule no está "en" ese compromiso.

Ahora es su trabajo asegurarse de que el superproyecto funcione correctamente con el nuevo hash de submodule en su lugar. Si es así, puede, mientras está en el superproyecto, ejecutar git add en la ruta del submodule. Esto actualiza la input de índice especial, manteniendo la ruta intacta pero escribiendo un nuevo hash de confirmación en ella.

Ahora puedes git commit en el superproyecto. Los contenidos del índice, como de costumbre, determinan los contenidos de la nueva confirmación. La confirmación registrará la nueva identificación hash. Los contenidos de .gitmodules , que contienen el nombre de la twig, no han cambiado, por lo que la versión de .gitmodules registrada en la confirmación nueva es la misma que la versión de .gitmodules registrada en la confirmación anterior. El único signo de la nueva ID de hash en el superproyecto es que la ID de hash almacenada en la confirmación (para ser copyda de nuevo en el índice en la git checkout de git checkout de esa confirmación en el repository de superproyectos) es esta actualizada.


1 La twig utilizada en este punto se toma de .gitmodules less que haya un submodule.<name>.branch configurado en $GIT_DIR/config . La configuration de configuration anula la configuration de .gitmodules . La parte <name> de esto es el nombre de la twig actual en el superproyecto . Todas estas varias cosas necesitan calificación, porque estamos viendo dos Gits simultáneamente: el superproyecto Git repo, y el submodule Git repo.

(La documentation existente de Git parece no ser tan buena para mantener claras las distinciones aquí).