Alternatives à Git Submodule : Git Subtree

Nicola Paolucci
Nicola Paolucci
Retour à la liste

Internet regorge d'articles expliquant pourquoi vous ne devez pas utiliser les submodules Git. Je suis d'accord la plupart du temps, même si je ne suis pas très strict dans mon appréciation. Les submodules sont utiles dans certains cas, mais ils ont plusieurs inconvénients.

Existe-t-il des alternatives ? La réponse est : oui ! Il existe (au moins) deux outils permettant de suivre l'historique des dépendances de logiciel dans votre projet tout en vous permettant de continuer à utiliser Git :

Dans ce billet, j'explorerai git subtree et je vous expliquerai pourquoi il s'agit d'une avancée, bien qu'imparfaite, par rapport à git submodule.

À titre d'exemple, je vais vous parler de mon utilisation habituelle. Comment puis-je stocker et tenir à jour facilement les plug-ins VIM utilisés dans mes fichiers dotfiles ?

Pourquoi utiliser un subtree et pas un submodule ?

Vous aurez envie de privilégier subtree pour plusieurs raisons :

  • Il est facile de gérer un simple workflow.
  • Les anciennes versions de Git sont prises en charge (même avant v1.5.2).
  • Le code du sous-projet est disponible une fois que le superprojet est cloné.
  • subtree n'exige pas que les utilisateurs de votre dépôt développent de nouvelles compétences. Ils peuvent ignorer le fait que vous utilisez subtree pour gérer les dépendances.
  • subtree n'ajoute pas de nouveaux fichiers de métadonnées comme le fait submodules (p. ex., .gitmodule).
  • Le contenu du module peut être modifié sans avoir une copie de dépôt distincte de la dépendance à un autre emplacement.

À mon avis, les inconvénients sont acceptables :

  • Vous devez vous familiariser avec une nouvelle stratégie de merge (p. ex., subtree).
  • Revenir à upstream pour les sous-projets peut s'avérer un peu plus compliqué.
  • C'est à vous de vous assurer de ne pas mélanger le code du superprojet avec celui du sous-projet.

Comment utiliser git subtree ?

git subtree est disponible avec la version de série de Git, disponible depuis mai 2012 – 1.7.11+. La version de Homebrew sous OSX comporte déjà une commande subtree prête à l'emploi. Sur certaines plateformes, il vous faudra cependant suivre les instructions d'installation.

À présent, je vais vous montrer une utilisation classique de git subtree pour effectuer le suivi d'un plug-in vim.

La solution rapide sans suivi distant

Si vous souhaitez juste obtenir quelques commandes sur une ligne pour couper et coller, lisez simplement ce paragraphe.

Premièrement, ajoutez le subtree à un dossier prefix spécifique :

git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git master --squash

(La pratique courante consiste à ne pas stocker l'historique complet du sous-projet dans votre dépôt principal, mais si vous voulez le conserver, il vous suffit d'omettre le flag --squash.)

La commande ci-dessus génère la sortie suivante :

git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git master
warning: no common commits
remote: Counting objects: 338, done.
remote: Compressing objects: 100% (145/145), done.
remote: Total 338 (delta 101), reused 323 (delta 89)
Receiving objects: 100% (338/338), 71.46 KiB, done.
Resolving deltas: 100% (101/101), done.
From https://bitbucket.org/vim-plugins-mirror/vim-surround.git
* branch            master     -} FETCH_HEAD
Added dir '.vim/bundle/tpope-vim-surround'

Comme vous pouvez le constater, un commit de merge est enregistré alors que l'historique complet du dépôt vim-surround est mergé dans un seul :

1bda0bd [3 minutes ago] (HEAD, stree) Merge commit 'ca1f4da9f0b93346bba9a430c889a95f75dc0a83' as '.vim/bundle/tpope-vim-surround' [Nicola Paolucci]
ca1f4da [3 minutes ago] Squashed '.vim/bundle/tpope-vim-surround/' content from commit 02199ea [Nicola Paolucci]

Si après un moment, vous souhaitez mettre à jour le code du plug-in issu du dépôt upstream, il vous suffit d'exécuter subtree pull :

git subtree pull --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git master --squash

C'est très rapide et facile, mais les commandes sont un peu longues et difficiles à mémoriser. Nous pouvons les raccourcir en ajoutant le sous-projet en tant que remote.

Ajout du sous-projet en tant que remote

L'ajout du subtree en tant que remote nous permet d'y faire référence sous sa forme abrégée :

git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git

Nous pouvons ajouter le subtree (comme avant), mais nous pouvons désormais faire référence au remote sous sa forme abrégée :

git subtree add --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround master --squash

On obtient alors cette commande de mise à jour du sous-projet à une date ultérieure :

git fetch tpope-vim-surround master
git subtree pull --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround master --squash

Revenir à l'upstream

Désormais, nous pouvons librement faire un commit des corrections apportées au sous-projet dans notre répertoire de travail local.

Quand le moment est venu de revenir au projet en amont, il faut faire un fork du projet et l'ajouter comme un autre remote :

git remote add durdn-vim-surround ssh://git@bitbucket.org/durdn/vim-surround.git

À présent, nous pouvons utiliser la commande subtree push comme suit :

git subtree push --prefix=.vim/bundle/tpope-vim-surround/ durdn-vim-surround master

git push using:  durdn-vim-surround master
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 308 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To ssh://git@bitbucket.org/durdn/vim-surround.git
  02199ea..dcacd4b  dcacd4b21fe51c9b5824370b3b224c440b3470cb -} master

Ensuite, nous sommes prêts et nous pouvons ouvrir une pull-request adressée au mainteneur du package.

Sans l'aide de la commande subtree

git subtree diffère de la stratégie de merge subtree. Vous pouvez toujours utiliser la stratégie de merge, même si git subtree n'est plus disponible pour une raison ou une autre. Voici comment procéder :

Ajoutez la dépendance comme un simple remote Git :

git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git

Avant de consigner le contenu de la dépendance dans le dépôt, il est important d'enregistrer un merge pour pouvoir suivre l'arborescence complète du plug-in jusqu'au point suivant :

git merge -s ours --no-commit tpope-vim-surround/master

Qui génère :

Automatic merge went well; stopped before committing as requested

Ensuite, nous consignons le contenu du dernier objet arbre du dépôt du plug-in dans notre répertoire de travail prêt à être commité :

git read-tree --prefix=.vim/bundle/tpope-vim-surround/ -u tpope-vim-surround/master

À présent, nous pouvons faire un commit (il s'agira d'un commit de merge qui conservera l'historique de l'arborescence consigné) :

git ci -m"[subtree] adding tpope-vim-surround"

[stree 779b094] [subtree] adding tpope-vim-surround

Pour mettre à jour le projet, vous pouvez maintenant faire un pull en utilisant la stratégie de merge subtree :

git pull -s subtree tpope-vim-surround master

Conclusions

J'ai utilisé submodule pendant un certain temps et je suis nettement plus satisfait de git subtree, car bon nombre de problèmes liés à submodule n'ont plus lieu d'être et sont réglés grâce à subtree. Comme d'habitude et comme avec tout dans Git, il faut passer par une phase d'apprentissage pour tirer le meilleur parti de la fonctionnalité.

Suivez-moi (@durdn) et l'incroyable équipe @Bitbucket pour plus d'infos passionnantes sur Git.

Prêt à découvrir Git ?

Essayez ce tutoriel interactif.

Démarrez maintenant