infra / git-github
Sous-modules
Explication
Ce que vous allez apprendre
- Comprendre pourquoi un submodule imbrique un dépôt Git complet dans un autre
- Réaliser qu'un submodule pointe vers un commit précis, pas vers une branche en continu
- Cloner correctement un dépôt qui contient des submodules avec
--recurse-submodules - Mettre à jour un submodule en deux étapes distinctes (dans le submodule, puis dans le parent)
- Connaître les alternatives (monorepo, registre de paquets) souvent préférées en pratique
Dans quel contexte ?
L'entreprise maintient une bibliothèque de composants d'interface, shared-ui-kit, réutilisée à la fois par boutique-api et par un autre projet interne. Plutôt que de dupliquer ce code ou de le publier comme un paquet npm complet, l'équipe l'inclut comme submodule dans boutique-api, ce qui garde les deux historiques Git séparés tout en figeant une version précise et connue de la bibliothèque.
Un besoin particulier : un dépôt dans un dépôt
D'abord, il arrive qu'un projet dépende d'un autre dépôt Git à part entière, une bibliothèque interne partagée entre plusieurs applications, par exemple, que l'on veut garder distinct.
Ce que les solutions classiques ne permettent pas
Copier-coller son code casserait le lien avec les mises à jour futures ; en faire une dépendance de gestionnaire de paquets classique n'est pas toujours possible ou souhaité.
La solution : le submodule
Le submodule répond à ce cas précis : il imbrique un dépôt Git complet dans un autre, tout en gardant les deux historiques bien séparés.
Le point le plus important à comprendre
Le dépôt parent ne suit pas "la dernière version" du submodule en continu, il enregistre un commit précis, figé, du submodule.
Ce que ça implique concrètement
Le contenu du submodule ne change donc jamais tout seul : il faut une action explicite, aller dans le submodule, tirer les nouveautés, puis revenir dans le parent pour enregistrer ce nouveau point de référence.
| Étape | Où | Commande |
|---|---|---|
| 1. Récupérer les nouveautés | Dans le dossier du submodule | git pull origin main |
| 2. Enregistrer le nouveau point de référence | Dans le dépôt parent | git add + git commit |
Pourquoi cette rigidité est une garantie
C'est une garantie de stabilité : le parent ne casse jamais à cause d'un changement imprévu dans une dépendance.
Le piège classique du clone incomplet
Cloner un dépôt qui contient des submodules ne récupère PAS automatiquement leur contenu par défaut : les dossiers correspondants restent vides.
Comment éviter cette confusion
Il faut soit une initialisation explicite après le clone, soit demander directement un clone récursif dès le départ.
Piège fréquent
Un git clone classique sur un dépôt contenant des submodules laisse leurs dossiers vides, ce qui peut faire croire à un bug ou à des fichiers manquants. Utilise toujours git clone --recurse-submodules, ou lance git submodule init && git submodule update juste après un clone classique.
Une alternative de plus en plus préférée
Les submodules restent utiles pour du code partagé peu couplé, mais leur complexité d'usage pousse de nombreuses équipes vers des alternatives : un monorepo ou un gestionnaire de paquets privé.
La leçon suivante s'attaque à un besoin différent : faire respecter des règles automatiquement à chaque commit, avec les hooks Git.
Commandes & code
Sous-modules (submodules)
Un submodule imbrique un dépôt Git DANS un autre, en pointant vers un commit précis.
# Ajouter un submodule (ex: une bibliothèque partagée entre plusieurs projets)
git submodule add git@github.com:org/shared-ui-kit.git libs/shared-ui-kit
git commit -m "Add shared-ui-kit as submodule"# .gitmodules généré automatiquement à la racine du dépôt parent
[submodule "libs/shared-ui-kit"]
path = libs/shared-ui-kit
url = git@github.com:org/shared-ui-kit.git
branch = main# Cloner un dépôt QUI CONTIENT des submodules : ils sont vides par défaut !
git clone git@github.com:org/main-app.git
cd main-app
git submodule init
git submodule update
# ou en une seule commande dès le clone :
git clone --recurse-submodules git@github.com:org/main-app.git# Mettre à jour un submodule vers son dernier commit distant
cd libs/shared-ui-kit
git pull origin main
cd ../..
git add libs/shared-ui-kit # enregistre le NOUVEAU commit pointé par le submodule
git commit -m "Bump shared-ui-kit to latest"
# Mettre à jour TOUS les submodules d'un coup vers leur branche suivie
git submodule update --remote --merge# Piège classique : oublier "--recurse-submodules" laisse des dossiers vides
git status --ignore-submodules=none
git submodule status
# -shared-ui-kit <- le "-" indique un submodule non initialisé
# Alternative moderne souvent préférée : monorepo ou gestionnaire de paquets privé
# (les submodules restent utiles pour du code partagé peu couplé)Résumé
- Un submodule pointe vers un COMMIT PRÉCIS d'un autre dépôt, pas vers une branche en continu.
git clone --recurse-submodulesévite d'oubliersubmodule init && update.- Mettre à jour un submodule = 2 étapes :
pulldedans, puisadd+commitdans le parent. - Alternative fréquente en pratique : monorepo ou registre de paquets privé.
Exercices pratiques
Mission : diagnostiquer un submodule à moitié cloné
Objectif : Comprendre pourquoi un submodule mal initialisé laisse un dossier vide, et mettre à jour correctement sa référence dans le dépôt parent.
Contexte
Un nouveau développeur clone boutique-api avec un simple git clone, sans savoir que le projet inclut libs/shared-ui-kit comme submodule. Le dossier libs/shared-ui-kit existe mais reste totalement vide, ce qui casse la compilation.