Chapitre 3. Clonons gaiement

Avec les anciens systèmes de gestion de versions, l’opération standard pour obtenir des fichiers est le checkout. Vous obtenez un ensemble de fichiers correspondant à un état particulier précédemment enregistré.

Avec Git et d’autres systèmes distribués de gestion de versions, le clonage est l’opération standard. Pour obtenir des fichiers, on crée un clone du dépôt entier. En d’autres termes, il s’agit de faire un miroir du serveur central. Tout ce qui peut se faire sur le dépôt central peut être fait sur le vôtre.

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardes ou une synchronisation simple. Mais parfois j'édite sur mon portable, d’autres fois sur mon fixe, et les deux peuvent ne pas avoir communiqué entre temps.

Initialisez un dépôt Git et faites un commit de vos fichiers depuis une machine. Ensuite sur l’autre :

$ git clone autre.ordinateur:/chemin/vers/les/fichiers

pour créer une deuxième copie de ces fichiers et du dépôt Git.

À partir de ce moment,

$ git commit -a
$ git pull autre.ordinateur:/chemin/vers/les/fichiers HEAD

ira chercher l'état des fichiers sur l’autre ordinateur pour mettre à jour celui sur lequel vous travaillez. Si récemment vous avez fait des modifications d’un même fichier en conflit entre elles, Git vous le signalera et vous devrez répéter à nouveau le commit après avoir résolu ces conflits.

Gestion classique des sources

Initialisez le dépôt Git de vos fichiers :

$ git init
$ git add .
$ git commit -m "Commit initial"

Sur le serveur central, initialisez un dépôt nu (bare dans la terminologie Git) dans un dossier quelconque :

$ mkdir proj.git
$ cd proj.git
$ git init --bare
$  # variante en une ligne : GIT_DIR=proj.git git init

Si besoin, démarrez le démon (service) :

$ git daemon --detach  # peut être tourne-t-il déjà

Pour les services d’hébergement en ligne, suivez les instructions fournies pour mettre en place le dépôt Git initialement vide. En général il s’agit de remplir un formulaire sur une page web.

Poussez votre projet vers le serveur central en utilisant :

$ git push git://serveur.central/chemin/du/proj.git HEAD

Pour obtenir les sources, un développeur saisit :

$ git clone git://serveur.central/chemin/du/proj.git

Après avoir fait des modifications, le développeur les enregistre en local :

$ git commit -a

Pour se mettre à jour par rapport à la dernière version :

$ git pull

Tout conflit lors de la fusion doit être résolu puis validé :

$ git commit -a

Pour envoyer les modifications locales vers le dépôt central :

$ git push

Si le serveur principal a de nouvelles modifications dues à d’autres développeurs, l’envoi échoue et le développeur doit se mettre à jour de la dernière version, résoudre les éventuels conflits de fusion, puis essayer à nouveau.

Dépôts nus

Un dépôt nu (bare repository) est nommé ainsi car il n’a pas de dossier de travail : il ne contient que des fichiers qui sont normalement cachés dans le sous dossier .git. En d’autres termes, il ne conserve que l’historique d’un projet et ne contient jamais le rendu d’une version donnée.

Un dépôt nu joue un rôle similaire à celui du serveur principal dans un système de gestion de versions centralisé : le réceptacle de vos projets. Les développeurs clonent vos projets à partir de celui-ci et y poussent les dernières modifications officielles. En général il est placé sur un serveur qui ne fait quasiment que ce travail de distribution de l’information. Le développement s’opère sur les clones de sorte que le dépôt principal peut se passer d’un dossier de travail.

Beaucoup des commandes de Git échouent sur un dépôt nu tant que la variable d’environnement GIT_DIR n’est pas renseignée avec le chemin vers le dépôt ou que l’option --bare n’est pas utilisée.

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de se contenter de la commande pull (tirer ou rapatrier) plus familière ? Premièrement, la commande pull échoue sur un dépôt nu : il faut y utiliser la commande fetch dont nous parlerons plus tard. Mais même si nous conservions un dépôt standard sur le serveur central, y rapatrier les modifications serait peu pratique. Nous devrions d’abord nous connecter au serveur et donner en argument à la commande pull l’adresse de la machine depuis laquelle nous souhaitons rapatrier des modifications. Des pare-feux peuvent éventuellement nous embêter, et comment faire si nous n’avons pas d’accès shell au serveur ?

Quoi qu’il en soit, ce cas mis à part, nous décourageons l’envoi ( en comparaison du rapatriement ) parce que cela peut entraîner des confusions lorsque la destination possède un dossier de travail.

En résumé, pendant votre phase d’apprentissage de Git, n’utilisez l’envoi ( push ) que lorsque la destination est un dépôt nu ; sinon rapatriez ( pull ).

Forker un projet

Vous en avez marre de la manière dont est géré un projet ? Vous pensez pouvoir faire mieux ? Dans ce cas, sur votre serveur :

$ git clone git://serveur.principal/chemin/vers/les/fichiers

Ensuite, informez tout le monde du fork de ce projet sur votre serveur.

Par la suite, vous pouvez fusionner les modifications venant du projet originel grâce à :

$ git pull

Système ultime de sauvegarde

Vous voulez des archives redondantes et géographiquement distribuées, permettant de faire face à un désastre ? Si votre projet a beaucoup de développeurs, ne faites rien ! Chaque clone de votre code est de fait une sauvegarde. Non seulement de l'état actuel, mais de l’historique complet. Grâce aux empreintes cryptographiques, si le clone de quelqu’un est corrompu, il sera repéré dès qu’il tentera de communiquer avec d’autres.

Si votre projet n’est pas si populaire, trouvez autant de serveurs que possible afin d’héberger vos clones.

Le vrai paranoïaque devrait toujours noter la dernière empreinte SHA1 de 20 octets du HEAD dans un endroit sûr. Ce doit être sûr, pas privé. Par exemple, la publier dans un quotidien marcherait bien, parce qu’il est difficile de réaliser une attaque modifiant l’ensemble des exemplaires d’un journal.

Le multi-tâche à la vitesse de la lumière

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnalités en parallèle. Dans ce cas validez (commit) votre projet et lancez :

$ git clone . /un/nouveau/dossier

Grâce aux liens matériels, les clones locaux sont créés plus rapidement et occupent moins de place que de simples copies.

Vous pouvez maintenant travailler simultanément sur deux fonctionnalités indépendantes. Par exemple vous pouvez modifier l’un des clones pendant que l’autre est en cours de compilation. À tout moment vous pouvez valider (commit) vos modifications puis rapatrier (pull) les modifications depuis l’autre clone.

$ git pull /mon/autre/clone HEAD

Guérilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre système de gestion de versions, Git vous manque ? Dans ce cas, initialisez un dépôt Git dans votre dossier de travail.

$ git init
$ git add .
$ git commit -m "Commit initial"

puis clonez-le :

$ git clone . /un/nouveau/dossier

Allez ensuite dans le nouveau dossier et travaillez plutôt là, utilisant Git comme vous le voulez. De temps à autre, quand vous voulez vous synchroniser avec les autres, rendez-vous dans le dossier de départ, synchronisez-le en utilisant l’autre système de gestion de version, puis saisissez :

$ git add .
$ git commit -m "Synchro avec les autres"

Ensuite allez dans le nouveau dossier et lancez :

$ git commit -a -m "Description de mes modifications"
$ git pull

La procédure pour partager vos modifications avec les autres dépend de l’autre système de gestion de versions. Le nouveau dossier contient les fichiers avec vos modifications. Lancez toute commande de l’autre système de gestion de versions nécessaire pour les envoyer au dépôt central.

Subversion, qui est peut être le meilleur système de gestion de versions centralisé est utilisé par d’innombrables projets. La commande git svn automatise la procédure ci-dessus pour les dépôts Subversion, et peut aussi être utilisée pour exporter un projet Git vers un dépôt Subversion.

Mercurial

Mercurial est un système de gestion de versions similaire qui peut travailler quasiment sans heurt avec Git. Avec le plugin hg-git un utilisateur de Mercurial peut, sans rien perdre, envoyer (push) vers ou rapatrier (pull) depuis un dossier Git.

Téléchargez le plugin hg-git avec Git :

$ git clone git://github.com/schacon/hg-git.git

ou Mercurial:

$ hg clone http://bitbucket.org/durin42/hg-git/

Malheureusement, il ne semble pas y avoir de plugin analogue pour Git. Pour cette raison, il semble préférable d’utiliser Git plutôt que Mercurial pour le dépôt principal. Avec un dépôt Mercurial, il faut généralement un volontaire qui maintienne un dépôt Git en parallèle alors que, grâce au plugin hg-git, un dépôt Git fait l’affaire même pour les utilisateurs de Mercurial.

Bien que ce plugin puisse convertir un dépôt Mercurial en un dépôt Git en le poussant dans un dépôt vide, cette tâche est plus simple avec le script hg-fast-export-git, disponible via :

$ git clone git://repo.or.cz/fast-export.git

Pour faire une conversion, dans un nouveau dossier :

$ git init
$ hg-fast-export.sh -r /depot/hg

ceci après avoir ajouté le script à votre $PATH.

Bazaar

Nous allons rapidement évoquer Bazaar parce que c’est le système de gestion de versions distribué libre le plus populaire après Git et Mercurial.

Bazaar à l’avantage d’avoir plus de recul, étant donné qu’il est relativement jeune ; ses concepteurs ont pu tirer les leçons du passé et éviter des petits écueils historiques. De plus ses développeurs ont le souci de la portabilité et de l’interopérabilité avec les autres systèmes de gestion de versions.

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec les dépôts Git dans une certaine mesure, et permet de le faire de manière incrémentale, tandis que bzr-fast-export est fait pour les conversions uniques.

Pourquoi j’utilise Git

Au départ j’ai choisi Git parce que j’ai entendu qu’il gérait l’inimaginablement ingérable source du noyaux Linux. Je n’ai jamais ressenti le besoin d’en changer. Git m’a rendu de fiers services et je ne me suis toujours pas heurté à ses limites. Comme j’utilise surtout Linux, les éventuels problèmes sur d’autres plateformes n’entrent pas en ligne de compte.

De plus je préfère les programmes C et les scripts bash aux exécutables comme les scripts Pythons : il y a moins de dépendances et je suis accro aux temps d’exécution rapides.

J’ai réfléchi à la manière d’améliorer Git, allant jusqu'à écrire mes propres outils de type Git, mais uniquement à des fins de recherche. Même si j’avais terminé ce projet j’aurais tout de même continué avec Git vu que les avantages sont trop peu significatifs pour justifier l’utilisation d’un système farfelu.

Bien sur, vos besoins et envies diffèrent sûrement et vous pouvez très bien vous trouver mieux avec un autre système. Néanmoins vous ne pouvez pas faire une grosse erreur en choisissant Git.