W3docs

Git Submodule

Introducción a los submódulos de Git: cómo añadirlos, clonarlos, actualizarlos y eliminarlos, con los casos de uso más comunes.

Un submódulo te permite incrustar un repositorio Git dentro de otro y mantener sus historiales completamente separados. Esta página explica qué es un submódulo, cuándo es la herramienta adecuada y el ciclo de vida completo de comandos: añadir, clonar, extraer, actualizar, enviar y eliminar un submódulo, además de los errores comunes que hacen que los submódulos sean complicados.

Qué es un submódulo

Con mucha frecuencia, un repositorio de código depende de código externo de otros repositorios. Puedes copiar y pegar directamente el código externo en el repositorio principal, o usar el sistema de gestión de paquetes del lenguaje. Sin embargo, ambos métodos tienen la desventaja de no realizar un seguimiento de los cambios en el repositorio externo.

Git te permite incluir otros repositorios Git — llamados submódulos — dentro de un único repositorio. Un submódulo vive en una ruta específica del directorio de trabajo del repositorio padre y es, en sí mismo, un clon completo de otro repositorio con su propio historial .git.

La idea clave es que un submódulo está anclado a un commit exacto, no a una rama o una etiqueta. El repositorio padre almacena únicamente la ruta del submódulo, la URL y el SHA del commit que espera. Esto es lo que te permite depender de código externo en un punto conocido y reproducible en el tiempo.

Dos archivos rastrean esta relación:

  • .gitmodules — un archivo rastreado en la raíz del repositorio padre. Mapea la ruta de cada submódulo a su URL remota (y opcionalmente una rama). Este archivo se confirma y se comparte con todos.
  • .git/config y la entrada gitlink en el árbol — información de seguimiento local por clon que registra el commit actualmente extraído (el gitlink aparece con modo 160000).

Los submódulos permiten añadir, sincronizar, actualizar y clonar, pero dado que el padre solo recuerda un SHA de commit, actualizar un submódulo es siempre un acto deliberado en dos pasos — nunca automático.

Cuándo usar submódulos

Trabajar con submódulos es complicado, por lo que sugerimos algunos casos de uso ideales para ellos.

  • Si el subproyecto cambia demasiado rápido o los próximos cambios romperán la API, ancla el código a un commit específico por seguridad.
  • Si un componente no se actualiza con mucha frecuencia y quieres rastrearlo como una dependencia de proveedor.
  • Si representas una parte del proyecto a un tercero y quieres integrar su trabajo en un momento concreto (solo funciona cuando las actualizaciones no son demasiado frecuentes).
  • Si el contexto tecnológico permite el empaquetado y la gestión formal de dependencias, deberías usar gestores de paquetes en lugar de submódulos.
  • Si tu base de código es masiva y no quieres descargarla completa cada vez, usa submódulos para que los colaboradores solo descarguen las partes que necesitan.

Añadir un submódulo

Primero, crea (o muévete hacia) el repositorio que contendrá el submódulo:

mkdir git-submodule-demo
cd git-submodule-demo/
git init
Initialized empty Git repository in /Users/example/git-submodule-demo/.git/

Añade un submódulo con git submodule add, pasando la URL del repositorio que quieres incrustar:

git submodule add https://somehost/example/textexample
Cloning into '/Users/example/git-submodule-demo/textexample'...
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 8 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.

Git clona inmediatamente el repositorio textexample en una carpeta del mismo nombre y crea un archivo .gitmodules. Para colocar el submódulo en una ruta diferente, añádela como último argumento, por ejemplo git submodule add <url> vendor/textexample.

Ahora comprueba el estado del repositorio con git status:

git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   .gitmodules
	new file:   textexample

Observa que textexample está preparado como una única entrada, no como los archivos individuales que contiene. El repositorio padre solo rastrea el puntero de commit del submódulo. Confirma ambos archivos con git add y git commit:

git add .gitmodules textexample
git commit -m "Add textexample submodule"
[master (root-commit) d5002d0] Add textexample submodule
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 textexample

El modo 160000 es especial: marca textexample como un gitlink (un puntero a un commit) en lugar de un directorio normal.

Comprobar el estado del submódulo

Antes de cambiar cualquier cosa, comprueba en qué punto se encuentra cada submódulo:

git submodule status
 a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 textexample (v1.2.0)

El carácter inicial es significativo: un espacio significa que el submódulo está en el commit esperado, un + significa que está extraído en un commit diferente al que registra el padre, y un - significa que aún no está inicializado.

Actualizar submódulos

Los miembros del equipo deben actualizar el código del submódulo cuando ha sido modificado en otro lugar. No puedes depender solo de git pull, porque extraer el repositorio padre solo cambia el commit del submódulo registrado — no toca los archivos extraídos dentro del submódulo. Para extraer el commit que el padre espera, ejecuta:

git submodule update

Sin la bandera --remote, este comando extrae el commit registrado en el repositorio padre y no obtiene los nuevos cambios del origen.

Para obtener en su lugar el commit más reciente de la rama rastreada del submódulo (main por defecto, o la branch establecida en .gitmodules), usa --remote:

git submodule update --remote textexample

Esto obtiene el origen del submódulo y lo avanza. El repositorio padre ahora ve un nuevo puntero de commit, así que debes hacer git add y confirmar el submódulo para registrar el cambio.

Para ejecutar una actualización en todos los submódulos, incluidos los anidados, añade --init --recursive:

git submodule update --init --recursive

Si el archivo .gitmodules cambia (por ejemplo, la URL del submódulo se mueve), ejecuta git submodule sync para copiar las nuevas URLs en tu .git/config local antes de actualizar:

git submodule sync --recursive

Clonar submódulos de Git

Para clonar un proyecto con submódulos, usa el comando git clone. Por defecto, clona el repositorio padre pero deja los directorios de los submódulos vacíos. Luego debes ejecutar git submodule init y git submodule update. El primero actualiza el .git/config local con los mapeos de .gitmodules, mientras que el segundo obtiene los datos del submódulo y extrae el commit registrado.

Si clonaste sin --recurse-submodules, rellena los submódulos después:

git clone /url/to/repo/with/submodules
git submodule init
git submodule update

El atajo git submodule update --init combina esos dos últimos comandos. Mejor aún, clona todo en un solo paso con --recurse-submodules:

git clone --recurse-submodules /url/to/repo/with/submodules

Esto clona el padre e inicializa y extrae automáticamente cada submódulo, de modo que el árbol de trabajo queda completo de inmediato.

Extraer el código del submódulo

Cuando extraes un repositorio padre que ha adquirido nuevos submódulos, esos submódulos llegan sin inicializar. Primero, obtén el estado más reciente del padre:

git pull

Si hay nuevos submódulos listados, inicialízalos y obtenlos en un solo paso:

git submodule update --init --recursive

git submodule init por sí solo solo copia los mapeos al .git/config local; no descarga ningún código. El paso update es el que realmente obtiene el submódulo y extrae el commit registrado. Puedes hacer que git pull haga esto automáticamente configurando:

git config submodule.recurse true

Enviar actualizaciones en un submódulo

Un submódulo es un repositorio Git completo e independiente, por lo que confirmas y envías cambios dentro de su directorio exactamente como lo harías en cualquier otro lugar:

cd textexample
git checkout main
# ...edit files...
git commit -am "Fix typo in textexample"
git push
cd ..

Después de confirmar dentro del submódulo, el repositorio padre sigue apuntando al commit antiguo. Al ejecutar git status en el padre ahora se muestra:

	modified:   textexample (new commits)

Registra el nuevo puntero preparando y confirmando la ruta del submódulo en el padre, luego enviándolo:

git add textexample
git commit -m "Bump textexample to latest"
git push

Para evitar enviar el padre antes de que sus commits del submódulo existan en el remoto (lo que dejaría a los compañeros con un puntero roto e inaccesible), envía todo junto:

git push --recurse-submodules=on-demand

Esto envía primero los commits no enviados del submódulo y luego el padre.

Eliminar un submódulo

Eliminar la carpeta manualmente no es suficiente — Git mantiene su propia contabilidad. Elimina un submódulo correctamente con:

git submodule deinit -f textexample
git rm textexample
git commit -m "Remove textexample submodule"

deinit da de baja el submódulo y elimina su árbol de trabajo, git rm borra el gitlink y su entrada en .gitmodules, y el commit registra la eliminación.

Resumen

Los submódulos son una buena forma de mantener proyectos en repositorios separados mientras se hace referencia a ellos como carpetas en el directorio de trabajo de otro repositorio. El modelo mental que hay que tener es sencillo: el padre almacena un puntero de commit, cada actualización es deliberada, y --recurse-submodules te salva de clones a medio poblar. Para dependencias que cambian con frecuencia, un gestor de paquetes real suele ser la mejor opción. Para profundizar en flujos de trabajo relacionados, consulta git clone, git pull y git status.

Práctica

Práctica
¿Cuáles son los aspectos clave del uso de los submódulos de Git?
¿Cuáles son los aspectos clave del uso de los submódulos de Git?
Was this page helpful?