Un submodule Git est un dépôt Git imbriqué dans un autre. Le projet parent référence un commit précis du sous-dépôt, ce qui permet d'intégrer des bibliothèques, des outils ou des configurations partagées tout en gardant les historiques séparés. Ce guide couvre le workflow complet, de l'ajout à la mise à jour.
Prérequis : Remotes fondamentaux et Branches distantes.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Ajouter un submodule dans un dépôt existant et cloner avec ses submodules
- Mettre à jour un submodule vers une nouvelle version du dépôt distant
- Identifier les pièges classiques : HEAD détaché, oubli de commit, double push
- Comparer submodules et
git subtreepour choisir la bonne approche
Quand utiliser des submodules ?
Section intitulée « Quand utiliser des submodules ? »Les submodules sont utiles quand :
- Vous intégrez une bibliothèque partagée entre plusieurs projets
- Vous voulez une version figée d'une dépendance (pas toujours la dernière)
- Les dépôts doivent garder des historiques indépendants
- Chaque équipe gère son propre dépôt
Exemples concrets : un framework interne, des fichiers de configuration Terraform partagés, un thème de documentation.
Ajouter un submodule
Section intitulée « Ajouter un submodule »Une seule commande suffit pour rattacher un dépôt externe. Elle prend deux arguments : l'URL du dépôt à intégrer, puis le chemin où le déposer dans votre projet. Ce chemin devient le nom du submodule, c'est lui que vous retrouverez dans toutes les commandes ultérieures.
git submodule add https://github.com/org/lib-utils.git libs/utilsCette commande :
-
Clone
lib-utilsdanslibs/utils/ -
Crée (ou met à jour) le fichier
.gitmodules:[submodule "libs/utils"]path = libs/utilsurl = https://github.com/org/lib-utils.git -
Enregistre le commit exact du submodule dans l'index du projet parent
-
Écrit l'URL dans
.git/configdu projet parent, sous la clésubmodule.libs/utils.url: c'est cette copie locale, et non.gitmodules, que Git utilise réellement pour cloner
Commitez les changements :
git add .gitmodules libs/utilsgit commit -m "chore: ajouter lib-utils comme submodule"Cloner un projet avec submodules
Section intitulée « Cloner un projet avec submodules »En une seule commande
Section intitulée « En une seule commande »Un git clone ordinaire crée bien le dossier libs/utils/ mais le laisse
vide : Git connaît la référence, il ne l'a simplement pas suivie.
L'option --recurse-submodules enchaîne le clone du projet parent et
celui de chaque submodule dans la foulée. C'est la forme à retenir quand
vous récupérez un projet pour la première fois.
git clone --recurse-submodules https://github.com/org/mon-projet.gitSi vous avez déjà cloné
Section intitulée « Si vous avez déjà cloné »Le rattrapage se fait en deux temps, et cette séparation explique la
plupart des messages d'erreur. init recopie les URLs de .gitmodules
vers votre .git/config local, update va chercher le contenu au
commit exact enregistré par le projet parent. Oublier init donne un
fatal: No url found for submodule path.
git submodule init # Enregistre les URLs depuis .gitmodulesgit submodule update # Clone les submodules au commit référencéOu en une seule commande :
git submodule update --init --recursive--recursive gère aussi les submodules imbriqués (submodules de
submodules).
Mettre à jour un submodule
Section intitulée « Mettre à jour un submodule »Récupérer la dernière version
Section intitulée « Récupérer la dernière version »Mettre à jour un submodule, c'est deux opérations dans deux dépôts différents. Vous faites d'abord avancer le sous-dépôt, puis vous enregistrez cette nouvelle position dans le projet parent avec un commit. Sauter la seconde étape est l'oubli le plus courant : votre poste fonctionne, mais vos collègues récupèrent toujours l'ancienne version.
-
Allez dans le dossier du submodule :
Fenêtre de terminal cd libs/utils -
Mettez à jour depuis le remote :
Fenêtre de terminal git fetchgit checkout maingit pull -
Revenez au projet parent et commitez la nouvelle référence :
Fenêtre de terminal cd ../..git add libs/utilsgit commit -m "chore: mettre à jour lib-utils vers v2.1"
Raccourci : mettre à jour tous les submodules
Section intitulée « Raccourci : mettre à jour tous les submodules »Sans --remote, git submodule update ramène le submodule au commit
enregistré par le parent. Avec --remote, il fait l'inverse : il va
chercher la pointe de la branche distante et fait donc avancer le
submodule. Une seule lettre d'option sépare deux comportements opposés,
c'est la confusion la plus fréquente sur cette commande.
git submodule update --remoteEn l'absence de configuration, la branche suivie est celle vers laquelle
pointe le HEAD du dépôt distant. Vous pouvez en imposer une autre, par
exemple develop :
git submodule set-branch --branch develop -- libs/utilsCette commande écrit branch = develop dans .gitmodules, un fichier
versionné : pensez à le commiter pour que le choix s'applique à toute
l'équipe.
Travailler dans un submodule
Section intitulée « Travailler dans un submodule »Vous pouvez modifier le code du submodule directement :
-
Entrez dans le submodule et créez une branche :
Fenêtre de terminal cd libs/utilsgit switch -c fix/typo -
Modifiez, commitez :
Fenêtre de terminal git add .git commit -m "fix: corriger typo dans README" -
Poussez vers le remote du submodule :
Fenêtre de terminal git push origin fix/typo -
Revenez au projet parent et enregistrez le nouveau commit :
Fenêtre de terminal cd ../..git add libs/utilsgit commit -m "chore: avancer lib-utils (fix typo)"
--recurse-submodules partout
Section intitulée « --recurse-submodules partout »Ajoutez cette option aux commandes courantes pour ne pas oublier les submodules :
git pull --recurse-submodulesgit switch --recurse-submodules feature/ajout-logingit clone --recurse-submodules https://github.com/org/mon-projet.gitPour l'activer par défaut :
git config --global submodule.recurse trueSupprimer un submodule
Section intitulée « Supprimer un submodule »Il n'y a pas de commande unique, et c'est ce qui rend l'opération
piégeuse : un submodule laisse des traces à trois endroits. Le
.gitmodules versionné, le .git/config local, et le dépôt réel stocké
dans .git/modules/. Sauter la première étape ci-dessous laisse une
entrée submodule.libs/utils.url orpheline dans votre configuration
locale, qui ressortira lors d'un futur git submodule update.
# 1. Désenregistrer le submodule (vide le dossier, nettoie .git/config)git submodule deinit -f libs/utils
# 2. Supprimer l'entrée de .gitmodules et le dossier de l'indexgit rm libs/utils
# 3. Supprimer le dépôt interne conservé par Gitrm -rf .git/modules/libs/utils
# 4. Commitergit commit -m "chore: supprimer le submodule lib-utils"Vérifiez le résultat avant de commiter : git config --get-regexp '^submodule\.' ne doit plus rien renvoyer pour ce chemin.
foreach : commande sur tous les submodules
Section intitulée « foreach : commande sur tous les submodules »git submodule foreach exécute une commande shell dans chaque
submodule, l'un après l'autre. C'est utile pour une inspection groupée
sur un projet qui en compte plusieurs. Deux précautions : la commande
s'arrête au premier submodule en échec, et elle ne connaît rien du projet
parent, donc elle ne commite jamais la nouvelle référence pour vous.
# Afficher le statut de tous les submodulesgit submodule foreach 'git status'
# Mettre à jour tous les submodules vers leur branche suiviegit submodule update --remote# Ou, si vous voulez passer par git pull dans chaque submodule :# git submodule foreach 'git pull'
# Stasher dans tous les submodulesgit submodule foreach 'git stash'Pièges courants
Section intitulée « Pièges courants »Le submodule est en HEAD détaché
Section intitulée « Le submodule est en HEAD détaché »Après git submodule update, le submodule est toujours en detached
HEAD (il pointe vers un commit, pas une branche). Pour travailler
dedans, créez ou checkoutez une branche :
cd libs/utilsgit switch mainmodified content (new commits) dans git status
Section intitulée « modified content (new commits) dans git status »Le projet parent voit que le submodule pointe vers un commit différent
de celui référencé. C'est normal si vous avez fait un git pull dans
le submodule. Commitez la mise à jour dans le parent :
git add libs/utilsgit commit -m "chore: avancer lib-utils"git diff montre des submodules modifiés
Section intitulée « git diff montre des submodules modifiés »Par défaut, un git diff sur un submodule n'affiche que deux empreintes
de commit, ce qui ne dit rien de ce qui a réellement changé. Les options
ci-dessous demandent à Git de résumer les commits traversés plutôt
que les SHA bruts. C'est la seule façon de relire une mise à jour de
dépendance avant de la valider.
# Voir les détailsgit diff --submodule
# Résumégit diff --submodule=shortPour avoir le résumé automatiquement :
git config --global diff.submodule logSubmodules vs alternatives
Section intitulée « Submodules vs alternatives »La ligne qui décide dans neuf cas sur dix est Contribution au
sous-projet. Si votre équipe modifie régulièrement le code intégré, les
submodules sont le seul choix qui garde un vrai dépôt Git en local, avec
son historique et sa possibilité de pousser. Si vous consommez du code
sans jamais le modifier, un gestionnaire de paquets vous épargnera
toute la complexité décrite dans cette page. Le subtree est le
compromis pour ceux qui veulent un clone simple sans dépendance externe.
| Critère | Submodules | Subtree | Gestionnaire de paquets |
|---|---|---|---|
| Historiques | Séparés | Fusionné | Non versionné |
| Mise à jour | Manuelle (commit ref) | git subtree pull | npm update, etc. |
| Complexité | Moyenne-élevée | Moyenne | Faible |
| Clone | Nécessite --recurse | Automatique | Nécessite install |
| Contribution au sous-projet | Facile (push dans le submodule) | Possible (subtree push) | Via le repo original |
Dépannage
Section intitulée « Dépannage »Quatre de ces cinq symptômes ont la même origine : le projet parent
référence un commit que Git ne trouve pas, ou pas encore. Avant
d'appliquer une solution, lancez git submodule status à la racine du
projet : un préfixe - signale un submodule non initialisé, un + que
le commit sorti diffère de celui enregistré. Ce seul caractère oriente le
diagnostic plus vite que n'importe quel message d'erreur.
| Symptôme | Cause probable | Solution |
|---|---|---|
| Dossier submodule vide après clone | --recurse-submodules oublié | git submodule update --init --recursive |
| HEAD détaché dans le submodule | Comportement normal | git switch branche pour travailler |
reference is not a tree au clone | Commit du submodule non poussé | Pousser le submodule d'abord |
| Conflit sur la ref du submodule | Deux branches avancent le submodule | Résolvez en choisissant le bon commit |
fatal: No url found for submodule | .gitmodules absent ou corrompu | Vérifiez/recréez .gitmodules |
À retenir
Section intitulée « À retenir »- Un submodule référence un commit précis d'un dépôt externe
git submodule update --init --recursiveest la commande à retenir pour initialiser- Après
update, le submodule est en detached HEAD, normal - Poussez toujours le submodule avant le parent
submodule.recurse truesimplifie la vie au quotidien- Pour des besoins plus simples, considérez subtree