Utiliser Git en entreprise

Introduction

Je ne vais pas détailler le pourquoi. Si vous lisez ça, c’est que vous connaissez déjà les avantages de Git et peut-être l’utilisez vous déjà, soit sur des projets open source soit sur des projets en solo dans votre entreprise.

Le vrai problème en entreprise est le comment. En particulier parce que vous avez probablement des collègues qui sont sous Windows et qui n’ont aucune culture linux ni open source. Il est même vraisemblable qu’il s’agisse de la majorité. Malgré tout, en supposant qu’ils soient ouverts et qu’il n’y ait pas de politisation de l’affaire, rien n’est perdu. En me basant sur mon expérience, je décris ici les étapes que j’ai identifiées :

  1. expliquer la motivation, convaincre
  2. définir la structure des repository et le workflow
  3. documenter l’installation
  4. documenter les premiers pas et les manipulations basiques puis les astuces
La première étape, je ne la décrirai pas, car non seulement vous trouverez de nombreuses références sur Internet mais surtout elle est éminémment contextuelle et dépend autant de l’exemple que vous donnez que des ennuis provoqués par votre gestionnaire de sources actuels.
Ce que je vais décrire, car je pense qu’il s’agit d’éléments portables d’une entreprise (ou équipe) à l’autre est la succession des étapes suivantes.
Git offre énormément de liberté mais ceci peut égarer les nouveaux utilisateurs. C’est pourquoi ce document pose comme règles ce qui n’est généralement vu que comme des bonnes pratiques (organisation des branches, repository et workflow), peut-être les plus communes mais absolument pas les seules possibles.
Je vais supposer, pour la suite, que vous disposez d’un serveur linux. Il peut s’agir d’un serveur interne, accessible uniquement sur le réseau local, ou, mieux, d’un serveur hébergé et toujours disponible. Ceci  étant supposé acquis, la suite de cette article peut être vue comme un manuel tout prêt pour tous les développeurs qui dans l’entreprise se mettent à git.
Les exemples de cet article vont être basés sur ces éléments de contexte :
  • notreProjet : nom du projet
  • dev.laboite.com : le serveur linux
  • alain : compte sur dev.laboite.com du développeur initié à Git, à l’origine du projet notreProjet et son intégrateur
  • bernard : compte sur dev.laboite.com d’un développeur Windows
  • christian : compte d’un autre développeur Windows

Workflow et repository

Chaque développeur, pour chaque projet, dispose de deux repository :
  • un repository privé, dans lequel il développe, sur son poste de travail
  • un repository public, hébergé sur le serveur linux, lisible par tous ses collègues mais dans lequel lui seul écrit
L’un des développeurs a, à un moment donné, le rôle d’intégrateur et son repository public sert de référence pour tous les développeurs : ils iront chercher dans ce repository le dernier état de la branche master (notons qu’un autre développeur pourra être l’intégrateur sur une autre branche du projet).
Le workflow le plus basique possible est celui-ci :
  • bernard travaille, comme tous les développeurs, dans son repository de travail.
  • Il effectue une modification relativement simple et courte sur le code commun. Au fur et à mesure de son développement, très fréquemment, il effectue des commit locaux. Il met ainsi à jour sa branche master locale.
  • Lorsque ses développements doivent être partagés, il envoie (push) l’état de son repository vers son repository public et demande à l’intégrateur de récupérer ses travaux.
  • alain, l’intégrateur dans notre exemple, effectue un fetch pour les récupérer. Ces développements apparaissent pour lui sous la branche bernard/master. Il merge cette branche avec son répertoire de travail (éventuellement dans une branche dédiée), teste si nécessaire, et publie (push) dans son répository public.
  • Les autres développeurs peuvent ensuite, lorsqu’ils le souhaitent, récupérer l’état faisant référence via un fetch de alain/master suivi d’un merge (lequel n’est pas destructif : il s’intégrera généralement sans intervention manuelle à leur travail en cours).

 Les développeurs, le plus souvent, ne travaillent pas dans leur branche master mais dans une branche spécifique à la fonctionnalité en cours. Lorsque c’est le cas il peuvent :

  • soit merger cette branche à la branche master avant d’effectuer un push vers leur repository public
  • soit envoyer cette branche sur le repository public

Le premier cas est le plus fréquent et correspond à un développement que tout le monde a intérêt à récupérer rapidement (c’est-à-dire pas une fonctionnalité posant problème, incomplète ou incompatible).
La logique générale est que la branche master correspond à la version en cours de production (on étiquette les versions « stables » ou « releases » en créant des branches spécifiques, ce qui permet par exemple de redéployer ou patcher facilement une vieille version).
Si un sous-groupe des développeurs travaille sur une fonctionnalité particulière, qui n’a pas vocation à être intégrée à la version master générale, l’un d’entre eux pourra, pour la branche associée, faire office d’intégrateur sans passer par l’intégrateur de la branche master.

Remarquons que pour pouvoir sans difficulté intégrer facilement les développements de ses collègues, l’intégrateur plus encore que les autres s’astreint à éviter de réaliser de gros développements dans la branche master.

Mise en place sous Windows

Le développeur sous linux ou mac n’aura pas de difficulté à installer et utiliser Git, par contre une aide est réellement indispensable pour le développeur sous Windows.

Installation de msysgit

Après avoir téléchargé la dernière version de l’installeur de Git for Windows, exécutez là en appliquant les choix par défaut :

  • Use Git Bash only
  • Checkout Windows-style, commit Unix-style line endings
Suite à cette installation vous disposerez deux logiciels :
  • Git Bash
  • Git Gui

Paramétrage et prise en main du bash de msysgit

La première chose à faire est de paramétrer Git Bash afin qu’il soit adapté à votre écran :

  1. Faites un clic droit sur l’icône de Git Bash et sélectionnez Properties
  2. Choisissez l’onglet Layout
  3. Modifier les quatre premiers champs (par exemple 150, 9000, 150, 50)
  4. Cliquez sur OK pour sauvegarder vos modifications

Git Bash met à votre disposition un shell qui conceptuellement ne surprendra pas les habitués de la commande dos mais bien plus puissant et définissant des commandes différentes pour certaines opérations communes sous Windows.
De même que sous Windows vous pouvez compléter les noms de fichiers ou chemins via la touche tab, et naviguer parmi les commandes déjà exécutées via les flèches haut et bas du clavier. Vous pouvez coller ce qui est dans votre presse-papier (ou dans la sélection de la console) en cliquant avec le bouton droit de la souris.
L’invite de commande vous indique en permanence là où vous trouvez.
Je décris ici très très sommairement les commandes indispensables pour l’utilisation de msysgit. Il ne s’agit pas d’une référence : l’appel à l’aide de Google ou d’un linuxien près de chez vous sera indispensable pour en savoir plus.

cd

Cette commande vous permet de changer de répertoire.
Pour aller dans le répertoire c:\code, tapez ainsi

cd /c/code

(sans oublier que la touche tab complète les noms de fichiers et répertoires)

Pour remonter d’un niveau, tapez

cd ..

Notez que si vous vous déplacez vers un répertoire qui est sous Git, l’invite de commande vous précise quelle est la branche courante (initialement master). C’est en effet une information qu’il faut toujours avoir en tête avant de faire des manipulations sur le repository.

mkdir

Cette commande permet de créer un répertoire.

ls

Cette commane commande est l’équivalent de dir. Une variante souvent utile permet d’afficher les fichiers cachés et donne leurs caractéristiques :

ls -al

cp

Cette commande permet de dupliquer un fichier ou répertoire (ajouter dans ce cas l’option -r)

mv

mv permet de renommer ou déplacer un fichier ou répertoire

less

less suivie d’un nom de fichier vous permet de le visualiser rapidement le contenu d’un fichier

Vous pouvez utiliser les flèches du clavier pour faire défiler et la touche q ferme la commande. Notez que d’autres commandes utilisent ce principe, en particulier git log ou bien git show.

rm

rm permet de supprimer un fichier ou répertoire. L’option -r est souvent combinée à l’option -f afin de ne pas devoir confirmer chaque suppression :

rm -rf grosRepertoire

ssh

ssh vous permet une connexion via le protocole sécurisé ssh sur un serveur distant. Vous disposez alors du shell qui est associé à votre compte sur ce serveur.

Exemple de connexion pour christian sur le serveur dev.laboite.com :

ssh christian@dev.laboite.com

Si vous n’avez pas mis en place de clef publique (voir plus loin), un mot de passe vous est demandé.

scp

scp est similaire à cp mais permet de faire une copie par ssh (vous connaissez peut-être l’interface winscp pour le même usage). On donnera un exemple de son utilisation un peu plus loin, pour la copie de votre clef publique.

Installation des clefs sur le serveur linux

Notez que la clef publique que vous allez définir est totalement disjointe de celle que vous avez déjà éventuellement pour putty (et que vous chargez via pageant).

On donne ici l’exemple de manipulation pour bernard.

Dans la console Git Bash, la génération de clef se fait via la commande ssh-keygen :

ssh-keygen -t rsa -C "bernard@laboite.com"

Il n’est pas forcément indispensable en LAN de renseigner la passphrase (tapez juste entrée) mais dans ce cas vous devrez protéger la clef générée. Le plus simple est de simplement faire entrée à chaque question posée par la commande.

Cette commande génère deux fichiers, id_rsa et id_rsa.pub, dans le répertoire .ssh de votre compte utilisateur (sous Windows).

Il faut envoyer le fichier .pub sur le serveur linux. Pour ce faire, on emploie la commande scp :

scp /c/Users/Bernard/.ssh/id_rsa.pub bernard@dev.laboite.com:~

Normalement, vous devrez taper votre mot de passe puisque la clef publique n’est pas encore en place. Cette commande envoie le fichier dans le répertoire .ssh de bernard sous dev.laboite.com.

Vous devez ensuite vous connecter sous dev.laboite.com pour la suite :

ssh bernard@dev.laboite.com

Afin d’assurer que le répertoire .ssh existe, tapez la commande suivante

mkdir -p .ssh

Vous aurez aussi besoin par la suite d’un répertoire git dans votre home :

mkdir -p .git

Et ajoutez la clef publique à la liste des clefs autorisées :

cat id_rsa.pub >> .ssh/authorized_keys

Et supprimez le fichier inutile :

rm id_rsa.pub

Vous pouvez maintenant vous déconnecter de dev.laboite.com :

exit

Configuration générale de Git

Deux paramètres qui seront les mêmes sur tous les projets doivent être renseignés. Adaptez les commandes suivantes et tapez les dans Git Bash :

git config --global user.name "Bernard Sonom"
git config --global user.email "Bernard.Sonom@laboite.com"

Récupération du projet existant

Nous sommes ici dans le cas où bernard rejoint le projet notreProjet, lequel a déjà été publié sur dev.laboite.com par alainBernard a installé Git mais n’a pas encore le code source du projet.

Déplacez vous, sur la console, vers le répertoire dans lequel vous voulez travailler. Par exemple :

cd /c/dev/

(en supposant que vous ayez un répertoire c:\dev\ sur votre disque dur)

Clonez le repository officiel (repository public de l’intégrateur) :

git clone ssh://bernard@dev.laboite.com/home/alain/git/notreProjet.git

Cette commande crée le répertoire notreProjet. Notez qu’il s’agit non seulement de votre répertoire de travail mais également d’un repository complet, contenant l’historique de toutes les branches et dans lequel vous pourrez faire des commits et autres manipulation sans connexion réseau. Les fichiers de Git sont rangés dans le répertoire .git. Les sous répertoires sont exempts de fichiers de Git.

Pour la suite des manipulations, vous devez être dans le répertoire de travail :

cd notreProjet

Il faut maintenant créer le répertoire public du développeur (celui, sur dev.laboite.com qui sera accessible à tous) :

git clone --bare .git notreProjet.git
scp -r notreProjet.git bernard@dev.laboite.com:git/notreProjet.git
rm -rf notreProjet.git

Il est maintenant nécessaire de définir un certain nombre d’alias qui éviteront par la suite de taper les url. Dans notre cas Bernard va devoir désigner au minimum son répertoire public et on va supposer pour l’exemple qu’il veut aussi désigner le répertoire public d’un autre collègue :

git remote add pub ssh://bernard@dev.laboite.com/home/bernard/git/notreProjet.git
git remote add christian ssh://bernard@dev.laboite.com/home/christian/git/notreProjet.git

Par convention, chaque développeur voit sous le nom pub son propre répertoire public (vous pouvez aussi lui donner un autre nom mais s’agissant du répertoire auquel vous vous adresserez le plus souvent, faites en sorte qu’il soit court !).

Le répertoire public de l’intégrateur a déjà un alias défini : origin.

Workflow le plus élémentaire, contribution et mise à jour

On va illustrer les commandes de base au travers d’un exemple. Dans cet exemple tout se fait dans la branche master.

bernard ajoute un fichier (curry.html) et modifie un fichier qui était déjà présent (index.html).

Avant de commiter, il vérifie que l’état de son répertoire de travail correspond bien à ce qu’il pense, via la commande git status.

S’il veut plus de détail sur l’écart entre ses données de travail et le repository, il peut utiliser la commande git diff.

Avant de commiter, il faut spécifier, via git add que le fichier curry.html, jusque là inconnu de Git, doit faire partie de l’ajout. git status permet ensuite de vérifier la prise en compte.

Il s’agit maintenant de faire un commit. Notons qu’il n’est pas possible de ne pas spécifier de message. On utilise l’option -a (all) afin de préciser que les fichiers modifiés (ici le fichier index.html) font partie du commit. La commande ainsi effectuée est la suivante :

git commit -am "description de l'evolution"

(notons que sous Windows en utilisant msysgit et il n’est pas possible de mettre des accents dans les commentaires à la ligne de commande)

On effectue encore ensuite un git status pour voir la modification.

Avant de transmettre ses modifications, un développeur effectue typiquement plusieurs commits. Dans notre exemple le développeur va publier ses travaux et demander à l’intégrateur de les intégrer.

La publication se fait simplement via la commande git push :

git push pub

L’intégrateur, prévenu, récupère les modifications, les merge avec les développements des autres développeurs et, dés que possible, les publie dans son propre répertoire public lequel fait référence.

bernard récupère la dernière version officielle via les commandes suivantes :

git fetch origin
git merge origin/master

(origin est l’alias du repository officiel, et origin/master désigne simplement la branche master provenant de ce repository)

Remarquons que la commande merge indique succinctement les modifications effectuées (fichiers et nombres de lignes impactées).

Si bernard veut connaitre plus en détail les modifications récentes, il peut exploiter la commande git log :

git log --stat

Notons que de nombreuses autres options sont possibles, par exemple pour étudier le graphe des commits et que l’outil Git Gui offre également un outil de visualisation des évolutions.

Utilisation d’une branche

La branche master doit toujours rester partageable, mergeable, déployable (pas en production réelle ou chez le client mais pour les tests courants).

Ceci signifie que dés lors que vous tapez du code qui peut avoir des effets de bord, ou implique des évolutions conjointes d’autres fichiers partagés, ou correspond à une fonctionnalité dont la réalisation peut prendre de longues heures (ou pire), il est nécessaire de créer une branche.

Travail en solo sur une branche

Supposons que vous ayez à développer la fonctionnalité « zoom ». Après avoir commité ce qui traînait dans votre branche actuelle, vous faites simplement appel à la commande git branch :

git branch zoom

Puis vous basculez sur cette branche

git checkout zoom

L’invite de commande (si vous êtes utilisez Git Gui, scm breeze ou un système analogue) vous indique que vous êtes sur la branche checklistgit status aurait pu vous l’indiquer également.

Vous effectuez alors vos développements et vos commits normalement. Ils n’impactent pas la branche master. Lorsque vous avez fini (et commité!) vos travaux, vous revenez sur la branchemaster et vous intégrez (merge) la branche checklist :

git checkout master
git merge zoom

Si vous n’avez jamais publié la branche zoom, l’historique (log) des développements reste linéaire (donc moins verbeux) et n’indique pas cette branche.

Travail sur plusieurs branches

Le principal intérêt de travailler sur des branches est évidemment de pouvoir en changer.

Supposons que vous soyez sur la branche zoom mais que vous ayez une correction à faire qui ne concerne pas particulièrement la fonction de zoom, il vaut mieux la faire dans master.

Vous commencez par sauvegarder votre travail en cours éventuel par un git commit dans votre branche zoom.

Vous passez sur la branche master :

git checkout master

Vous effectuez et commitez votre modification, vous la partagez si nécessaire (via git push).

Vous revenez ensuite sur votre branche zoom :

git checkout zoom

Il est probable que vous souhaitiez disposer tout de suite de cette correction faite dans master, vous effectuez donc un merge (la destination d’un merge est toujours la branche en cours) :

git merge master

La correction est maintenant présente dans les deux branches master et zoom.

Partager une branche

Lorsque l’on hésite à créer une branche, c’est généralement qu’il faut la créer, au cas où. Cela signifie que vous aurez souvent des branches à très courte durée de vie et qu’il n’y a aucune raison de les publier.

Vous publierez une branche dans les deux cas suivants :

  • d’autres que vous doivent consulter cette branche ou y contribuer
  • vous voulez la sauvegarder afin de ne pas la perdre si vous perdez votre disque dur local

Lorsque vous effectuez un git push pub, seules les branches déjà publiées (master à l’origine) sont mises à jour.

Si vous souhaitez qu’une branche soit envoyée sur pub, vous devez simplement la spécifier :

git push pub zoom

Par la suite, si vous modifiez cette branche elle sera automatiquement publiée lorsque vous ferez git push pub.

Elagage

Pour supprimer une vieille branche (ici nommée saucisson), vous tapez simplement

git branch -d saucisson

Branches, versions, déploiements

On utilise communément la logique suivante :

  • la branche master, qui doit toujours rester propre, partageable et déployable (au moins pour tests)
  • une branche dédiée par fonctionnalité non triviale, qu’elle soit partagée ou propre à un développeur
  • une branche par version identifiée (a fortiori une branche pour chaque version donnée à un client)
  • une branche pour chaque hot fix (correction bug bloquant) qui doit être appliquée sur plusieurs branches

Créer une branche pour chaque version identifiée permet de facilement récupérer cette version pour test ou la patcher en cas de bug.

Remarquez que d’autres workflows existent et sont discutés sur internet.

.gitignore

Il est fréquent d’avoir dans son répertoire de travail des fichiers qui n’ont pas à être sous Git, qu’il s’agisse de fichiers de paramétrage contenant des mots de passe, de fichiers automatiquement créés par un IDE, de documents de travail provisoire, etc.

Afin de ne pas alourdir l’affichage de git status par ces fichiers, on les référence dans un fichier nommé .gitignore que l’on place dans le répertoire de travail. Par exemple :

# config confidentielle locale
scripts/config.sh

# fichiers générés par l'IDE
*-bak

# application compilée et objets
*.6
*.8
batteurchoucroute

On placera généralement un fichier .gitignore à la racine du répertoire de travail mais il est possible d’en disposer également dans les sous-répertoires.

Création d’un nouveau projet

Mettre un répertoire de travail sous git est facile. Il suffit de se placer dans le répertoire et d’exécuter la commande

git init

Ceci crée le répertoire .git. Rien n’est ajouté au repository, vous pouvez maintenant effectuer les add et commit.

Vous pouvez ensuite appliquer la manipulation décrite plus haut pour partager ce projet, sous l’alias remote pub sur dev.laboite.com.

Astuces et manipulations avancées

Visualiser l’historique

La commande git log vous donne l’historique des commits du projet. Vous pouvez naviguer avec les flèches du clavier et vous quittez cet affichage avec la touche q.

git help log vous liste toutes les options possibles mais elles sont un peu difficiles à comprendre. Voici certaines variantes utiles :

Listage des fichiers modifiés et nombres de lignes modifiées :

git log --stat

Affichage compact :

git log --oneline

Affichage du log d’un fichier particulier :

git log curry.html

Affichage du graphe des branches :

git log --graph --all --abbrev --color

Notez que les options sont généralement combinables.

Comparaison avec une version précédente

Pour savoir en quoi votre répertoire de travail diffère du dernier commit, tapez :

git diff

Si vous vous intéressez à un fichier particulier (ici sauceoseille.html), tapez ceci

git diff sauceoseille.html

Supposons que vous ayez mergé une modification et vouliez voir en quoi elle consistait, vous voulez donc comparer avec l’avant-dernier commit :

git diff HEAD^1 sauceoseille.html

Visualisation d’une vieille version

La version commitée est visible ainsi :

git show HEAD:cheminFichier

Une version plus ancienne ainsi :

git show HEAD~4:cheminFichier

Récupération d’une vieille version

Récupérer la dernière version commitée du fichier ascenseur.go :

git checkout HEAD ascenseur.go

Effacer tout ce que vous avez fait depuis le dernier commit :

git reset --hard HEAD

Exploiter le hash

Une notion importante de Git est le hash. Les objets du modèle de données de Git (commits, fichiers, répertoires, tags) sont tous identifiés par un hash (SHA1) calculé à partir de leur contenu et permettant :

  • leur indexation pour le moteur de Git
  • le dédoublonnage (si deux fichiers ont le même hash, on peut partir du principe qu’ils sont identiques)
  • la désignation par différents outils de Git

Lorsque vous appelez la commande git log, Git vous donne le hash des commits :

Dans cet exemple, le hash du dernier commit est db5e6c5b44c6a462e87364cf59d5cad66461161f. En pratique, vous exploiterez généralement le début de ce hash (au moins 5 caractères) car il y a peu de chances que vous ayez deux objets dont les hash partagent les même 5 ou 6 premiers caractères (en cas de confusion, Git vous avertit).

Ce hash permet par exemple de consulter un ancien commit :

 

Vous pouvez l’utiliser pour comparer la version de travail d’un fichier avec celle datant de ce vieux commit.

git diff d0b09 restart-mapserver.sh

affiche :

Si vous souhaitez remplacer un fichier de votre répertoire de travail par une vieille version, vous faites ainsi

git reset --hard d0b09 restart-mapserver.sh

 Conclusion

J’ai écrit ce document pour permettre la migration vers Git d’une petite équipe de développeurs, la plupart étant sous Windows et sans culture linux. Il s’agissait de la seconde tentative, la première, basée sur l’auto apprentissage et la débrouillardise de chacun, ayant échoué, en raison principalement de la difficulté pour les développeurs Windows à gérer à la fois Git, la logique unix et les solutions techniques nécessaires pour faire tourner Git sur Windows. Cette fois notre nouveau gestionnaire de sources est entré dans les moeurs de l’équipe qui en apprécie à juste titre les avancées par rapport au système précédent (svn). Je pense qu’un tel guide est une condition, dans ce type d’équipe, d’une migration sans douleur.

3 réflexions au sujet de « Utiliser Git en entreprise »

  1. Bonjour,
    Article intéressant. Perso j’ai trouvé beaucoup plus simple d’utiliser gitolite, cela ne permet de gérer les droits d’accès à une série de repository centraux de façon aisée, sans devoir créer plusieurs compte ssh.
    Gitolite permet également de gérer les droits d’accès sur les branches : R, W, W+ (ce dernier voulant dire ré-écriture d’historique git autorisée)

    • Merci. Gitolite est effectivement une alternative à considérer, en particulier quand l’équipe veut rester 100% Windows.

      Dans mon cas, ce n’était pas vraiment intéressant, tant de fonctions dans ma boite nécessitant un compte linux (et je veux pousser les derniers réfractaires à se mettre aux bases de la ligne de commande afin qu’ils puissent déployer de façon autonome un programme sur un serveur linux et globalement profiter de l’intérêt d’avoir un serveur puissant visible de tous les sites…).

  2. Although this approach works fine, it does mean that your web pages needs a git ropsoitery embedded within it.a0 A better approach, and one Ia0use now is to use rsync to copy (and synchorise) the files at the remote end.Here is an example, which detects a git merge, or a commit in one of two branches (site and test)a0which then rsyncs via ssh (to site mb) into the web locations for the production and test sites respectively.#!/bin/sh## Output a version file that we can include at the bottom of the pagebranch=$(git branch | sed -n s/^\*\ //p)cd « $(git rev-parse –show-cdup) »if [ "$branch" == "site" ]; then git clean -f rsync -axq –delete –exclude=scripts/calendar –exclude=htaccess –exclude=.git –exclude=test ./ mb:public_html/static/fiif [ "$branch" == "test" ]; then git clean -f rsync -axq –delete –exclude=scripts/calendar –exclude=htaccess –exclude=.git ./ mb:public_html/static/test/static/fi