Section courante

A propos

Section administrative du site

Définition

Un sous-module (submodule) dans Git est un dépôt Git imbriqué à l'intérieur d'un autre dépôt Git. Les sous-modules permettent d'intégrer et de gérer un dépôt Git distinct comme une partie d'un autre dépôt. Cela est particulièrement utile lorsque vous souhaitez inclure un projet externe dans un autre projet, tout en conservant les deux projets séparés.

Principe de fonctionnement

Utilisation des sous-modules

Les sous-modules sont particulièrement utiles dans les cas où vous travaillez sur des projets complexes dépendant d'autres projets, ou lorsque vous voulez partager un ensemble de bibliothèques ou de composantes entre différents projets sans les dupliquer.

Mise en situation

Il arrive souvent que lorsque vous travaillez sur un projet, vous ayez besoin d'utiliser un autre projet à partir de celui-ci. Il peut s'agir d'une bibliothèque développée par un tiers ou que vous développez séparément et que vous utilisez dans plusieurs projets parents. Un problème courant se pose dans ces scénarios : vous souhaitez pouvoir traiter les deux projets comme des projets distincts tout en étant en mesure d'utiliser l'un à partir de l'autre.

Voici un exemple. Supposons que vous développiez un site Web et que vous créiez des flux Atom. Au lieu d'écrire votre propre code générateur d'Atom, vous décidez d'utiliser une bibliothèque. Vous devrez probablement inclure ce code à partir d'une bibliothèque partagée comme une installation CPAN ou un gem de Ruby, ou copier le code source dans votre propre arborescence de projet. Le problème avec l'inclusion de la bibliothèque est qu'il est difficile de personnaliser la bibliothèque de quelque manière que ce soit et souvent plus difficile de la déployer, car vous devez vous assurer que chaque client dispose de cette bibliothèque. Le problème avec la copie du code dans votre propre projet est que toutes les modifications personnalisées que vous apportez sont difficiles à fusionner lorsque les modifications en amont deviennent disponibles.

Git résout ce problème à l'aide de sous-modules (submodule). Les sous-modules vous permettent de conserver un dépôt Git en tant que sous-répertoire d'un autre dépôt Git. Cela vous permet de cloner un autre dépôt dans votre projet et de conserver vos commits séparés.

Commencer par les sous-modules

Nous allons voir comment développer un projet simple ayant été divisé en un projet principal et quelques sous-projets.

Commençons par ajouter un dépôt Git existant en tant que sous-module du dépôt sur lequel nous travaillons. Pour ajouter un nouveau sous-module, utilisez la commande git submodule add avec l'URL absolue ou relative du projet que vous souhaitez commencer à suivre. Dans cet exemple, nous allons ajouter une bibliothèque appelée «MonSousModule» :

git submodule add https://github.com/gladir/MonSousModule

on obtiendra un résultat ressemblant à ceci :

Cloning into 'MonSousModule'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.

Par défaut, les sous-modules ajouteront le sous-projet dans un répertoire portant le même nom que le dépôt, dans ce cas «MonSousModule». Vous pouvez ajouter un chemin différent à la fin de la commande si vous souhaitez qu'il aille ailleurs.

Si vous exécutez git status à ce stade, vous remarquerez quelques éléments :

git status

on obtiendra un résultat ressemblant à ceci :

On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

new file:   .gitmodules
new file:   MonSousModule

Vous devriez d'abord remarquer le nouveau fichier .gitmodules. Il s'agit d'un fichier de configuration entreposant la cartographie entre l'URL du projet et le sous-répertoire local dans lequel vous l'avez extrait :

[submodule "MonSousModule"]
    path = MonSousModule
    url = https://github.com/gladir/MonSousModule

Remarque : Étant donné que l'URL du fichier .gitmodules est celle que les autres personnes essaieront d'abord de cloner/récupérer, assurez-vous d'utiliser une URL à laquelle elles peuvent accéder si possible. Par exemple, si vous utilisez une URL différente de celle à laquelle les autres personnes auraient accès pour effectuer le push, utilisez celle à laquelle les autres ont accès. Vous pouvez remplacer cette valeur localement avec git config submodule.MonSousModule.url PRIVATE_URL pour votre propre usage. Le cas échéant, une URL relative peut être utile.

L'autre liste dans la sortie de git status est l'entrée du dossier du projet. Si vous exécutez git diff dessus, vous voyez quelque chose d'intéressant :

git diff --cached MonSousModule

on obtiendra un résultat ressemblant à ceci :

diff --git a/MonSousModule b/MonSousModule
new file mode 160000
index 0000000..c3f01dc
--- /dev/null
+++ b/MonSousModule
@@ -0,0 +1 @@
+Subproject commit cbf01dc8862123d317dd47284b05b6892c7b29bc

Bien que MonSousModule soit un sous-répertoire de votre répertoire de travail, Git le considère comme un sous-module et ne suit pas son contenu lorsque vous n'êtes pas dans ce répertoire. Au lieu de cela, Git le considère comme un commit particulier de ce dépôt.

Si vous souhaitez une sortie de diff un peu plus agréable, vous pouvez passer l'option --submodule à git diff :

git diff --cached --submodule

on obtiendra un résultat ressemblant à ceci :

diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..71fc376
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "MonSousModule"]
+       path = MonSousModule
+       url = https://github.com/gladir/MonSousModule
Submodule MonSousModule 0000000...c3f01dc (new submodule)

Lorsque vous vous engagez, vous voyez quelque chose comme ceci :

git commit -am 'Add MonSousModule module'

on obtiendra un résultat ressemblant à ceci :

[master fb9093c] Add MonSousModule module
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 MonSousModule

Notez le mode 160000 pour l'entrée MonSousModule. Il s'agit d'un mode spécial dans Git signifiant essentiellement que vous enregistrez un commit en tant qu'entrée de répertoire plutôt qu'en tant que sous-répertoire ou fichier.

Enfin, appliquez ces modifications :

git push origin master

Cloner un projet avec des sous-modules

Nous allons ici cloner un projet contenant un sous-module. Lorsque vous clonez un tel projet, vous obtenez par défaut les répertoires contenant les sous-modules, mais aucun des fichiers qu'ils contiennent encore :

git clone https://github.com/gladir/MainProject

on obtiendra un résultat ressemblant à ceci :

Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.

Ensuite, vous allez voir dans le projet principal :

cd MainProject
ls -la

on obtiendra un résultat ressemblant à ceci :

total 16
drwxr-xr-x   9 schacon  staff  306 Sep 17 15:21 .
drwxr-xr-x   7 schacon  staff  238 Sep 17 15:21 ..
drwxr-xr-x  13 schacon  staff  442 Sep 17 15:21 .git
-rw-r--r--   1 schacon  staff   92 Sep 17 15:21 .gitmodules
drwxr-xr-x   2 schacon  staff   68 Sep 17 15:21 MonSousModule
-rw-r--r--   1 schacon  staff  756 Sep 17 15:21 Makefile
drwxr-xr-x   3 schacon  staff  102 Sep 17 15:21 includes
drwxr-xr-x   4 schacon  staff  136 Sep 17 15:21 scripts
drwxr-xr-x   4 schacon  staff  136 Sep 17 15:21 src

Ensuite, vous allez voir dans le projet MonSousModule :

cd MonSousModule/
ls

Le répertoire MonSousModule est présent, mais vide. Vous devez exécuter deux commandes : git submodule init pour initialiser votre fichier de configuration local et git submodule update pour récupérer toutes les données de ce projet et extraire le commit approprié répertorié dans votre super projet :

git submodule init

on obtiendra un résultat ressemblant à ceci :

Submodule 'MonSousModule' (https://github.com/gladir/MonSousModule) registered for path 'MonSousModule'

Ensuite, vous le mettez à jour :

git submodule update

on obtiendra un résultat ressemblant à ceci :

Cloning into 'MonSousModule'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'MonSousModule': checked out 'c3f01dc8872123d317dd46284b05b7892c7b29bc'

Votre sous-répertoire MonSousModule est désormais dans l'état exact où il se trouvait lorsque vous avez effectué votre commit plus tôt.

Il existe cependant une autre façon de procéder, un peu plus simple. Si vous passez --recurse-submodules à la commande git clone, elle initialisera et mettra automatiquement à jour chaque sous-module du dépôt, y compris les sous-modules imbriqués si l'un des sous-modules du dépôt en possède lui-même :

git clone --recurse-submodules https://github.com/gladir/MainProject

on obtiendra un résultat ressemblant à ceci :

Cloning into 'MainProject'...
remote: Counting objects: 14, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 14 (delta 1), reused 13 (delta 0)
Unpacking objects: 100% (14/14), done.
Checking connectivity... done.
Submodule 'MonSousModule' (https://github.com/gladir/MonSousModule) registered for path 'MonSousModule'
Cloning into 'MonSousModule'...
remote: Counting objects: 11, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 11 (delta 0), reused 11 (delta 0)
Unpacking objects: 100% (11/11), done.
Checking connectivity... done.
Submodule path 'MonSousModule': checked out 'c3f01dc8862123d317dd47284b05b6892c7b29bc'

Si vous avez déjà cloné le projet et oublié --recurse-submodules, vous pouvez combiner les étapes git submodule init et git submodule update en exécutant git submodule update --init. Pour initialiser, récupérer et extraire également tous les sous-modules imbriqués, vous pouvez utiliser la méthode infaillible git submodule update --init --recursive.



Dernière mise à jour : Vendredi, le 8 janvier 2021