Versionner un projet avec Git : principes et bases

Le gestionnaire de source est un outil indispensable pour le développement d’applications. Nous commencerons par expliquer son principe, puis aborderons l’utilisation d’un gestionnaire de source très complet, Git, avec CakePHP.

Introduction aux gestionnaires de sources

Principe et avantages

Un gestionnaire de source (en anglais SCM : Source Control Manager) agit comme une base de données de tous les changements apportés au code au cours du développement. Il offre ainsi à la fois une sauvegarde en cas de problème et un historique du développement.

Cela permet de travailler sur d’importantes modifications du code plus sereinement en sachant que l’on pourra facilement revenir en arrière si besoin. Fini les fichiers de sauvegarde .bak ou .old et les pavés de code en commentaire avant de gros changements !

Un autre avantage offert par un SCM est la possibilité de travailler à plusieurs sur une base de code en partageant ses modifications.

Il existe deux grandes familles de SCM : les centralisés et les décentralisés. Nous allons détailler rapidement leurs différences et expliquer les raisons lors du choix de notre SCM.

Les SCM centralisés

Ils reposent sur un serveur unique hébergeant la base de données du code, ce qui implique de pouvoir s’y connecter pour y enregistrer ses modifications. Cela offre l’avantage d’avoir à un seul endroit la base de données toujours à jour des dernières modifications, ainsi que la possibilité de mettre en place des autorisations d’accès.

Deux inconvénients majeurs découlent cependant de ce fonctionnement.

Premièrement, un intérêt majeur d’un SCM étant la possibilité de revenir en arrière, il est d’autant plus utile lorsque les sauvegardes concernent de petits blocs fonctionnels. Or avec un SCM centralisé, les personnes travaillant fréquemment sans connexion Internet (dans le train, l’avion, à l’hôtel…) ne peuvent enregistrer leurs modifications au fur et à mesure de leur travail. Cela les oblige à sauvegarder de grandes parties de code en une seule fois et limite la flexibilité du SCM.

Deuxièmement, le serveur étant le seul gardien de la base de données du code, il est important d’en garantir l’intégrité. Une fois qu’une modification y est enregistrée, elle est disponible pour tous les développeurs et ne peut plus être supprimée. Cela oblige alors à créer un système de droits d’accès pour garantir que seuls les développeurs habilités pourront enregistrer leurs modifications.

Ce fonctionnement pose problème lors du partage de code entre de nombreux développeurs ne se connaissant pas forcément comme c’est le cas dans les projets open-source. Les nouveaux venus n’ont généralement pas accès en écriture au serveur et doivent alors réaliser l’ensemble de leurs modifications sans la possibilité de les versionner, avant de les envoyer à un responsable qui décidera de leur intégration à la base de données. Les contributeurs occasionnels perdent alors l’intérêt de l’utilisation d’un SCM et cela les rebute souvent à contribuer à un projet.

Ces deux inconvénients ne se posent pas lors de l’utilisation d’un SCM décentralisé.

Les SCM décentralisés

Contrairement aux SCM centralisés, ils ne reposent pas sur une base de données unique. Celle-ci peut être disponible sur plusieurs serveurs, et chaque développeur en possède une copie complète sur son propre poste. Ceci paraît à première vue étrange : comment travailler à plusieurs si plusieurs versions du code existent à des endroits différents ? Comment maintenir des droits d’accès entre les différentes copies ? Il s’avère en fait que non seulement tout cela est possible avec les SCM décentralisés, mais qu’en plus ils apportent des solutions aux inconvénients des SCM centralisés évoqués ci-dessus.

Comme dans le cas d’un SCM centralisé, lorsque les développeurs souhaitent partager leurs modifications, ils synchronisent leur base de données locale avec celle du serveur. Il est également tout à fait possible de restreindre les droits d’accès aux différents serveurs hébergeant la base de données.

Par contre, comme le développeur possède sur son poste la totalité de la base de données, il peut travailler tout en étant déconnecté. De plus, tout se faisant en local, les opérations sont en général bien plus rapides. Enfin, il peut enregistrer ses modifications par blocs fonctionnels quand il le souhaite et les publier plus tard, une fois connecté à un des serveurs hébergeant la base de données.

Ensuite, cela rend la participation à des projets open-source plus aisée car s’il souhaite contribuer à un projet mais n’a pas accès en écriture, il lui est tout de même possible de versionner son travail en local et de le transmettre ensuite à un intégrateur qui se chargera de l’intégrer à la base de données principale.

Un autre avantage enfin est la multiplication des sauvegardes. Chaque développeur possédant l’ensemble de la base de données, celle-ci est facilement récupérable en cas de panne d’un des serveurs.

Ces raisons nous ont amené à nous tourner vers un SCM centralisé, et plus particulièrement vers l’un des plus utilisés actuellement : Git.

Git

Git est un SCM créé par Linus Torvalds, le créateur de Linux, pour le développement du noyau. Il est devenu récemment très populaire avec la création du site GitHub, une plateforme de développement collaborative, et son adoption par la communauté du framework Ruby On Rails dont CakePHP s’est inspiré.

Il offre en outre quelques particularités très pratiques comme la possibilité de revenir sur des modifications enregistrées ou une gestion des branches extrêmement puissante.

Git est maintenant utilisé pour le développement de CakePHP, d’où l’intérêt d’apprendre son utilisation.

Versionner un projet CakePHP avec Git

Installation de Git

Git est disponible sur les plateformes Windows, Mac OS X et Linux. Les différentes verisons sont disponibles sur le site de Git. Sur Windows, msysGit est recommandé. Sur Mac OS X, il est également possible de l’installer via MacPorts. Sur Linux, il est certainement préférable d’utiliser le gestionnaire de paquets de votre distribution/

Toutes les commandes donnés ci-après sont à taper dans un terminal. Sous Windows, Git installe un raccourci « Git Bash » permettant d’accéder aux outils Git ainsi qu’à plusieurs outils Unix très pratiques.

Une fois Git installé, nous configurons notre nom d’utilisateur et notre email qui apparaîtront dans la liste des modifications. Nous ajoutons également une option pour bénéficier de l’affichage en couleurs.

git config --global user.name 'Matthieu Sadouni'
git config --global user.email matthieusadouni@gmail.com
git config --global color.ui true

Ces modifications sont enregistrées dans le fichier .gitconfig situé dans notre répertoire personnel.

Initialisation d’un projet CakePHP

Git est prêt à être utilisé, nous passons maintenant à CakePHP. Nous commençons par créer le squelette de l’application à l’aide de la commande bake :

cake bake mon-projet

Puis nous initialisons un dépôt à la racine de l’application :

git init

Le dépôt est enregistré dans le répertoire .git se trouvant à la racine du projet. Il contient l’ensemble des informations sur toutes les modifications enregistrées. Ceux qui ont utilisé le SCM centralisé Subversion apprécieront l’absence des répertoires .svn présents dans chaque sous-dossier du projet !

Ce dépôt est pour le moment vide, nous allons devoir indiquer quels fichiers devront être versionnés et ceux qu’il faudra ignorer.

Versionner les répertoires vides

Une particularité de Git est de ne versionner que le contenu des fichiers et non leur existence en tant que telle. Ainsi un fichier ou un répertoire vide ne sera pas vu par Git. Nous avons cependant besoin de créer certains répertoires vides à l’initialisation de notre applications, notamment le répertoire tmp et ses sous-répertoires. Une astuce consiste à créer un fichier caché à l’intérieur des répertoires vides à versionner. Nous créons donc un fichier .gitignore vide dans tous les répertoires vides :

# dans le répertoire de l'application
find . -type d -empty | xargs -I % touch %/.gitignore

Sur Windows il faut …

Ignorer les fichiers inutiles

Le fait d’indiquer à Git d’ignorer des fichiers inutiles permet de ne conserver la trace que des modifications apportés au code lui-même.

Les changements dans les fichiers temporaires par exemple sont trop fréquents et inintéressants. Nous allons donc tout bonnement ignorer ces fichiers.

Le contenu des fichiers de paramétrage (config/database.php, webroot/index.php, etc) dépend quant à lui de l’environnement sur lequel est installé le code (développement en local chez plusieurs développeurs, serveur de production…) et ne nécessite pas d’être versionné. Nous allons donc créer une version par défaut des fichiers de configuration (par exemple config/database.php.default) et ignorer le fichier en lui-même (par exemple config/database.php). Cela permettra lors de l’installation de l’application chez un autre développeur ou en production de dupliquer les fichiers par défaut pour y renseigner les paramètres de l’environnement actuel.

Voici une liste non exhaustive de fichiers à ignorer :

  • des fichiers temporaires : logs, cache…
  • des fichiers uploadés par les utilisateurs
  • des fichiers dépendant de l’environnement : configuration de la base de données, index.php, .htaccess…

Git stocke la liste des fichiers à ignorer dans un fichier .gitignore situé à la racine de l’application. Nous créons ce fichier et y ajoutons le contenu suivant :

tmp/**/*
tmp/**/**/*

Voilà nos fichiers temporaires ignorés. La syntaxe avec les étoiles permet d’ignorer tous les sous-répertoires de tmp. Il nous faut ensuite créer les versions par défaut des fichiers susceptibles de changer selon l’environnement. En voici la liste :

  • .htaccess
  • config/core.php
  • config/config.php
  • config/database.php
  • webroot/.htaccess
  • webroot/index.php
  • webroot/test.php

La copie se fait grâce à la commande cp <fichier> <fichier>.default, par exemple cp config/database.php config/database.php.default.

Une fois ces fichiers par défaut créés, nous indiquons à Git d’ignorer les fichiers d’origine :

# .gitignore
.htaccess
config/core.php
config/config.php
config/database.php
webroot/.htaccess
webroot/index.php
webroot/test.php

Enfin, dernière chose, nous devons également indiquer à Git de ne pas ignorer les fichiers .gitignore présents dans les répertoires vides. Nous ajoutons pour cela en fin de fichier .gitignore la ligne

!.gitignore

Voici notre .gitignore final :

# .gitignore
tmp/**/*
tmp/**/**/*
.htaccess
config/core.php
config/config.php
config/database.php
webroot/.htaccess
webroot/index.php
webroot/test.php
!.gitignore

Premier commit

Nous voilà fin prêts pour enregister la première version de notre application. Un commit (enregistrement d’un ensemble de modifications) a lieu en deux étapes (Git nécessite d’indiquer les modifications à commiter avant de valider le commit, nous reviendrons sur cette fonctionnalité à première vue pénible mais en fait extrêmement pratique dans un prochain article) :

  • ajout des modifications à enregistrer
  • enregistrement proprement dit, accompagné d’un message décrivant les modifications

Nous tapons pour cela les commandes suivantes :

git add .
git commit -m "Premier commit"

Et voilà ! Notre première modification est enregistrée. Nous pouvons en vérifier l’existence en tapant git log :

commit 657cec1ea3a6b9c41b202806a45f4e7219125859
Author: Matthieu Sadouni <matthieusadouni@gmail.com>
Date:   Tue Nov 17 22:41:48 2009 +0100
 
Premier commit

Le numéro de commit sera différent de celui donné ici, il est unique car calculé en fonction du contenu des modifications.

Toutes ces étapes étant un peu fastidieuses à répéter à chaque nouveau projet, j’ai créé un script permettant des les automatiser. Les instructions sont disponibles sur le site forum.cakephp-fr.org.

Conclusion

Nous avons vu comment utiliser Git pour versionner une nouvelle application CakePHP. Lors de prochains articles nous aborderons l’utilisation de Git au quotidien pour le développement, et notammemt :

  • l’utilisation de l’index pour versionner uniquement certaines modifications
  • l’utilisation des branches, l’un des gros points forts de Git, pour travailler en parallèle sur des fonctionnalités différentes
  • comment contribuer à améliorer CakePHP
  • l’utilisation de GitHub pour héberger son code

ainsi que des trucs et astuces pour faciliter l’utilisation de Git. Stay tuned !

Matthieu Sadouni

Articles connexes

Commentaires

Excellent article. Très clair.

Vivement la suite : je ne suis pour le moment toujours pas convaincu de l’intérêt d’utiliser Git dans une web agency (enfin pas plus que SVN), mais peut être tes prochains tutoriaux mettront en valeur des éléments qui peuvent m’être utiles.

Merci Sébastien, ceux sur la gestion de l’index et les branches devraient aider te convaincre :)

très bon article

@sébastien je ne vois pas comment il est possible de se passer d’un SCM

@matthieu pour des projets déjà versionnés avec SVN, il y a t’il un moyen de migrer vers Git et si oui as tu déjà testé ?

@fred je pense que Sébastien parlait des avantages de Git par rapport à SVN. Pour migrer de Git vers SVN, il existe un outil git-svn qui permet de :

  • convertir un dépôt pour passer entièrement à Git
  • cloner un dépôt distant SVN en un dépôt Git en local, ce qui permet de bénéficier de Git sur son poste (branches etc) puis de remonter les commits sur le dépôt SVN.

J’ai utilisé les deux méthodes, cela dépend de la nécessité ou non de conserver le dépôt distant sous SVN. Dans les deux cas l’utilisation est assez simple :

  • pour convertir un depôt SVN, quelques commandes suffisent
  • pour synchroniser avec un dépôt SVN, les commandes « git-svn fetch » et « git-svn dcommit » remplaçent « git pull » et « git push »

Je ferai peut-être un article sur le sujet, j’imagine qu’il y a un certain nombre de personnes ayant déjà travaillé avec SVN qui ne souhaitent pas perdre leur versionning en passant à Git.

@matthieu merci pour ces précisions

@sébastien désolé je n’avais pas compris je pensais que tu parlais des SCM en général ;)

@sebastien J’utilise un scm dans ma webagency. Et je trouve l’utilisation très pratique. Je travaille avec 3 espace. 1 Dev, 1 préprod, et un autre prod. Avec un scm il est très facile de répercuter en préprod ou en prod tout les développements qui ont été effectué(, ou modifications). Sans d’inquiété d’avoir oublié un fichier. En plus en développant à plusieurs (ne serait-ce qu’1 intégrateur et 1 développeur), l’intégrateur n’est jamais dérangé par les modifications et les messages d’erreurs engendrés par un développeur.

Bonjour Matthieu et merci pour ce tutoriel très instructif.

Deux petites questions : - tu donnais cette instruction pour le fichier gitignore : find . -type d -empty | xargs -I % touch %/.gitignore Après xargs, c’est un i majuscule ? Car la console me renvoie une erreur semblant ne pas l’accepter.

  • As-tu expérimenté un plugin Git avec Eclipse ?

@Fred

oui c’est un i majuscule, après peut-être est-ce une option qui n’est pas disponible sur tous les environnements, je l’ai testé uniquement sur mac. Sinon il est possible de modifier la commande en remplaçant la partie « xargs » par l’option « -exec » de find, voir alors la doc et sur google pour la syntaxe exacte.

Pour Eclipse je n’ai pas essayé, ne l’utilisant pas moi-même. EGit est apparemment un plugin connu :

@Fred je me suis trompé pour le dernier lien EGit : http://github.com/guides/using-the-egit-eclipse-plugin-with-github

Merci Matthieu, Je pensais justement à Egit mais il a des dépendances avec d’autres plugin, je n’arrive pas encore à le faire fonctionner. Je reviendrais par là à l’occasion si je trouve une solution.

@Fred sinon ces vidéos pourront peut-être t’aider, elles expliquent comment intégrer git gui à eclipse :

Ca marche bien, merci :)

Petite question pour ceux qui utilisent un SCM. Comment vous organisez vous pour synchroniser et éventuellement versionner les modifications effectuées sur une base de données. Pour être plus concret, pour un projet Drupal ou un autre CMS ou une grosse partie du projet ne concerne pas la modification de fichiers mais plutôt des modifications de configuration via l’interface admin, comment synchroniser le travail de tout le monde ?

[...] Versionner un projet avec Git : principes et bases [...]

Participez

Pour insérer une portion de code, utilisez <pre lang="php">...</pre>