Comment utiliser Git Hooks pour automatiser des tâches de développement et de déploiement

introduction

Le contrôle de version est devenu une exigence centrale du développement de logiciels modernes. Il permet aux projets de suivre les modifications en toute sécurité et d’activer les inversions, la vérification de l’intégrité et la collaboration, entre autres avantages. Le système de contrôle de version `+ git + ', en particulier, a été largement adopté ces dernières années en raison de son architecture décentralisée et de la rapidité avec laquelle il peut effectuer et transférer des modifications entre les parties.

Bien que la suite d’outils + git + offre de nombreuses fonctionnalités bien implémentées, l’une des caractéristiques les plus utiles est sa flexibilité. Grâce à l’utilisation d’un système de «points d’ancrage», git permet aux développeurs et aux administrateurs d’étendre les fonctionnalités en spécifiant les scripts que git appellera en fonction de différents événements et actions.

Dans ce guide, nous explorerons l’idée des git hooks et montrerons comment implémenter du code pouvant vous aider à automatiser des tâches dans votre propre environnement. Nous utiliserons un serveur Ubuntu 14.04 dans ce guide, mais tout système pouvant exécuter git devrait fonctionner de la même manière.

Conditions préalables

Avant de commencer, vous devez avoir installé + git + sur votre serveur. Si vous suivez Ubuntu 14.04, vous pouvez consulter notre guide sur how pour installer git sur Ubuntu 14.04 ici.

Vous devriez être familiarisé avec l’utilisation de git dans un sens général. Si vous avez besoin d’une introduction, la série dont l’installation fait partie est intitulée Introduction à Git: Installation , Utilisation et branches est un bon point de départ.

Lorsque vous avez terminé avec les exigences ci-dessus, continuez.

Idée de base avec des crochets Git

Les crochets Git sont un concept assez simple qui a été mis en œuvre pour répondre à un besoin. Lors du développement de logiciels sur un projet partagé, du respect des normes de guides de style ou du déploiement de logiciels (toutes sont des situations dans lesquelles git est souvent impliqué), vous souhaiterez souvent effectuer des tâches répétitives chaque fois qu’une action est entreprise.

Les hooks Git sont basés sur des événements. Lorsque vous exécutez certaines commandes git, le logiciel vérifie le répertoire + hooks + dans le référentiel git pour voir si un script associé doit être exécuté.

Certains scripts s’exécutent avant une action, ce qui peut être utilisé pour assurer la conformité du code aux normes, pour la vérification de la cohérence ou pour configurer un environnement. D’autres scripts s’exécutent après un événement pour déployer du code, rétablir les autorisations appropriées (quelque chose que git ne peut pas très bien suivre), etc.

En utilisant ces capacités, il est possible d’appliquer des stratégies, d’assurer la cohérence, de contrôler votre environnement et même de gérer des tâches de déploiement.

Le livre Pro Git de Scott Chacon tente de diviser les différents types d’hameçons en catégories. Il les classe comme tels:

  • Crochets côté client: Crochets appelés et exécutés sur l’ordinateur du commetteur. Celles-ci sont à leur tour divisées en quelques catégories distinctes:

  • Crochets Committing-Workflow: Les crochets de validation sont utilisés pour dicter les actions à entreprendre lorsqu’un commit est en cours. Ils sont utilisés pour exécuter des contrôles de cohérence, pré-renseigner des messages de validation et vérifier leurs détails. Vous pouvez également l’utiliser pour fournir des notifications lors de la validation.

  • Crochets de flux de travail de messagerie: cette catégorie de crochets englobe les actions entreprises lors de l’utilisation de correctifs envoyés par courrier électronique. Des projets tels que le noyau Linux soumettent et révisent les correctifs à l’aide d’une méthode de courrier électronique. Celles-ci sont dans la même veine que les hooks de validation, mais peuvent être utilisées par les responsables qui sont responsables de l’application du code soumis.

  • Autre: D’autres points d’ancrage côté client incluent les points d’accrochage exécutés lors de la fusion, de l’extraction de code, de la redéfinition de la base, de la réécriture et du nettoyage des pensions.

  • Hooks côté serveur: Ces hooks sont exécutés sur des serveurs utilisés pour recevoir des envois. Généralement, ce serait le dépôt principal git pour un projet. Encore une fois, Chacon a divisé ces catégories en catégories:

  • Pré-réception et post-réception: elles sont exécutées sur le serveur recevant un push pour effectuer des tâches telles que la vérification de la conformité du projet et le déploiement après un push.

  • Mise à jour: Cela ressemble à une pré-réception, mais fonctionne branche par branche pour exécuter du code avant que chaque branche ne soit acceptée.

Ces catégorisations sont utiles pour avoir une idée générale des événements pour lesquels vous pouvez éventuellement configurer un hook. Mais pour comprendre réellement le fonctionnement de ces éléments, il est préférable d’expérimenter et de déterminer les solutions que vous essayez de mettre en œuvre.

Certains crochets prennent également des paramètres. Cela signifie que lorsque git appelle le script pour le hook, il transmettra des données pertinentes que le script pourra ensuite utiliser pour effectuer des tâches. Au complet, les crochets disponibles sont:

Hook Name Invoked By Description Parameters (Number and Description)

applypatch-msg

git am

Can edit the commit message file and is often used to verify or actively format a patch’s message to a project’s standards. A non-zero exit status aborts the commit.

(1) name of the file containing the proposed commit message

pre-applypatch

git am

This is actually called after the patch is applied, but before the changes are committed. Exiting with a non-zero status will leave the changes in an uncommitted state. Can be used to check the state of the tree before actually committing the changes.

(none)

post-applypatch

git am

This hook is run after the patch is applied and committed. Because of this, it cannot abort the process, and is mainly used for creating notifications.

(none)

pre-commit

git commit

This hook is called before obtaining the proposed commit message. Exiting with anything other than zero will abort the commit. It is used to check the commit itself (rather than the message).

(none)

prepare-commit-msg

git commit

Called after receiving the default commit message, just prior to firing up the commit message editor. A non-zero exit aborts the commit. This is used to edit the message in a way that cannot be suppressed.

(1 to 3) Name of the file with the commit message, the source of the commit message (message, template, merge, squash, or commit), and the commit SHA-1 (when operating on an existing commit).

commit-msg

git commit

Can be used to adjust the message after it has been edited in order to ensure conformity to a standard or to reject based on any criteria. It can abort the commit if it exits with a non-zero value.

(1) The file that holds the proposed message.

post-commit

git commit

Called after the actual commit is made. Because of this, it cannot disrupt the commit. It is mainly used to allow notifications.

(none)

pre-rebase

git rebase

Called when rebasing a branch. Mainly used to halt the rebase if it is not desirable.

(1 or 2) The upstream from where it was forked, the branch being rebased (not set when rebasing current)

post-checkout

git checkout and git clone

Run when a checkout is called after updating the worktree or after git clone. It is mainly used to verify conditions, display differences, and configure the environment if necessary.

(3) Ref of the previous HEAD, ref of the new HEAD, flag indicating whether it was a branch checkout (1) or a file checkout (0)

post-merge

git merge or git pull

Called after a merge. Because of this, it cannot abort a merge. Can be used to save or apply permissions or other kinds of data that git does not handle.

(1) Flag indicating whether the merge was a squash.

pre-push

git push

Called prior to a push to a remote. In addition to the parameters, additional information, separated by a space is passed in through stdin in the form of “<local ref> <local sha1> <remote ref> <remote sha1>”. Parsing the input can get you additional information that you can use to check. For instance, if the local sha1 is 40 zeros long, the push is a delete and if the remote sha1 is 40 zeros, it is a new branch. This can be used to do many comparisons of the pushed ref to what is currently there. A non-zero exit status aborts the push.

(2) Name of the destination remote, location of the destination remote

pre-receive

git-receive-pack on the remote repo

This is called on the remote repo just before updating the pushed refs. A non-zero status will abort the process. Although it receives no parameters, it is passed a string through stdin in the form of “<old-value> <new-value> <ref-name>” for each ref.

(none)

update

git-receive-pack on the remote repo

This is run on the remote repo once for each ref being pushed instead of once for each push. A non-zero status will abort the process. This can be used to make sure all commits are only fast-forward, for instance.

(3) The name of the ref being updated, the old object name, the new object name

post-receive

git-receive-pack on the remote repo

This is run on the remote when pushing after the all refs have been updated. It does not take parameters, but receives info through stdin in the form of “<old-value> <new-value> <ref-name>”. Because it is called after the updates, it cannot abort the process.

(none)

post-update

git-receive-pack on the remote repo

This is run only once after all of the refs have been pushed. It is similar to the post-receive hook in that regard, but does not receive the old or new values. It is used mostly to implement notifications for the pushed refs.

(?) A parameter for each of the pushed refs containing its name

pre-auto-gc

git gc --auto

Is used to do some checks before automatically cleaning repos.

(none)

post-rewrite

git commit --amend, git-rebase

This is called when git commands are rewriting already committed data. In addition to the parameters, it receives strings in stdin in the form of “<old-sha1> <new-sha1>”.

(1) Name of the command that invoked it (amend or rebase)

Maintenant que vous avez toutes ces informations générales, nous pouvons montrer comment les implémenter dans quelques scénarios.

Mise en place d’un référentiel

Pour commencer, nous allons créer un nouveau référentiel vide dans notre répertoire de base. Nous appellerons cela + proj +.

mkdir ~/proj
cd ~/proj
git init
Initialized empty Git repository in /home/demo/proj/.git/

Nous sommes maintenant dans le répertoire de travail vide d’un répertoire contrôlé par git. Avant de faire autre chose, passons au référentiel qui est stocké dans le fichier caché appelé + .git + dans ce répertoire:

cd .git
ls -F
branches/  config  description  HEAD  hooks/  info/  objects/  refs/

Nous pouvons voir un certain nombre de fichiers et de répertoires. Celui qui nous intéresse est le répertoire + hooks +:

cd hooks
ls -l
total 40
-rwxrwxr-x 1 demo demo  452 Aug  8 16:50 applypatch-msg.sample
-rwxrwxr-x 1 demo demo  896 Aug  8 16:50 commit-msg.sample
-rwxrwxr-x 1 demo demo  189 Aug  8 16:50 post-update.sample
-rwxrwxr-x 1 demo demo  398 Aug  8 16:50 pre-applypatch.sample
-rwxrwxr-x 1 demo demo 1642 Aug  8 16:50 pre-commit.sample
-rwxrwxr-x 1 demo demo 1239 Aug  8 16:50 prepare-commit-msg.sample
-rwxrwxr-x 1 demo demo 1352 Aug  8 16:50 pre-push.sample
-rwxrwxr-x 1 demo demo 4898 Aug  8 16:50 pre-rebase.sample
-rwxrwxr-x 1 demo demo 3611 Aug  8 16:50 update.sample

Nous pouvons voir quelques choses ici. Premièrement, nous pouvons voir que chacun de ces fichiers est marqué comme exécutable. Étant donné que ces scripts ne sont appelés que par leur nom, ils doivent être exécutables et leur première ligne doit être une référence shebang pour appeler le bon interprète de script . Le plus souvent, il s’agit de langages de script tels que bash, perl, python, etc.

La deuxième chose que vous remarquerez peut-être est que tous les fichiers se terminent par + .sample a. C’est parce que git regarde simplement le nom du fichier lorsque vous essayez de trouver les fichiers hook à exécuter. Déviant du nom du script, git cherche à le désactiver. Pour activer n’importe quel script de ce répertoire, il faudrait supprimer le suffixe + .sample +.

Revenons dans notre répertoire de travail:

cd ../..

Premier exemple: déploiement sur un serveur Web local avec un crochet post-validation

Notre premier exemple utilisera le hook + post-commit + pour vous montrer comment déployer sur un serveur Web local chaque fois qu’une validation est effectuée. Ce n’est pas le crochet que vous utiliseriez pour un environnement de production, mais cela nous permet de démontrer quelques éléments importants, à peine documentés, que vous devriez connaître lorsque vous utilisez des crochets.

Tout d’abord, nous allons installer le serveur Web Apache pour démontrer:

sudo apt-get update
sudo apt-get install apache2

Pour que notre script modifie la racine Web sous + / var / www / html + (c’est la racine du document sur Ubuntu 14.04. Modifier au besoin), nous devons avoir une autorisation en écriture. Donnons à notre utilisateur normal la propriété de ce répertoire. Vous pouvez le faire en tapant:

sudo chown -R `whoami`:`id -gn` /var/www/html

Maintenant, dans notre répertoire de projet, créons un fichier + index.html +:

cd ~/proj
nano index.html

À l’intérieur, nous pouvons ajouter un peu de HTML simplement pour illustrer l’idée. Cela ne doit pas être compliqué:

<h1>Here is a title!</h1>

<p>Please deploy me!</p>

Ajoutez le nouveau fichier pour indiquer à git de suivre le fichier:

git add .

Maintenant, avant de vous engager, nous allons configurer notre hook + post-commit + pour le référentiel. Créez ce fichier dans le répertoire + .git / hooks + pour le projet:

vim .git/hooks/post-commit

Avant de voir ce qu’il faut mettre dans ce fichier, nous devons en apprendre un peu plus sur la façon dont git configure l’environnement lors de l’exécution de hooks.

Un côté des variables environnementales avec les crochets Git

Avant de commencer notre script, nous devons en apprendre un peu plus sur les variables d’environnement définies par git lors de l’appel de hooks. Pour que notre script fonctionne, nous devrons éventuellement annuler la définition d’une variable d’environnement que git définit lors de l’appel du hook + post-commit.

C’est un point très important à intérioriser si vous souhaitez écrire des hooks git fonctionnant de manière fiable. Git définit différentes variables d’environnement en fonction du hook appelé. Cela signifie que l’environnement à partir duquel git tire les informations sera différent selon le hook.

Le premier problème avec cela est que cela peut rendre votre environnement de script très imprévisible si vous ne savez pas quelles variables sont définies automatiquement. Le deuxième problème est que les variables définies sont presque complètement absentes de la propre documentation de git.

Heureusement, Mark Longair a mis au point la méthode a pour tester chacune des variables que git définit lors de l’exécution de ces points d’ancrage. Cela implique de mettre le contenu suivant dans différents scripts git hook:

#!/bin/bash
echo Running $BASH_SOURCE
set | egrep GIT
echo PWD is $PWD

Les informations sur son site datent de 2011 et fonctionnent avec la version 1.7.1 de git. Quelques modifications ont donc été apportées. Au moment d’écrire ces lignes en août 2014, la version actuelle de git dans Ubuntu 14.04 est 1.9.1.

Les résultats des tests sur cette version de git sont présentés ci-dessous (y compris le répertoire de travail tel que vu par git lors de l’exécution de chaque hook). Le répertoire de travail local pour le test était + / home / demo / test_hooks + et la télécommande nue (le cas échéant) était + / home / demo / origin / test_hooks.git +:

  • * Crochets *: + applypatch-msg +, '+ pre-applypatch + , + post-applypatch + `

  • Variables environnementales:

  • + GIT_AUTHOR_DATE = 'Lun, 11 août 2014 11:25:16 -0400' +

  • + GIT_AUTHOR_EMAIL = demo @ example.com +

  • + GIT_AUTHOR_NAME = 'Utilisateur de démonstration' +

  • + GIT_INTERNAL_GETTEXT_SH_SCHEME = gnu +

  • + GIT_REFLOG_ACTION = am +

  • * Répertoire de travail *: + / home / demo / test_hooks +

  • * Crochets *: + pré-commit,` + prepare-commit-msg`, + commit-msg +, + post-commit

  • Variables environnementales:

  • + GIT_AUTHOR_DATE = '@ 1407774159 -0400' +

  • + GIT_AUTHOR_EMAIL = demo @ example.com +

  • + GIT_AUTHOR_NAME = 'Utilisateur de démonstration' +

  • + GIT_DIR = .git +

  • + GIT_EDITOR =: +

  • + GIT INDEX FILE = .git / index

  • + GIT_PREFIX = +

  • * Répertoire de travail *: + / home / demo / test_hooks +

  • * Crochets *: + pré-rebase +

  • Variables environnementales:

  • + GIT_INTERNAL_GETTEXT_SH_SCHEME = gnu +

  • + GIT_REFLOG_ACTION = rebase +

  • * Répertoire de travail *: + / home / demo / test_hooks +

  • * Crochets *: + post-checkout +

  • Variables environnementales:

  • + GIT_DIR = .git +

  • + GIT_PREFIX = +

  • * Répertoire de travail *: + / home / demo / test_hooks +

  • * Crochets *: + post-fusion

  • Variables environnementales:

  • + GITHEAD_4b407c …​ +

  • + GIT_DIR = .git +

  • + GIT_INTERNAL_GETTEXT_SH_SCHEME = gnu +

  • + GIT_PREFIX = +

  • + GIT_REFLOG_ACTION = 'tirer l’autre maître' +

  • * Répertoire de travail *: + / home / demo / test_hooks +

  • * Crochets *: + pré-push +

  • Variables environnementales:

  • + GIT_PREFIX = +

  • * Répertoire de travail *: + / home / demo / test_hooks +

  • * Crochets *: + pré-réception,` + mise à jour`, + post-réception,` + post-mise à jour`

  • Variables environnementales:

  • + GIT_DIR =. +

  • * Répertoire de travail *: + / home / demo / origin / test_hooks.git +

  • * Crochets *: + pré-auto-gc +

  • (inconnu car cela est difficile à déclencher de manière fiable)

  • * Crochets *: + post-rewrite +

  • Variables environnementales:

  • + GIT_AUTHOR_DATE = '@ 1407773551 -0400' +

  • + GIT_AUTHOR_EMAIL = demo @ example.com +

  • + GIT_AUTHOR_NAME = 'Utilisateur de démonstration' +

  • + GIT_DIR = .git +

  • + GIT_PREFIX = +

  • * Répertoire de travail *: + / home / demo / test_hooks +

Ces variables ont une incidence sur la façon dont git voit son environnement. Nous utiliserons les informations ci-dessus sur les variables pour nous assurer que notre script prend correctement en compte son environnement.

Retour au script

Maintenant que vous avez une idée du type d’environnement qui sera mis en place (regardez les variables définies pour le hook + post-commit +), nous pouvons commencer notre script.

Puisque les hooks git sont des scripts standard, nous devons dire à git quel interpréteur utiliser:

#!/bin/bash

Après cela, nous allons juste utiliser git lui-même pour décompresser la version la plus récente du dépôt après la validation dans notre répertoire web. Pour ce faire, nous devons définir notre répertoire de travail sur la racine du document d’Apache. Nous devrions également définir notre répertoire git sur le repo.

Nous voudrons forcer cette transaction pour nous assurer qu’elle réussit à chaque fois, même s’il existe des conflits entre ce qui se trouve actuellement dans le répertoire de travail. Ça devrait ressembler à ça:

#!/bin/bash
git --work-tree=/var/www/html --git-dir=/home//proj/.git checkout -f

À ce stade, nous avons presque terminé. Cependant, nous devons examiner de plus près les variables d’environnement définies chaque fois que le hook + post-commit + est appelé. En particulier, + GIT_INDEX_FILE + est défini sur + .git / index.

Ce chemin est en relation avec le répertoire de travail, qui dans ce cas est + / var / www / html +. Comme l’index git n’existe pas à cet emplacement, le script échouera si on le laisse tel quel. Pour éviter cette situation, nous pouvons manuellement unset la variable, ce qui obligera git à effectuer une recherche par rapport au répertoire repo, comme il le fait habituellement. Nous devons ajouter ceci * au-dessus * de la ligne de paiement:

#!/bin/bash

git --work-tree=/var/www/html --git-dir=/home//proj/.git checkout -f

Ces types de conflits expliquent pourquoi les problèmes de git hook sont parfois difficiles à diagnostiquer. Vous devez être conscient de la manière dont git a construit l’environnement dans lequel il travaille.

Lorsque vous avez terminé ces modifications, enregistrez et fermez le fichier.

Comme il s’agit d’un fichier de script standard, nous devons le rendre exécutable:

chmod +x .git/hooks/post-commit

Nous sommes enfin prêts à appliquer les modifications apportées à notre dépôt Git. Assurez-vous de revenir dans le bon répertoire, puis validez les modifications:

cd ~/proj
git commit -m "here we go..."

Maintenant, si vous visitez le nom de domaine ou l’adresse IP de votre serveur dans votre navigateur, vous devriez voir le fichier + index.html + que vous avez créé:

http://

image: https: //assets.digitalocean.com/articles/git_hooks/first_deploy.png [Test index.html]

Comme vous pouvez le constater, nos modifications les plus récentes ont été automatiquement transférées à la racine du document de notre serveur Web lors de la validation. Nous pouvons apporter quelques modifications supplémentaires pour montrer que cela fonctionne sur chaque commit:

echo "<p>Here is a change.</p>" >> index.html
git add .
git commit -m "First change"

Lorsque vous actualisez votre navigateur, vous devriez voir immédiatement les nouvelles modifications que vous avez appliquées:

image: https: //assets.digitalocean.com/articles/git_hooks/deploy_changes.png [modifications de déploiement]

Comme vous pouvez le constater, ce type de configuration peut faciliter la tâche pour tester les modifications localement. Cependant, vous ne voudrez presque jamais publier sur commit dans un environnement de production. Il est beaucoup plus sûr d’appuyer une fois que vous avez testé votre code et que vous êtes certain qu’il est prêt.

Utiliser Git Hooks pour se déployer sur un serveur de production séparé

Dans cet exemple, nous allons montrer un meilleur moyen de mettre à jour un serveur de production. Nous pouvons le faire en utilisant le modèle push-to-deploy afin de mettre à jour notre serveur Web chaque fois que nous poussons vers un référentiel Git simple.

Nous pouvons utiliser le même serveur que nous avons configuré comme notre machine de développement. C’est là que nous allons faire notre travail. Nous pourrons voir nos modifications après chaque commit.

Sur notre machine de production, nous allons configurer un autre serveur Web, un référentiel Git simple vers lequel nous allons appliquer les modifications et un hook Git qui s’exécutera à chaque réception d’un push. Effectuez les étapes ci-dessous en tant qu’utilisateur normal doté des privilèges sudo.

Configuration du crochet de post-réception du serveur de production

Sur le serveur de production, commencez par installer le serveur Web:

sudo apt-get update
sudo apt-get install apache2

Encore une fois, nous devrions donner la propriété de la racine du document à l’utilisateur sous lequel nous opérons:

sudo chown -R `whoami`:`id -gn` /var/www/html

Nous devons aussi penser à installer git sur cette machine:

sudo apt-get install git

Maintenant, nous pouvons créer un répertoire dans le répertoire de base de notre utilisateur pour contenir le référentiel. Nous pouvons ensuite aller dans ce répertoire et initialiser un référentiel nu. Un référentiel nu n’a pas de répertoire de travail et est préférable pour les serveurs sur lesquels vous ne travaillerez pas directement:

mkdir ~/proj
cd ~/proj
git init --bare

Puisqu’il s’agit d’un référentiel nu, il n’y a pas de répertoire de travail et tous les fichiers situés dans + .git + dans une configuration conventionnelle se trouvent dans le répertoire principal même.

Nous devons créer un autre crochet git. Cette fois, nous nous intéressons au hook + post-receive +, qui est exécuté sur le serveur recevant un + git push +. Ouvrez ce fichier dans votre éditeur:

nano hooks/post-receive

Encore une fois, nous devons commencer par identifier le type de script que nous écrivons. Après cela, nous pouvons taper la même commande d’extraction que nous avons utilisée dans notre fichier + post-commit +, modifiée pour utiliser les chemins sur cette machine:

#!/bin/bash
git --work-tree=/var/www/html --git-dir=/home//proj checkout -f

Puisqu’il s’agit d’un référentiel nu, le + - git-dir + devrait pointer vers le répertoire de niveau supérieur de ce référentiel. Le reste est assez similaire.

Cependant, nous devons ajouter une logique supplémentaire à ce script. Si nous poussons accidentellement une branche + test-feature + sur ce serveur, nous ne voulons pas que cela soit déployé. Nous voulons nous assurer que nous ne déploierons que la branche + master +.

Pour le hook + post-receive +, vous avez peut-être déjà remarqué dans le tableau que git transmettait le hachage de validation de l’ancienne révision, le hachage de validation de la nouvelle révision et la référence poussée en tant qu’entrée standard dans le script. Nous pouvons utiliser ceci pour vérifier si le ref est la branche principale ou non.

Tout d’abord, nous devons lire l’entrée standard. Pour chaque ref qui est poussé, les trois informations (old rev, new rev, ref) seront introduites dans le script, séparées par un espace blanc, en tant qu’entrée standard. Nous pouvons lire ceci avec une boucle While while pour entourer la commande` + git`:

#!/bin/bash
while read oldrev newrev ref
do
   git --work-tree=/var/www/html --git-dir=/home//proj checkout -f
done

Alors maintenant, nous aurons trois variables définies en fonction de ce qui est poussé. Pour une poussée de branche principale, l’objet + ref + contiendra quelque chose qui ressemble à + ​​refs / heads / master +. Nous pouvons vérifier si le ref que le serveur reçoit a ce format en utilisant une construction + if +:

#!/bin/bash
while read oldrev newrev ref
do
   if [[ $ref =~ .*/master$ ]];
   then
       git --work-tree=/var/www/html --git-dir=/home//proj checkout -f
   fi
done

Pour les hooks côté serveur, git peut en réalité renvoyer des messages au client. Tout ce qui est envoyé à la sortie standard sera redirigé vers le client. Cela nous donne l’occasion d’informer explicitement l’utilisateur de la décision prise.

Nous devrions ajouter un texte décrivant quelle situation a été détectée et quelles mesures ont été prises. Nous devrions ajouter un bloc + else + pour avertir l’utilisateur quand une branche non principale a été reçue avec succès, même si l’action ne déclenche pas de déploiement:

#!/bin/bash
while read oldrev newrev ref
do
   if [[ $ref =~ .*/master$ ]];
   then
       echo "Master ref received.  Deploying master branch to production..."
       git --work-tree=/var/www/html --git-dir=/home//proj checkout -f
   else
       echo "Ref $ref successfully received.  Doing nothing: only the master branch may be deployed on this server."
   fi
done

Lorsque vous avez terminé, enregistrez et fermez le fichier.

N’oubliez pas que nous devons rendre le script exécutable pour que le hook fonctionne:

chmod +x hooks/post-receive

Maintenant, nous pouvons configurer l’accès à ce serveur distant sur notre client.

Configurez le serveur distant sur votre ordinateur client

De retour sur votre poste client (développement), retournez dans le répertoire de travail de votre projet:

cd ~/proj

A l’intérieur, ajoutez le serveur distant en tant que distant appelé + production. Vous aurez besoin de connaître le nom d’utilisateur que vous avez utilisé sur votre serveur de production, ainsi que son adresse IP ou son nom de domaine. Vous aurez également besoin de connaître l’emplacement du référentiel nu que vous avez configuré par rapport au répertoire de base de l’utilisateur.

La commande que vous tapez devrait ressembler à ceci:

git remote add production @:proj

Laissons notre branche principale actuelle sur notre serveur de production:

git push production master

Si les clés SSH ne sont pas configurées, vous devrez peut-être entrer le mot de passe de l’utilisateur de votre serveur de production. Vous devriez voir quelque chose qui ressemble à ceci:

Counting objects: 8, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 473 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)

To [email protected]:proj
  009183f..f1b9027  master -> master

Comme vous pouvez le constater, le texte de votre hook + post-receive est dans le résultat de la commande. Si nous visitons le nom de domaine ou l’adresse IP de notre serveur de production dans notre navigateur Web, nous devrions voir la version actuelle de notre projet:

image: https: //assets.digitalocean.com/articles/git_hooks/pushed_prod.png [production poussée]

Il semble que le crochet ait réussi à faire passer notre code à la production une fois qu’il a reçu les informations.

Maintenant, testons un nouveau code. De retour sur la machine de développement, nous allons créer une nouvelle branche pour contenir nos modifications. De cette façon, nous pouvons nous assurer que tout est prêt à fonctionner avant le déploiement en production.

Créez une nouvelle branche appelée + test_feature + et vérifiez la nouvelle branche en tapant:

git checkout -b test_feature

Nous travaillons maintenant dans la branche + test_feature +. Faisons un changement que nous pourrions peut-être passer à la production. Nous allons l’engager dans cette branche:

echo "<h2>New Feature Here</h2>" >> index.html
git add .
git commit -m "Trying out new feature"

À ce stade, si vous accédez à l’adresse IP ou au nom de domaine de votre ordinateur de développement, vos modifications devraient s’afficher:

image: https: //assets.digitalocean.com/articles/git_hooks/devel_commit.png [modifications de validation]

En effet, notre machine de développement est toujours en train d’être redéployée à chaque commit. Ce flux de travail est idéal pour tester les modifications avant de les passer en production.

Nous pouvons pousser notre branche + test_feature + sur notre serveur de production distant:

git push production test_feature

Vous devriez voir l’autre message de notre hook + post-receive + dans la sortie:

Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 301 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)

To [email protected]:proj
  83e9dc4..5617b50  test_feature -> test_feature

Si vous extrayez à nouveau le serveur de production dans votre navigateur, vous constaterez que rien n’a changé. C’est ce à quoi nous nous attendons, car le changement que nous avons poussé n’était pas dans la branche principale.

Maintenant que nous avons testé nos modifications sur notre machine de développement, nous sommes certains de vouloir intégrer cette fonctionnalité à notre branche maître. Nous pouvons récupérer notre branche + master + et fusionner dans notre branche + test_feature + sur notre machine de développement:

git checkout master
git merge test_feature

Vous avez maintenant fusionné la nouvelle fonctionnalité dans la branche principale. L’envoi au serveur de production déploiera nos modifications:

git push production master

Si nous vérifions le nom de domaine ou l’adresse IP de notre serveur de production, nous verrons nos modifications:

image: https: //assets.digitalocean.com/articles/git_hooks/new_prod.png [Passé à la production]

En utilisant ce flux de travail, nous pouvons avoir une machine de développement qui montrera immédiatement toutes les modifications validées. La machine de production sera mise à jour à chaque poussée de la branche principale.

Conclusion

Si vous avez suivi jusque-là, vous devriez être en mesure de voir les différentes manières dont git hook peut aider à automatiser certaines de vos tâches. Ils peuvent vous aider à déployer votre code ou à maintenir des normes de qualité en rejetant les modifications non conformes ou les messages de validation.

Bien qu’il soit difficile de discuter de l’utilité des git hooks, sa mise en œuvre réelle peut être assez difficile à comprendre et frustrante à résoudre. S’exercer à mettre en œuvre diverses configurations, à analyser des arguments et des entrées standard et à suivre la manière dont git construit l’environnement des hooks vous aidera à mieux comprendre comment écrire des hooks efficaces. À long terme, l’investissement en temps en vaut généralement la peine, car il peut facilement vous épargner, à vous et à votre équipe, des charges de travail manuel tout au long de la vie de votre projet.