git subtree fusionne un dépôt externe dans un sous-dossier de votre
projet, sans métadonnées séparées. Contrairement aux submodules, les
collaborateurs n’ont rien de spécial à faire au clone — le code est
directement dans le repo. Ce guide couvre l’ajout, la mise à jour, la
contribution en retour et le comparatif avec les submodules.
Prérequis : Submodules et Remotes fondamentaux.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Ajouter un dépôt externe avec
git subtree addsans fichier de configuration - Mettre à jour et contribuer des modifications vers le dépôt source
- Comprendre les différences entre subtree et submodule
- Choisir la stratégie adaptée selon votre organisation et vos équipes
Pourquoi subtree plutôt que submodule ?
Section intitulée « Pourquoi subtree plutôt que submodule ? »Les submodules demandent à chaque collaborateur de connaître les
commandes submodule. Un subtree est transparent :
- Le code est dans le repo — pas de référence externe
git clonerécupère tout, rien à initialiser- Pas de
.gitmodules, pas de HEAD détaché - Les outils CI/CD fonctionnent sans configuration spéciale
Le compromis : l’historique est mélangé et les mises à jour sont plus verbeuses.
Ajouter un dépôt avec subtree
Section intitulée « Ajouter un dépôt avec subtree »# Ajouter le remote pour simplifier les futures commandesgit remote add lib-utils https://github.com/org/lib-utils.gitgit fetch lib-utils
# Intégrer dans un sous-dossiergit subtree add --prefix=libs/utils lib-utils main --squash--prefix=libs/utils: dossier de destinationlib-utils main: remote et branche source--squash: compresse l’historique en un seul commit (recommandé pour garder un historique lisible)
Le résultat est un ou deux commits dans votre historique :
abc1234 Squashed 'libs/utils/' content from commit e4f5a6bdef5678 Merge commit 'abc1234' as 'libs/utils'Mettre à jour depuis l’amont
Section intitulée « Mettre à jour depuis l’amont »git fetch lib-utilsgit subtree pull --prefix=libs/utils lib-utils main --squashGit fusionne les nouveautés de lib-utils/main dans votre
sous-dossier. Avec --squash, un seul commit de merge apparaît dans
votre historique.
Contribuer en retour (push)
Section intitulée « Contribuer en retour (push) »Vous avez modifié du code dans libs/utils/ et voulez renvoyer les
changements au dépôt d’origine :
git subtree push --prefix=libs/utils lib-utils fix/correctionGit extrait les commits qui touchent libs/utils/, réécrit les chemins
et les pousse vers la branche fix/correction du remote lib-utils.
Créez ensuite une pull request sur le dépôt d’origine.
Alternative avec split
Section intitulée « Alternative avec split »split extrait un historique nettoyé sans pousser :
git subtree split --prefix=libs/utils -b subtree-branchgit push lib-utils subtree-branch:fix/correctionUtile si vous voulez inspecter les commits avant de pousser.
Workflow complet
Section intitulée « Workflow complet »# 1. Ajouter le remote et le subtreegit remote add lib-utils https://github.com/org/lib-utils.gitgit subtree add --prefix=libs/utils lib-utils main --squash
# 2. Travailler normalement — les fichiers sont dans libs/utils/git add libs/utils/src/helper.pygit commit -m "fix: corriger le helper dans lib-utils"
# 3. Mettre à jour depuis l'amontgit subtree pull --prefix=libs/utils lib-utils main --squash
# 4. Contribuer en retourgit subtree push --prefix=libs/utils lib-utils fix/correctionSubmodule vs subtree
Section intitulée « Submodule vs subtree »| Critère | Submodule | Subtree |
|---|---|---|
| Métadonnées | .gitmodules + ref dans l’index | Aucune — code dans le repo |
| Clone | --recurse-submodules nécessaire | Clone standard |
| Historique | Séparé (chaque repo le sien) | Fusionné dans le parent |
| Mise à jour | submodule update | subtree pull |
| Contribution | Push dans le submodule directement | subtree push (extraction) |
| Complexité | Moyenne-élevée | Moyenne |
| Taille du repo | Petite (référence seulement) | Plus grande (code intégré) |
| CI/CD | Configuration nécessaire | Transparent |
| Détached HEAD | Oui (après update) | Non |
Quand choisir subtree
Section intitulée « Quand choisir subtree »- Le sous-dépôt est rarement mis à jour
- Les collaborateurs ne connaissent pas les submodules
- L’intégration CI/CD doit être simple
- Le code du sous-dépôt est petit
Quand choisir submodule
Section intitulée « Quand choisir submodule »- Le sous-dépôt évolue souvent et indépendamment
- Plusieurs projets référencent le même sous-dépôt
- Vous voulez une version figée précise
- Le sous-dépôt est volumineux
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
Conflits au subtree pull | Mélange --squash / pas --squash | Restez cohérent : toujours --squash ou jamais |
subtree push est lent | Historique volumineux à parcourir | Utilisez split + push séparés |
Working tree has modifications | Fichiers non commités | Commitez ou stashez avant le subtree pull |
refusing to merge unrelated histories | Oubli de --squash au premier add | Recommencez avec --squash ou ajoutez --allow-unrelated-histories |
À retenir
Section intitulée « À retenir »git subtree addintègre un dépôt dans un sous-dossier — aucune métadonnée externegit subtree pullmet à jour,pushrenvoie les modifications--squashcompresse l’historique — gardez la cohérence- Subtree = transparence et simplicité, submodule = séparation et contrôle
- Les collaborateurs n’ont rien de spécial à faire au clone