Git sous-modules et sous-arbres
Maîtrisez les techniques pour gérer des dépendances externes et des projets multi-modules avec Git.
Git sous-modules et sous-arbres
Quand vos projets deviennent complexes et dépendent d’autres dépôts Git, les sous-modules et sous-arbres deviennent essentiels. Ce tutoriel vous apprendra à gérer efficacement des projets multi-dépôts avec Git.
Introduction aux dépendances Git
Problématiques courantes
graph TD
A[Projet Principal] --> B[Bibliothèque Commune]
A --> C[Module UI]
A --> D[API Client]
B --> E[Utilitaires]
C --> B
D --> B
Défis :
- Partager du code entre projets
- Gérer les versions des dépendances
- Maintenir la cohérence
- Éviter la duplication
Solutions Git
- Sous-modules (Submodules) : Références vers d’autres dépôts
- Sous-arbres (Subtrees) : Intégration du code externe
- Alternatives : Package managers, monorepos
Git Submodules
Concept
Un sous-module est un dépôt Git intégré dans un autre dépôt Git, maintenant sa propre histoire et ses références.
projet-principal/
├── src/
├── lib/
│ └── shared-utils/ # <- Sous-module
│ ├── .git # Dépôt Git séparé
│ └── utils.js
├── .gitmodules # Configuration des sous-modules
└── README.md
Ajouter un sous-module
# Ajouter un sous-module
git submodule add https://github.com/user/shared-utils.git lib/shared-utils
# Vérifier l'ajout
cat .gitmodules
Contenu 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"
Cloner un projet avec sous-modules
# 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
Travailler avec les sous-modules
Mettre à jour un sous-module
# 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"
Mettre à jour tous les sous-modules
# 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
Modifier un sous-module
# 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"
Configuration avancée
Branches spécifiques
# 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
URLs relatives
# .gitmodules avec URL relative
[submodule "lib/shared-utils"]
path = lib/shared-utils
url = ../shared-utils.git
Ignorer les modifications
# 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
Supprimer un sous-module
# 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
Concept
Un sous-arbre intègre le code d’un autre dépôt directement dans votre dépôt, sans maintenir de référence externe.
projet-principal/
├── src/
├── lib/
│ └── shared-utils/ # <- Code intégré
│ └── utils.js # Pas de .git séparé
└── README.md
Ajouter un sous-arbre
# 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/
Mettre à jour un sous-arbre
# Récupérer les mises à jour
git subtree pull --prefix=lib/shared-utils \
https://github.com/user/shared-utils.git \
main --squash
Contribuer à un sous-arbre
# 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
Extraire un sous-arbre
# 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
Comparaison Submodules vs Subtrees
Tableau comparatif
Aspect | Submodules | Subtrees |
---|---|---|
Complexité | Élevée | Moyenne |
Historique | Séparé | Intégré |
Taille du dépôt | Petite | Plus grande |
Clonage | Étapes supplémentaires | Standard |
Modifications | Complexes | Simples |
Versions | Explicites | Implicites |
Collaboration | Difficile | Plus facile |
Quand utiliser quoi ?
Submodules :
- Dépendances stables
- Contrôle strict des versions
- Équipes séparées
- Gros projets externes
Subtrees :
- Développement actif
- Collaboration fréquente
- Simplicité prioritaire
- Petites bibliothèques
Cas d’usage pratiques
Projet avec bibliothèque partagée
# 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
Thème WordPress avec sous-modules
# 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
Microservices avec dépendances communes
# 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
Exercices pratiques
Exercice 1 : Submodules basiques
# 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"
Exercice 2 : Subtrees avec contribution
# 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
Exercice 3 : Gestion des versions avec 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"
Bonnes pratiques
Pour les submodules
-
Documentation claire
# README.md ## Installation ```bash git clone --recurse-submodules https://github.com/user/project.git
Mise à jour des sous-modules
git submodule update --remote
-
Scripts d’automatisation
#!/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 Git
#!/bin/bash # .git/hooks/post-checkout # Mettre à jour les sous-modules après checkout git submodule update --init --recursive
Pour les subtrees
-
Aliases Git
git config alias.sba 'subtree add --prefix' git config alias.sbu 'subtree pull --prefix' git config alias.sbp 'subtree push --prefix'
-
Documentation des sources
# 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
Alternatives modernes
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
Package Managers
// 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
Dépannage
Problèmes courants avec 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"
Problèmes avec 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
Ressources supplémentaires
Outils
- Git Subrepo : Alternative aux submodules
- Lerna : Gestion de monorepos JavaScript
- Nx : Outils de développement monorepo
- Bazel : Système de build pour monorepos
Documentation
Conclusion
Les sous-modules et sous-arbres sont des outils puissants pour gérer des projets complexes avec des dépendances externes. Le choix entre les deux dépend de vos besoins spécifiques en termes de simplicité, contrôle et collaboration.
Dans le prochain tutoriel, nous explorerons GitHub Actions pour automatiser vos workflows de développement et de déploiement.
Temps de lecture estimé : 25 minutes
Niveau : Avancé
Étape précédente : Workflows Git avancés
Prochaine étape : GitHub Actions et CI/CD