Git Submodule vs. Git Subtree : Lequel Choisir ?
Submodule ou Subtree ? Découvrez les différences concrètes entre ces deux mécanismes Git et lequel choisir selon votre contexte.
Git Submodule vs. Git Subtree : Lequel Choisir ?
Gérer des dépendances ou du contenu partagé entre plusieurs dépôts Git est un défi courant. Que vous ayez un blogue dont les articles sont dans un dépôt séparé, une librairie de composants UI partagée, ou simplement un projet externe à intégrer, Git offre deux mécanismes principaux : submodule et subtree.
Beaucoup de développeurs commencent avec les submodules, car ils semblent être la solution “officielle” de Git. Malheureusement, cette approche vient avec son lot de frustrations : HEAD détachés, complexité dans les pipelines de CI/CD, et une expérience utilisateur qui laisse souvent à désirer.
Et si une meilleure solution existait, plus simple et mieux intégrée à votre workflow ? C’est là qu’intervient Git Subtree. Dans cet article, nous allons explorer les deux approches et vous aider à choisir la bonne pour votre projet. Si vous souhaitez ensuite passer d’un submodule à un subtree, consultez la suite : Migrer un Submodule vers un Subtree pas à pas.
1. Git Submodule – Définition et Fonctionnement
Un submodule est un pointeur vers un commit spécifique d’un autre dépôt. Votre dépôt principal (le projet parent) ne stocke pas le code du projet enfant, mais simplement une référence à son URL et au hash du commit.
Comment fonctionne un submodule ?
Lorsque vous ajoutez un submodule, Git crée un fichier .gitmodules à la racine de votre projet. Ce fichier contient la configuration de vos submodules, incluant leur chemin et leur URL.
[submodule "chemin/vers/submodule"]
path = chemin/vers/submodule
url = [email protected]:user/repo-enfant.git
Le dépôt principal enregistre alors un commit qui dit : “Au chemin/vers/submodule, je m’attends à trouver le commit abcdef123 du dépôt repo-enfant”.
Avantages réels
- Isolation parfaite : L’historique du submodule reste complètement séparé de celui du projet principal. C’est propre et clair.
- Gestion de version stricte : Vous pouvez verrouiller une dépendance à un commit très précis, garantissant qu’elle ne changera pas de manière inattendue.
Inconvénients concrets
- Expérience utilisateur (UX) complexe :
- Pour cloner un projet avec des submodules, il faut deux commandes :
git clonepuisgit submodule update --init --recursive. - En entrant dans un répertoire de submodule, vous vous retrouvez en état “detached HEAD”, ce qui est déroutant pour les débutants.
- Pousser une modification dans un submodule nécessite plusieurs étapes manuelles : aller dans le dossier, commiter, pousser, puis retourner au projet parent pour commiter le changement de pointeur.
- Pour cloner un projet avec des submodules, il faut deux commandes :
- CI/CD compliqué : Votre pipeline de déploiement doit être configuré pour initialiser les submodules, ce qui ajoute une étape et une source potentielle d’erreurs.
- Gestion des branches déconnectée : Le submodule ne suit pas automatiquement la branche du projet parent. Si vous changez de branche dans le parent, le submodule reste sur son commit épinglé.
2. Git Subtree – Définition et Fonctionnement
Un subtree, contrairement à un submodule, intègre directement les fichiers (et optionnellement l’historique) d’un autre dépôt dans un sous-répertoire de votre projet principal.
Comment fonctionne un subtree ?
La commande git subtree add agit comme une sorte de “copier-coller intelligent”. Elle fusionne le contenu et l’historique du dépôt externe dans votre projet. Pour les autres membres de l’équipe, il n’y a aucune différence : le sous-répertoire fait simplement partie du projet principal.
Avantages majeurs
- Simplicité extrême : Un simple
git clonedu projet parent suffit. Les collaborateurs n’ont même pas besoin de savoir qu’un subtree est utilisé. - CI/CD transparent : Votre pipeline de déploiement voit juste des fichiers dans un répertoire. Aucune configuration spéciale n’est nécessaire.
- Workflow unifié : Tout se passe dans le même dépôt. Pas besoin de jongler entre plusieurs contextes.
- Mises à jour simples : Des commandes dédiées (
git subtree pull,git subtree push) permettent de synchroniser facilement les modifications entre le projet principal et le dépôt externe.
Désavantages potentiels
- Historique fusionné : Si vous n’utilisez pas l’option
--squash, l’historique complet du dépôt externe est fusionné dans votre projet, ce qui peut le rendre plus “bruyant”. - Pousser est moins direct : Pousser des modifications du projet principal vers le dépôt externe demande une commande spécifique (
git subtree push). - Gestion des conflits : Lors d’un
git subtree pull, les conflits éventuels se gèrent exactement comme ungit mergeclassique, vos outils habituels suffisent.
3. Comparaison Claire : Submodule vs. Subtree
| Critère | Git Submodule | Git Subtree |
|---|---|---|
| Facilité d’usage | Difficile (commandes multiples, detached HEAD) | Simple (transparent pour les collaborateurs) |
| CI/CD | Complexe (configuration spéciale requise) | Simple (fonctionne sans configuration) |
| Gestion des branches | Déconnectée (pointeur sur un commit fixe) | Unifiée (fait partie du repo principal) |
| Mise à jour (Pull) | Manuelle et en plusieurs étapes | Simple via git subtree pull |
| Mise à jour (Push) | Manuelle et en plusieurs étapes | Simple via git subtree push |
| Historique Git | Séparé et propre | Fusionné (peut être bruyant sans --squash) |
| Isolation du code | Forte (dépôts physiquement distincts) | Faible (code intégré au repo principal) |
4. Quand choisir Submodule ?
Malgré ses défauts, le submodule reste pertinent dans quelques cas de figure :
- Dépendances tierces avec versionnement strict : Quand vous avez besoin de lier une version exacte d’une librairie externe et que vous ne voulez jamais la modifier.
- Projets matériels (Hardware) : Pour lier un firmware à un projet matériel, où la séparation stricte est une nécessité.
- Projets très volumineux : Si le dépôt externe est énorme et que vous ne voulez pas alourdir votre dépôt principal.
5. Quand choisir Subtree ?
Pour la grande majorité des projets web modernes, Subtree est la meilleure option.
- Gestion de contenu : Intégrer un blogue (fichiers
.mdxou.md) ou une documentation depuis un dépôt séparé. - Composants réutilisables : Partager une librairie de composants UI (React, Vue, etc.) entre plusieurs projets web.
- Monorepos légers : Quand vous voulez les avantages d’un monorepo sans la complexité des outils comme Lerna ou Turborepo.
- Simplification du workflow : Quand votre priorité est de rendre la vie de votre équipe (et de votre CI/CD) plus simple.
Conclusion
Pour la plupart des cas d’usage modernes, en particulier dans le développement web, Git Subtree offre une alternative bien plus simple, robuste et productive que Git Submodule. En intégrant directement le code externe, il élimine la friction pour les collaborateurs et simplifie radicalement les pipelines de déploiement.
Convaincu ? Retrouvez le guide complet pour migrer votre submodule existant vers un subtree : Migrer un Submodule vers un Subtree pas à pas.