-
Développement -
Publié le Dimanche 21 juin 2009 à 20 h 08 min -
5 commentaires
Introduction au contrôle de version avec Git
Tout projet nécessitant une collaboration entre plusieurs personnes se voulant simple à gérer et à maintenir se doit de faire recours au contrôle de version. Ceci est une introduction à Git, le système de contrôle de version puissant et moderne qui a le vent en poupe.
Un système de contrôle de version (Version Control System, VCS ou Source Control Management system, SCM) permet de suivre les modifications effectuées aux fichiers d’un projet. Dans sa forme la plus simple, la manipulation consiste à créer une copie du fichier vers un emplacement distant (appelé dépôt) en y ajoutant date, informations sur l’auteur et un commentaire sur les modifications apportées. Partant de cela, plusieurs outils destinés à automatiser la tâche ont vu le jour comme CVS (Concurrent Versions System) ou SVN (Subversion) ainsi que Git qui est le sujet de cet article.
Les principes de base de Git
Avant de pouvoir entrer dans le vif du sujet, il est nécessaire de comprendre la philosophie de Git. Les lignes qui suivent décrivent les principales terminologies et les atouts de Git face à la concurrence.
Le dépôt
Le dépôt est l’endroit où tous les fichiers de votre projet sont stockés, contenant un historique complet géré par un système de contrôle de version (VCS). Git diffère des autres outils dans la manière dont vous communiquez les changements apportés au projet. Quand les autres empruntent un modèle centralisé basé sur un seul et unique serveur, Git est entièrement décentralisé.
Dans un modèle centralisé, chaque personne désirant contribuer au projet rapatrie la version la plus récente du dépôt distant et envoi directement les modifications au serveur. Ce mode de fonctionnement présente un réel problème. En effet, il est impossible de travailler sans être connecté à Internet car une communication avec le serveur est forcément nécessaire.
Git est dit décentralisé car chaque collaborateur dispose d’une version complète de l’historique du dépôt distant (et non plus de la dernière version uniquement) sur son ordinateur appelé alors dépôt local. Une connexion à Internet n’est donc plus nécessaire pour continuer à travailler.
Ce modèle décentralisé permet également d’utiliser Git dans un but entièrement personnel. En effet, il est possible de créer un dépôt local pour un projet sans jamais le partager, simplement pour bénéficier des avantages d’un système de contrôle de version pour soi.
L’arbre de travail
L’arbre de travail contient tous les fichiers de votre projet à l’instant sélectionné dans l’historique du dépôt. C’est ici que les changements sont effectués. Contrairement à SVN, la modification d’un fichier ne signifie pas nécessairement l’envoi au dépôt distant. Le changement est dans un premier temps enregistré dans cet arbre de travail, à vous de décider ce que vous voulez en faire. Ce n’est pas le cas avec un modèle centralisé où chaque changement devient visible par tout le monde et une erreur peut très vite devenir embarrassante.
Manipulation des fichiers
Lorsqu’une modification est jugée satisfaisante, on en informe le dépôt local qui va alors y inscrire les informations sur la nouvelle révision du projet. Cette action est appelée commit.
Le fait d’avoir la possibilité de sauvegarder les changements dans le dépôt local avant l’envoi au dépôt distant présente un réel avantage. En effet, il devient alors possible d’expérimenter sans forcément le faire savoir aux autres collaborateurs tout en gardant un historique des modifications de ces expérimentations. Enfin, cela permet de s’affranchir du besoin constant d’une connexion Internet comme ce serait le cas dans un modèle centralisé.
Si l’on désire partager les nouveaux changements, on push la dernière révision vers un dépôt distant. Pour mettre à jour le dépôt local, on pull les derniers changements du dépôt distant.
Les branches et les fusions
Dans un projet, plusieurs idées peuvent être étudiées avant d’être intégrées définitivement. Grâce aux branches, Git offre la possibilité de faire diverger le projet à un moment donné. Ceci permet de pouvoir expérimenter sans modifier la branche principale du projet (aussi appelé trunk) tout en continuant à garder un historique des modifications pour toutes les branches.
Lorsqu’une idée s’avère meilleure que celle utilisée actuellement dans la branche principale et que l’on désire l’y inclure, on merge (fusionne) notre branche avec la branche principale. Pour cela, Git utilise une façon de faire très naturelle : il compare les deux historiques et détermine où les changements ont eu lieu. Cette branche peut ensuite être conservée ou détruite.
Verrouillage des fichiers
Les systèmes de contrôle de version traditionnels ne permettent pas l’édition du même fichier par plusieurs personnes. Vous demandez la permission au dépôt distant d’éditer un fichier (check out) et celui-ci se charge de bloquer son accès tant que les modifications ne sont pas terminées (check in).
Ce mode de fonctionnement est appelé verrouillage strict. Git utilise quant à lui un verrouillage optimiste : plusieurs personnes peuvent travailler sur le même fichier en assumant que la plupart du temps il n’y aura pas de conflits.
Une personne envoi les modifications au dépôt distant. Une autre personne ayant modifié le même fichier envoi également ses modifications et Git détecte un conflit. Dans ce cas, la deuxième personne devra récupérer la dernière version du fichier et gérer elle-même les conflits avant de pouvoir renvoyer ses modifications au serveur.
Installation et configuration de Git
Si vous avez compris les principes expliqués ci-dessus, le plus dur est fait. La prochaine étape consiste à installer Git sur notre machine. La manipulation est décrite pour Linux (Ubuntu plus précisément), Mac OS X et Windows. Dans le cas où vous rencontrerez des problèmes lors de l’installation, n’hésitez pas à consulter Google.
Installation sous Linux (Ubuntu 9.04)
Afin d’être certain de disposer de la dernière version (1.6.3.2 actuellement), il est recommandé d’aller télécharger directement les sources sur le site de Git et des les compiler soi-même.
Avant de télécharger les sources, il faut s’assurer que votre machine dispose des dépendances nécessaires au fonctionnement de Git :
1 | root@ubuntu:/$ apt-get install build-dep libcurl4-openssl git-core git-doc |
Téléchargement et décompression des sources dans le dossier /usr/src (par principe) :
1 2 3 4 | root@ubuntu:/$ cd /usr/src root@ubuntu:/usr/src$ wget http://kernel.org/pub/software/scm/git/git-1.6.3.2.tar.gz root@ubuntu:/usr/src$ tar xzf git-1.6.3.2.tar.gz root@ubuntu:/usr/src$ cd git-1.6.3.2 |
On peut alors passer à la compilation et l’installation :
1 2 | root@ubuntu:/usr/src$ make all root@ubuntu:/usr/src$ make install |
Pour vérifier que Git est bien installé, on utilise la commande :
1 2 | root@ubuntu:/usr/src$ git --version git version 1.6.3.2 |
Installation sous Mac OS X (Leopard)
Pour les utilisateurs du système à la pomme, l’installation se voit grandement simplifiée grâce à la mise en ligne d’un assistant d’installation répondant au nom de git-osx-installer.
Pour le télécharger, rendez-vous ici.
Installation sous Windows (Vista)
Faire fonctionner Git sur Windows n’a pas toujours été une mince affaire. Fort heureusement, il est aujourd’hui possible de s’affranchir de l’utilisation de Cygwin grâce à Git on Windows.
Le programme d’installation se trouve ici et ne demande rien de plus que de cliquer sur le bouton « Suivant » à chaque étape.
Configuration
La configuration de Git ne prendra que quelques secondes grâce à la commande git-config. Il suffit de renseigner les informations nécessaires pour nous contacter, c’est-à-dire un nom et une adresse mail en tapant les commandes suivantes :
1 2 | git config --global user.name "Maxime Bornemann" git config --global user.email "contact@maximebornemann.com" |
Travailler avec le dépôt local
Tout est enfin en place pour que nous commencions à manipuler Git. Durant la suite de cet article, je prendrai comme exemple une simple page HTML. J’y apporterai ainsi des modifications au fur et à mesure que les aspects évoqués précédemment seront illustrés par la pratique. Cette partie a uniquement pour objectif de travailler avec un dépôt local.
Création du dépôt local pour le projet
Créer un dépôt avec Git est très aisé. Une fois l’emplacement où seront stockés les fichiers de votre projet définit, il suffit d’utiliser la commande git init. Par exemple :
1 2 3 4 5 | mkdir projet-site cd projet-site git init Initialized empty Git repository in /Users/Maxime/projet-site/.git/ |
C’est aussi simple que ça, le répertoire projet-site sert désormais d’arbre de travail (pour rappel, l’arbre de travail contient les fichiers de votre projet à l’instant que vous avez sélectionné dans l’historique du projet), tandis que le dossier .git contient les informations relatives au dépôt.
Ajouter des fichiers au projet
Le dépôt est en place, il est temps d’y ajouter des fichiers. Pour cela, je vais créer une simple page HTML (index.html) contenant le strict minimum. Voici l’allure de la page :
1 2 3 4 5 6 7 8 9 10 11 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="fr-FR"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Introduction à Git</title> </head> <body> </body> </html> |
On doit maintenant informer Git que ce fichier fait parti du projet (et donc du commit) avec la commande git add :
1 | git add index.html |
Et on commit enfin le fichier accompagné d’un descriptif des modifications apportées avec la commande git commit -m « message » :
1 2 3 4 5 | git commit -m "Basic HTML index page created." [master (root-commit) 961d7c4] Basic HTML index page created. 1 files changed, 11 insertions(+), 0 deletions(-) create mode 100644 index.html |
Essayez d’être le plus descriptif dans les notes associées à vos commit, ils deviendront d’une grande utilité plus tard. J’ai tendance à conseiller d’écrire en anglais, pour faciliter le partage du code à l’international.
Plusieurs choses sont à noter dans le message renvoyé par Git. Tout d’abord, master signifie que le commit a été effectué sur la branche principale. 961d7c4 est un identifiant unique (obtenue avec la fonction de hachage SHA-1) permettant à Git de s’organiser.
La deuxième ligne indique les modifications qui ont été apportés à notre fichier par rapport à la version précédente. Git fait état de 11 ajouts dans le fichier et aucune suppression, ce qui est logique étant donné qu’il s’agit d’un nouveau fichier.
Voici un aspect que je n’ai pas évoqué jusqu’à présent. Contrairement à certains systèmes de contrôle de version, Git ne surveille pas les changements des fichiers mais les changements apportés au contenu des fichiers. Cela aura un impact important dans la taille que prendra notre dépôt par la suite.
Modification des fichiers
J’ajoute maintenant deux nouvelles lignes à mon index.html :
1 2 3 | <h1>Bienvenue !</h1> <p>Cet article a pour but de présenter Git, le mangeur d'arbres.</p> |
Grâce à la commande git diff, il est possible de connaître quelles lignes du fichier ont été modifiées comparé à la version sur notre dépôt local :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | git diff diff --git a/index.html b/index.html index 380dae5..8da2329 100644 --- a/index.html +++ b/index.html @@ -7,5 +7,8 @@ </head> <body> + <h1>Bienvenue !</h1> + + <p>Cet article a pour but de présenter Git, le mangeur d'arbres.</p> </body> </html> \ No newline at end of file |
Retenez bien cette commande, car vous allez l’utiliser très fréquemment tout comme git status, permettant d’afficher l’état de notre dépôt :
1 2 3 4 5 6 7 8 9 10 | git status On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: index.html # no changes added to commit (use "git add" and/or "git commit -a") |
Comme l’indique la dernière ligne il est possible d’effectuer un commit d’une autre façon que celle utilisée précédemment (git add puis git commit -m « message »), en utilisant git commit -a qui ne vous oblige plus à ajouter manuellement les fichiers destinés au commit. Cette commande ouvre l’éditeur vi dans lequel vous devrez rédiger le message accompagnant le commit.
Revenir en arrière
Imaginons que la dernière modification apportée à votre dépôt s’avère en réalité être une erreur. Pour revenir en arrière, il suffit d’utiliser la commande git revert associé à l’identifiant unique du commit. Cette commande va remettre notre arbre de travail (le contenu du dossier de notre projet), dans l’état où il était au moment du commit indiqué.
Pour obtenir l’identifiant unique d’un commit, on peut faire appel à la commande git log qui affichera des informations sur les dernières modifications apportées au dépôt.
1 2 3 4 5 6 7 8 9 10 11 12 13 | git log commit 624c0bc7afd9e2a6edcfdc3f41e99113c2dacbea Author: Maxime Bornemann <contact@maximebornemann.com> Date: Sat Jun 20 22:27:02 2009 +0200 Added basic structure for the content. commit 961d7c4de33acaa5350ca9b8540d9d6ec38ae6a3 Author: Maxime Bornemann <contact@maximebornemann.com> Date: Sat Jun 20 19:44:18 2009 +0200 Basic HTML index page created. |
Par exemple, pour revenir à mon premier commit et annuler les deux lignes que je viens d’ajouter :
1 | git revert 624c0bc7afd9e2a6edcfdc3f41e99113c2dacbea |
Travailler avec les branches
Prenons un exemple simple : vous arrivez à un certain point dans votre projet et vous aimeriez le présenter publiquement. Le temps que cela se produise, vous désirez pouvoir continuer à travailler dessus sans modifier l’état actuel du projet. La solution est simple, il suffit de créer une branche qui sera un clone des fichiers contenus dans la branche où se trouve le projet que l’on souhaite présenter.
Pour créer une nouvelle branche, on utilise la commande git branch nouvelle_branche branche_origine. Pour créer une branche « projet-2.0″ à partir de la branche principale de mon dépôt :
1 | git branch projet-2.0 master |
La commande git branch sans argument affiche la liste de toutes les branches du dépôt, celle où l’on se trouve étant symbolisée par une étoile :
1 2 3 4 | git branch * master projet-2.0 |
Comme l’on se trouve dans la branche principale, les commit effectués concerneront uniquement cette branche et n’affecterons en aucun cas les autres branches. Pour changer de branche, on utilise la commande git checkout nom_branche :
1 2 3 4 5 6 7 8 | git checkout projet-2.0 Switched to branch "projet-2.0" git branch master * projet-2.0 |
On peut aussi comparer deux branches avec la commande diff (git diff master projet-2.0 par exemple).
En travaillant sur votre projet, vous avez eu plusieurs idées sans être certain qu’elles seront intégrées au projet. Vous avez donc créé une ou plusieurs branches dans l’optique d’expérimenter. Une de ces idées s’avère être bonne et doit être ajoutée à la branche principale. Comment faire ? Tout simplement en faisant un merge des deux branches. Il faut préalablement se placer dans la branche de destination :
1 2 3 | git checkout master Switched to branch "master" git merge projet-2.0 |
Travailler avec le dépôt distant
Vous maîtrisez à présent toutes les commandes et principes de bases à savoir sur Git, il est temps de partager votre projet à l’aide d’un dépôt distant. Pour obtenir un dépôt distant, plusieurs possibilités s’offrent à vous. Si vous avez de la chance, quelqu’un en à déjà mis un en place. Si ce n’est pas le cas, vous pouvez décider de le créer vous même ou de vous tourner vers des hébergeurs spécialisés comme Github.
Création d’un dépôt public
L’inconvénient de Github est que pour disposer d’un dépôt distant privé (accessible uniquement par les membres de votre équipe par exemple) il est impératif de payer un abonnement. Bien qu’abordable (débutant à 7$ par mois) et dans la plupart des cas suffisante, cette solution peut ne pas plaire à tout le monde.
Pour cette raison, j’expliquerai uniquement comment mettre en place un dépôt distant sur un serveur Web nous étant propre. Si vous désirez tout de même utiliser Github, sachez que de nombreux tutoriels sont disponibles sur Internet, et une simple recherche Google devrait vous y conduire.
Pour communiquer avec un dépôt distant, nous avons le choix entre deux protocoles. Le protocole Git garantit un fonctionnement optimal mais nécessite l’ouverture de ports ce qui peut s’avérer gênant. Le protocole HTTP quant à lui ne nécessite guère plus qu’un serveur Web fonctionnel, c’est donc cette solution que nous allons utiliser.
Reprenons notre dépôt local situé dans le dossier projet-site/ pour le rendre public. Pour cela, on créé un clone du dépôt contenant uniquement les informations relatives à ce dépôt et non les fichiers, c’est à dire le dossier .git/ situé dans ce même dossier :
1 | git clone --bare projet-site projet-site.git |
Copiez ensuite le dossier sortant (ici projet-site.git) vers votre serveur Web et exécutez les deux commandes suivantes dans le dossier nécessaires au bon fonctionnement du dépôt :
1 2 | git --bare update-server-info chmod a+x hooks/post-update |
À cet instant précis, il devient possible de cloner le dépôt distant directement sur votre machine avec la commande :
1 | git clone http://monserveur.com/git/projet-site.git |
Attention, cette action aura pour effet de créer un nouveau dépôt local et non de mettre à jour celui que nous disposons déjà.
Pour éviter d’avoir à taper l’adresse entière à chaque fois, il possible de donner un nom à ce dépôt distant sur notre machine. Dans ce cas, le dépôt distant aura pour nom origin :
1 | git remote add origin http://monserveur.com/git/projet-site.git |
Envoyer les changements au dépôt distant
Pour envoyer les changements effectués au dépôt local vers le dépôt distant, il faut utiliser la commande git push en spécifiant la branche qui doit être envoyée ou en ne mettant rien pour envoyer la branche principale :
1 | git push origin |
Récupérer les nouveaux changements
Lorsque vous clonez un dépôt distant pour la première fois, vous « suivez » par défaut sa branche principale. Cela signifie que lorsque vous récupérerez les changements de ce dépôt, seuls cette branche sera mise à jour dans le dépôt local.
La liste des branches distantes est accessible avec la commande :
1 | git branch -r |
La commande git fetch permet d’ajouter une nouvelle branche distante à suivre et prend trois arguments : le nom ou l’adresse du dépôt distant, le nouveau de la branche distante et le nom qu’aura cette branche dans notre dépôt local (on peut conserver le même nom).
Par exemple, si l’on souhaite suivre une branche distante nommée projet-2.0-test :
1 | git fetch origin projet-2.0-test:projet-2.0-test |
Enfin, pour mettre à jour toutes les branches et les faire fusionner avec notre dépôt local on fait appel à la commande :
1 | git pull |
Pour aller plus loin
Cet article constitue une très bonne base pour utiliser Git dans la vie de tous les jours. Cependant, pour réellement le comprendre, je ne peux que vous encourager à pratiquer. Le contrôle de version s’applique à toute sortes de projets et pas seulement à ceux liés à la programmation alors n’hésitez pas à faire des commit à toutes les sauces !
Pour finir, voici une liste des liens intéressants sur le sujet :
- - Google Tech Talk : Linus Torvalds on Git (Video)
- - Google Tech Talk : Randal Schwartz on Git (Video)
- - FLOSS Weekly #19 : Git (Leo Laporte, Randal Schwartz, Junio Hamano) (Audio)
- - Gitcasts (Screencasts)
- - Git pour les (futurs) barbus (Article)
- - Setting up a new remote git repository (Article)






Retourner en haut de la page
XHTML



Que dire ! bien que je reste convaincu par SVN, ton article est excellent, complet et très instructif, merci à toi.
Salut,
Vraiment intéressant en effet cet article.
J’ai tout de même un peu de mal à comprendre l’intérêt. Faut dire que je me suis mis récemment à SVN. Est-ce que j’ai bien compris ? Le fait d’avoir un repository local permet de créer une version stable à un moment donné sans être connecté au réseau puis de continuer le développement.
Ainsi, sans être jamais connecté on peut créer plusieurs versions stables ce qui permettra, si besoin de revenir à une version stable facilement. Est-ce que tu confirmes que dans le cas où on peut être connecté en permanence, le gain d’avoir un repository local n’est pas si probant ?
Autre point, existe t-il des interfaces graphiques pour le dialogue avec les repositories ? J’utilise versions sous mac et subclipse et c’est un vrai bonheur, les utilisateurs du système à la fenêtre ont l’excellent tortoise
Merci pour ton article
Avoir un dépôt local permet de continuer à travailler sans être connecté constamment à Internet. Il est vrai que cet aspect peut de nos jours sembler mineur, mais si l’unique dépôt distant tombe en panne, tu vas avoir du mal à travailler. Ce n’est pas le cas avec Git. Enfin, avoir un dépôt local permet de travailler sur des morceaux de projet sans être obligé de partager ton travail avec les autres et quand même continuer avoir un suivi des modifications sur ta machine (contrairement à SVN), c’est principalement sur ce point que j’apprécie Git.
Je ne suis pas fan des interfaces graphiques pour ce genre d’outils (ce qui peut paraître étrange vu mes centres d’intérêts), mais GitX répondra peut-être à tes besoins.
Je conçois que Git ne soit pas simple à utiliser du premier coup, c’est pour cela que j’essaye de rédiger un guide compréhensible et cet article sera peaufiné avec le temps grâce aux commentaires que je reçois. Je te remercie donc d’avoir donné ton avis.
Bonjour,
Bon article qui m’a appris beaucoup et félicitation pour ce nouveau blog. Le fait de pouvoir utiliser un dépôt local est une fonctionnalité hautement utile pour moi qui développe presque exclusivement dans le train (et donc sans connexion internet).
Concernant l’utilisation de Git j’ai deux questions :
1) Comment faire pour que Git prenne en compte les sous-dossier d’un projet (ce qui revient à demander comment faire pour distinguer nouvelle branche et sous-dossier) ?
2) Comment fait-on pour utiliser Git sur un projet existant : doit-on ajouter chaque fichier « à la main » ou existe-il une commande qui automatise tout ça ?
En vous remerciant pour votre réponse.
Wham ^_^
@Jerry Wham: pour rajouter un dossier, il suffit de faire git add /le/chemin/du/dossier. L’inclusion est récursive, et tu dois ajouter les dossier dans .gitignore si tu ne veux pas qu’ils soient inclus.
Tu peux aussi inclure un dossier qui est déjà versionné, si tu ne veux pas faire la chasse aux fichiers non versionnés, en faisant par exemple : git add .
Git ajoutera tous les fichiers non versionnés ou modifiés, et ignorera les autres.
@pyrou, @switcherdav : Je vois au moins trois intérêts majeurs à git :
1°) les branches et les tags. Leur utilisation est extrêmement simplifiée par rapport à svn, ce qui encourage leur utilisations. Je ne compte plus le nombre de fois où je crée une branche juste pour faire un test. Si ca me va, je merge la branche dans la branche principale, sinon je l’efface. Il n’y a plus ainsi de crainte de tester des modifications qui risquent de trop retourner le code.
2°) le répertoire .git. Il est pénible, avec svn, de devoir taper une ligne de find pour supprimer chaque répertoire svn si on désire déversionner une working copy. Avec git, il n’y a qu’un dossier .git à la racine qu’il suffit de supprimer. Le prix a payer pour ça est de ne pas pouvoir extraire qu’une partie du repository, comme avec svn checkout svn://repos/un/path/quelconque
3°) github ( https://github.com ). C’est aujourd’hui l’un des pôles les plus actifs d’innovation, et il nécessite l’utilisation de git.
Enfin, j’ajouterai que le pont entre git et svn est possible. Avec mes collègue, nous utilisons svn comme application de versionnement globale, et j’utilise git de mon côté, en local. La démarche est relativement simple :
# récupération des sources initiales
mkdir repos
cd repos
git svn init svn://repos
git svn fetch
# mise à jour (svn update)
git svn rebase
# commit
git commit
git svn dcommit
Avec un petit « trick », consistant dans le fait que git-svn a besoin d’un repos clean :
git stash
git svn rebase
git stash apply
(valable aussi pour dcommit)