4min.

L’option reference de git clone

Il existe une option dans git pour cloner un dépôt qui n’est pas très connue mais qui mérite pourtant de l’être d’avantage.

Section intitulée prenons-quelques-cas-d-utilisation-pour-illustrer-cette-optionPrenons quelques cas d’utilisation pour illustrer cette option

Section intitulée le-serveur-de-buildLe serveur de build

Sur un serveur de build ou lors d’un déploiement, vous avez besoin du dépôt git pour construire l’application. Mais ce dépôt ne doit contenir aucun artefact d’un build précédent. En effet, nous ne voulons pas envoyer en prod des fichiers inutiles, ou des fichiers de configuration obsolète. De plus, il faut être capable de builder plusieurs branches en parallèle.

Nous pourrions être tentés d’utiliser la solution suivante, dans un dossier où le repo est déjà sur la machine :

cd /home/build/projectX/
git fetch 
git reset --hard <SHA>
git clean -fdx # Supprime tout ce qui n’est pas tracké par git, même ce qui est ignoré

… mais cela ne permettra pas de builder plusieurs branches en parallèle (il faut un dossier par build). De plus, nous ne sommes jamais à l’abri d’un oubli de git clean -fdx qui pourrait laisser des artefacts d’un build précédent à cause d’un problème de droit (been there!).

Section intitulée en-localEn local

En local, vous voulez tester dans un environnement propre. C’est-à-dire que vous voulez un dépôt nu, sans configuration, etc. Cela peut être utile pour tester des scripts de déploiement, des scripts de build, etc. Ici, vous ne voulez pas supprimer toutes vos configurations, vous pouvez alors faire un git clone mais cela peut être un peu lent si le dépôt est gros.

Section intitulée la-ciLa CI

Il est possible d’optimiser certaines CI quand les planètes sont alignées. Par exemple, avec GitLab, quand il n’existe qu’un hosted runner. Nous pouvons utiliser le même dossier pour plusieurs jobs. Cela permet de ne pas avoir à cloner le dépôt a chaque job, de télécharger les dépendances une seule fois, etc.

Comme en local, nous pourrions utiliser git clone, mais cela va induire de la latence sur le premier job de build. Surtout que GitLab a déjà cloné le projet ! Et qu’il n’est pas rare de voir des repository de plusieurs centaines de Mo, voire plusieurs Go.

Section intitulée la-solutionLa solution

La solution est d’utiliser l’option --reference de git clone. Celle-ci permet de cloner un dépôt en utilisant un autre dépôt local comme référence. Cela permet de ne pas avoir à télécharger les objets git déjà présents dans le dépôt de référence.

De plus, git va automatiquement le mettre à jour avec les objets manquants. Cela permet de ne pas avoir à gérer sa mise à jour.

Section intitulée exemple-du-serveur-de-buildExemple du serveur de build

Avec le layout suivant :

  • /home/build/projectX/reference.git/ : Dépôt de référence, qui peut même être cloné avec --bare pour économiser de l’espace disque ;
  • /home/build/projectX/build/0001 : Le dépôt nu pour le build 0001 que l’on veut cloner.

Nous allons lancer la commande suivante :

git clone \ #
    --reference /home/build/projectX/reference.git/  \  # le dépôt de référence
    git@github.com/jolicode/projectX.git \              # la source
    /home/build/projectX/build/0001                     # la destination

git va alors (retranscription très approximative de la réalité) :

  1. Mettre à jour le dépôt de référence avec les objets manquants
    cd /home/build/projectX/reference.git/ && git fetch
    
  2. Cloner le dépôt en utilisant le dépôt de référence
    git clone /home/build/projectX/reference.git/ /home/build/projectX/build/0001
    
  3. Mettre à jour la configuration du dépôt cloné pour mettre le vrai upstream
    cd /home/build/projectX/build/0001 && git remote set-url origin git@github.com/jolicode/projectX.git
    
    tout en gardant le dépôt de référence pour les objets git.

Et voilà, vous avez un dépôt cloné très rapidement, sans aucun artefact précédent et qui est prêt à être utilisé pour un build.

Le clone a été très rapide car il n’a pas été nécessaire de télécharger depuis le git distant les objets déjà présents dans le dépôt de référence. Ce n’est qu’une copie locale des objets déjà présents.

Nous pouvons même aller encore plus loin pour optimiser le clone lors d’un build :

git clone \ #
    --reference /home/build/projectX/reference.git/  \  # le dépôt de référence
    --depth 1 \                                         # seulement le dernier commit
    --branch prod \                                     # de la branch prod
    git@github.com/jolicode/projectX.git \              # la source
    /home/build/projectX/build/0001                     # la destination

Avec cette commande, vous n’avez que le dernier commit de la branche prod. Pas besoin de gérer des git fetch / git reset / git checkout, git le fait pour vous en une commande !

Section intitulée exemple-pour-la-ciExemple pour la CI

Les moteurs d’intégration continue clonent déjà le dépôt pour vous. Vous pouvez alors utiliser le dépôt cloné comme référence pour les autres jobs. Cependant, ils utilisent déjà l’option --depth 1 pour ne cloner que le dernier commit. Il vous faudra alors utiliser l’option unshallow pour que le dépôt cloné soit complété avec tous les objets git du projet.

git fetch --unshallow

Vous n’aurez ensuite plus qu’à utiliser la commande qu’on a vue plus haut 🎉

Utiliser cette technique vous fera gagner du temps et de la bande passante, il serait dommage de s’en passer. Joyeux clonage !

Commentaires et discussions

Nos formations sur ce sujet

Notre expertise est aussi disponible sous forme de formations professionnelles !

Voir toutes nos formations