0%
Tutorial 9 de 10
90% completado

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

Projet PrincipalBibliothèque CommuneModule UIAPI ClientUtilitaires

Retos:

  • Compartir código entre proyectos
  • Gestionar las versiones de las dependencias
  • Mantener la coherencia
  • Evitar la duplicación

Soluciones de Git

  1. Submódulos (Submodules): referencias a otros repositorios
  2. Subárboles (Subtrees): integración del código externo
  3. 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

AspectoSubmodulesSubtrees
ComplejidadAltaMedia
HistorialSeparadoIntegrado
Tamaño del repositorioPequeñoMayor
ClonadoPasos adicionalesEstándar
ModificacionesComplejasSencillas
VersionesExplícitasImplícitas
ColaboraciónDifícilMá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

  1. Documentación clara

    # README.md
    ## Installation
    
    ```bash
    git clone --recurse-submodules https://github.com/user/project.git

    Mise à jour des sous-modules

    git submodule update --remote
  2. 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"
  3. 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

  1. Alias de Git

    git config alias.sba 'subtree add --prefix'
    git config alias.sbu 'subtree pull --prefix'
    git config alias.sbp 'subtree push --prefix'
  2. 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