Submódulos y subárboles de Git
Domine las técnicas para gestionar dependencias externas y proyectos multimódulo con Git.
Submódulos y subárboles de Git
Cuando sus proyectos se vuelven complejos y dependen de otros repositorios Git, los submódulos y los subárboles resultan esenciales. Este tutorial le enseñará a gestionar eficazmente proyectos con varios repositorios usando Git.
Introducción a las dependencias en Git
Problemáticas habituales
Retos:
- Compartir código entre proyectos
- Gestionar las versiones de las dependencias
- Mantener la coherencia
- Evitar la duplicación
Soluciones de Git
- Submódulos (Submodules): referencias a otros repositorios
- Subárboles (Subtrees): integración del código externo
- Alternativas: gestores de paquetes, monorepos
Git Submodules
Concepto
Un submódulo es un repositorio Git integrado en otro repositorio Git, que mantiene su propio historial y sus propias referencias.
projet-principal/
├── src/
├── lib/
│ └── shared-utils/ # <- Sous-module
│ ├── .git # Dépôt Git séparé
│ └── utils.js
├── .gitmodules # Configuration des sous-modules
└── README.md
Añadir un submódulo
# Ajouter un sous-module
git submodule add https://github.com/user/shared-utils.git lib/shared-utils
# Vérifier l'ajout
cat .gitmodules
Contenido de .gitmodules:
[submodule "lib/shared-utils"]
path = lib/shared-utils
url = https://github.com/user/shared-utils.git
# Commiter l'ajout du sous-module
git add .gitmodules lib/shared-utils
git commit -m "Add shared-utils submodule"
Clonar un proyecto con submódulos
# Méthode 1 : Clone avec initialisation automatique
git clone --recurse-submodules https://github.com/user/projet-principal.git
# Méthode 2 : Clone puis initialisation
git clone https://github.com/user/projet-principal.git
cd projet-principal
git submodule init
git submodule update
# Méthode 3 : Commande combinée
git submodule update --init --recursive
Trabajar con submódulos
Actualizar un submódulo
# Aller dans le sous-module
cd lib/shared-utils
# Récupérer les dernières modifications
git fetch
git merge origin/main
# Ou directement
git pull origin main
# Revenir au projet principal
cd ../..
# Commiter la nouvelle référence
git add lib/shared-utils
git commit -m "Update shared-utils to latest version"
Actualizar todos los submódulos
# Mettre à jour tous les sous-modules
git submodule update --remote
# Avec merge automatique
git submodule update --remote --merge
# Avec rebase
git submodule update --remote --rebase
Modificar un submódulo
# Aller dans le sous-module
cd lib/shared-utils
# Créer une branche
git checkout -b feature/new-utility
# Développer
echo "export function newUtil() { return 'new'; }" >> utils.js
git add utils.js
git commit -m "Add new utility function"
# Pousser vers le dépôt du sous-module
git push origin feature/new-utility
# Revenir au projet principal
cd ../..
# Le sous-module pointe maintenant vers le nouveau commit
git add lib/shared-utils
git commit -m "Update shared-utils with new utility"
Configuración avanzada
Ramas específicas
# Configurer un sous-module pour suivre une branche
git config -f .gitmodules submodule.lib/shared-utils.branch develop
# Mettre à jour vers cette branche
git submodule update --remote
URL relativas
# .gitmodules avec URL relative
[submodule "lib/shared-utils"]
path = lib/shared-utils
url = ../shared-utils.git
Ignorar las modificaciones
# Ignorer les modifications non commitées dans le sous-module
git config submodule.lib/shared-utils.ignore dirty
# Ignorer tous les changements
git config submodule.lib/shared-utils.ignore all
Eliminar un submódulo
# 1. Désactiver le sous-module
git submodule deinit lib/shared-utils
# 2. Supprimer du dépôt
git rm lib/shared-utils
# 3. Supprimer le dossier .git/modules
rm -rf .git/modules/lib/shared-utils
# 4. Commiter la suppression
git commit -m "Remove shared-utils submodule"
Git Subtrees
Concepto
Un subárbol integra el código de otro repositorio directamente en su repositorio, sin mantener ninguna referencia externa.
projet-principal/
├── src/
├── lib/
│ └── shared-utils/ # <- Code intégré
│ └── utils.js # Pas de .git séparé
└── README.md
Añadir un subárbol
# Ajouter un sous-arbre
git subtree add --prefix=lib/shared-utils \
https://github.com/user/shared-utils.git \
main --squash
# Vérifier l'ajout
ls lib/shared-utils/
Actualizar un subárbol
# Récupérer les mises à jour
git subtree pull --prefix=lib/shared-utils \
https://github.com/user/shared-utils.git \
main --squash
Contribuir a un subárbol
# Modifier le code du sous-arbre
echo "export function newFeature() { return 'feature'; }" >> lib/shared-utils/utils.js
git add lib/shared-utils/utils.js
git commit -m "Add new feature to shared utils"
# Pousser les modifications vers le dépôt original
git subtree push --prefix=lib/shared-utils \
https://github.com/user/shared-utils.git \
main
Extraer un subárbol
# Créer un nouveau dépôt depuis un sous-dossier
git subtree split --prefix=lib/shared-utils -b shared-utils-branch
# Créer un nouveau dépôt
mkdir ../shared-utils-extracted
cd ../shared-utils-extracted
git init
git pull ../projet-principal shared-utils-branch
Comparación entre Submodules y Subtrees
Tabla comparativa
| Aspecto | Submodules | Subtrees |
|---|---|---|
| Complejidad | Alta | Media |
| Historial | Separado | Integrado |
| Tamaño del repositorio | Pequeño | Mayor |
| Clonado | Pasos adicionales | Estándar |
| Modificaciones | Complejas | Sencillas |
| Versiones | Explícitas | Implícitas |
| Colaboración | Difícil | Más fácil |
¿Cuándo usar cada uno?
Submodules:
- Dependencias estables
- Control estricto de las versiones
- Equipos separados
- Grandes proyectos externos
Subtrees:
- Desarrollo activo
- Colaboración frecuente
- Prioridad a la simplicidad
- Bibliotecas pequeñas
Casos de uso prácticos
Proyecto con biblioteca compartida
# Structure du projet
mkdir monorepo-example
cd monorepo-example
git init
# Créer la bibliothèque commune
mkdir -p shared/utils
echo "export function formatDate(date) {
return date.toISOString().split('T')[0];
}" > shared/utils/date.js
git add shared/
git commit -m "Add shared utilities"
# Ajouter comme sous-module dans d'autres projets
cd ../web-app
git submodule add ../monorepo-example/shared shared/utils
Tema de WordPress con submódulos
# Thème principal
mkdir wp-theme
cd wp-theme
git init
# Ajouter un framework CSS
git submodule add https://github.com/twbs/bootstrap.git assets/bootstrap
# Ajouter une bibliothèque JS
git submodule add https://github.com/jquery/jquery.git assets/jquery
# Structure finale
# wp-theme/
# ├── assets/
# │ ├── bootstrap/ # Sous-module
# │ └── jquery/ # Sous-module
# ├── style.css
# └── index.php
Microservicios con dependencias comunes
# Service utilisateur
mkdir user-service
cd user-service
git init
# Ajouter les utilitaires communs
git subtree add --prefix=lib/common \
https://github.com/company/common-lib.git \
main --squash
# Service commande
cd ../order-service
git init
git subtree add --prefix=lib/common \
https://github.com/company/common-lib.git \
main --squash
Ejercicios prácticos
Ejercicio 1: Submodules básicos
# 1. Créer un dépôt de bibliothèque
mkdir math-lib
cd math-lib
git init
echo "export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }" > math.js
git add math.js
git commit -m "Initial math library"
# Simuler un dépôt distant
cd ..
git clone --bare math-lib math-lib.git
# 2. Créer le projet principal
mkdir calculator-app
cd calculator-app
git init
echo "# Calculator App" > README.md
git add README.md
git commit -m "Initial commit"
# 3. Ajouter le sous-module
git submodule add ../math-lib.git lib/math
git commit -m "Add math library submodule"
# 4. Utiliser la bibliothèque
echo "import { add, multiply } from './lib/math/math.js';
console.log('2 + 3 =', add(2, 3));
console.log('4 * 5 =', multiply(4, 5));" > app.js
git add app.js
git commit -m "Add calculator app using math library"
Ejercicio 2: Subtrees con contribución
# 1. Créer une bibliothèque d'utilitaires
mkdir utils-lib
cd utils-lib
git init
echo "export function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}" > string-utils.js
git add string-utils.js
git commit -m "Add string utilities"
# 2. Créer le projet principal
cd ..
mkdir blog-app
cd blog-app
git init
# 3. Ajouter comme sous-arbre
git subtree add --prefix=utils ../utils-lib main --squash
# 4. Modifier et contribuer
echo "export function slugify(str) {
return str.toLowerCase().replace(/\s+/g, '-');
}" >> utils/string-utils.js
git add utils/string-utils.js
git commit -m "Add slugify function to string utils"
# 5. Pousser la contribution
git subtree push --prefix=utils ../utils-lib main
Ejercicio 3: Gestión de versiones con submodules
# 1. Dans le dépôt de bibliothèque
cd math-lib
git tag v1.0.0
# Ajouter une nouvelle fonction
echo "export function subtract(a, b) { return a - b; }" >> math.js
git add math.js
git commit -m "Add subtract function"
git tag v1.1.0
# 2. Dans le projet principal
cd ../calculator-app
# Mettre à jour vers une version spécifique
cd lib/math
git fetch --tags
git checkout v1.1.0
cd ../..
git add lib/math
git commit -m "Update math library to v1.1.0"
# 3. Utiliser la nouvelle fonction
echo "import { subtract } from './lib/math/math.js';
console.log('10 - 3 =', subtract(10, 3));" >> app.js
git add app.js
git commit -m "Use subtract function"
Buenas prácticas
Para los submodules
-
Documentación clara
# README.md ## Installation ```bash git clone --recurse-submodules https://github.com/user/project.gitMise à jour des sous-modules
git submodule update --remote -
Scripts de automatización
#!/bin/bash # scripts/update-submodules.sh echo "Updating all submodules..." git submodule update --remote --merge echo "Committing updates..." git add . git commit -m "Update submodules to latest versions" -
Hooks de Git
#!/bin/bash # .git/hooks/post-checkout # Mettre à jour les sous-modules après checkout git submodule update --init --recursive
Para los subtrees
-
Alias de Git
git config alias.sba 'subtree add --prefix' git config alias.sbu 'subtree pull --prefix' git config alias.sbp 'subtree push --prefix' -
Documentación de las fuentes
# SUBTREES.md ## lib/shared-utils - Source: https://github.com/company/shared-utils.git - Branch: main - Last update: 2024-01-15 ### Update command: ```bash git subtree pull --prefix=lib/shared-utils \ https://github.com/company/shared-utils.git \ main --squash
Alternativas modernas
Git Worktrees
# Créer des arbres de travail séparés
git worktree add ../feature-branch feature/new-feature
git worktree add ../hotfix-branch hotfix/critical-fix
# Lister les arbres de travail
git worktree list
# Supprimer un arbre de travail
git worktree remove ../feature-branch
Gestores de paquetes
// package.json avec dépendances Git
{
"dependencies": {
"shared-utils": "git+https://github.com/company/shared-utils.git#v1.2.0"
}
}
Monorepos
# Structure monorepo
project/
├── packages/
│ ├── shared-utils/
│ ├── web-app/
│ └── mobile-app/
├── tools/
└── package.json
Solución de problemas
Problemas habituales con submodules
# Submodule vide après clone
git submodule update --init --recursive
# Conflit de sous-module
git reset --hard HEAD
git submodule update --init --recursive
# Sous-module détaché
cd submodule-path
git checkout main
cd ..
git add submodule-path
git commit -m "Fix detached submodule"
Problemas con subtrees
# Erreur "Working tree has modifications"
git stash
git subtree pull --prefix=lib/utils origin main --squash
git stash pop
# Historique pollué
# Utiliser --squash pour éviter l'historique complet
git subtree add --prefix=lib/utils origin main --squash
Recursos adicionales
Herramientas
- Git Subrepo: alternativa a los submodules
- Lerna: gestión de monorepos JavaScript
- Nx: herramientas de desarrollo para monorepos
- Bazel: sistema de compilación para monorepos
Documentación
Conclusión
Los submódulos y los subárboles son herramientas potentes para gestionar proyectos complejos con dependencias externas. La elección entre ambos depende de sus necesidades específicas en cuanto a simplicidad, control y colaboración.
En el próximo tutorial exploraremos GitHub Actions para automatizar sus flujos de trabajo de desarrollo y despliegue.
Tiempo de lectura estimado: 25 minutos
Nivel: Avanzado
Etapa anterior: Flujos de trabajo avanzados de Git
Siguiente etapa: GitHub Actions y CI/CD