SCM - Git

Prise en main de Git

Thomas Riboulet

Librium.org, GCU, Koalabs


          
        


Table of Contents

1. Git 101
Licence
Rapide tour d'horizon
Le cas Git
Avant de s'aventurer trop loin
Ce que nous allons voir
Un détour par Limoges
2. Git 102
Initialisation d'un depot
Ajouter/Supprimer un fichier, un repertoire
Commit
Et sinon, je peux faire un diff ?
Tu nous a toujours pas montre le diff
Les ptis gateaux avec le the
3. Git 103
L'autre pistonne la ...
Si Si il y avait un treizieme apotre ...
Light Tag
Annotated tag
Il prit le pain et le rompit
Rompons donc, rompons
Et la les deux branches n'en refont qu'une
Alors la marmotte tu vois ...
4. Git 104
Hello world, here is something for you
Quand Jean veut que Jeanne puisse acceder a son depot
Hep, hep tiens v'la de la bonne stuff etranger !
Hep ! Messire ?! J'aurai quelques pillules pour vous !
What does the H stand for in 'SSH' ?
Pull, pull, mais ... mais, comment on fait ?
Enl4rg3 your d3p0t !
Eviter les urls ...
Et c'est quoi ce bouton la ?

Chapter 1. Git 101

Mais tu sais pas cliquer !

Ayant, pour mes projets personnels, besoin d'utiliser un gestionnaire de configuration (que c'est beau comme dénomination, j'utiliserai désormais 'SCM') décentralisé je me suis intéressé a plusieurs d'entre eux. Évidement seulement ceux qui sont libres. Je ne rentrerai pas dans les détails de mes raisons afin d'éviter de voir se jeter sur moi un troll des cavernes hirsute. Ceci dit Git semble coller à mes besoins et présenter un certain nombre d'avantage sur d'autres.

Licence

Ce document est publié sous licence Creative Commons by SA.

Rapide tour d'horizon

Depuis CVS (et meme ses aieuls) il y a eu beaucoup de progrés et beaucoup de nouveaux sur le marché. On a du mal à garder le compte. Certains sont populaires, d'autres moins, et nombreux sont les inconnus. Ils sont généralement répartis dans deux familles : les scm centralisés et ceux qui ne le sont pas.

Classiques et surement plus connus sont les centralisés.

  • subversion

  • cvs

Mais il y a de plus en plus de non centralisés, parfois très populaires.

  • darcs

  • arch

  • bzr

  • mercurial

  • git

  • monotone

Ces deux listes ne sont pas exhaustives et de nombreux autres existent.

Le cas Git

Écrit par Linus Torvalds peu de temps après que BitKeeper soit devenu non gratuit (il était déja propriétaire) pour les projetslibres il a rapidement atteint un stade de maturité puisqu'il a très vite été utilisé pour gérer le développement du noyau linux. Désormais maintenu par Junio Hamano, Git semble promis a un sympathique avenir.

Cette serie d'articles constitue une prise en main de celui ci. Largement inspirés du howto initialement écrit par Linus Torvalds (et la ml git) disponible dans les sources de Git.

Je ne couvrirai pas l'install puisque suivant l'OS libre que vous utilisez la méthode changera probablement. Cependant les sources sont disponibles via git (malin hein ...) ou de facon plus pratique via des tarballs : http://www.kernel.org/pub/software/scm/git/. Ce qui suit a été réalisé sur un GNU Gentoo Linux, avec les ports git et cogito installés puis continué sur un OpenBSD 3.7 (sur un laptop oui, c'est pas seulement pour les serveurs OpenBSD) avec seulement le core installé.

Ceux qui suivent la ml git auront peut être vu passer un thread à propos d'un homonyme de git : git Gnu Interactive Tools. Pour ceux qui utilisent Debian faites attention d'installer le bon paquet.

Avant de s'aventurer trop loin

Si vous êtes habitué (comme moi) à utiliser un SCM centralisé (cvs, subversion, ...) : ne paniquez pas, vous retrouverez vos marques en terme d'utilisation. En terme de principes principes et de méthodologie je ne peux pas dire la meme chose. Utiliser un SCM decentralisé implique une facon différente de travailler. Différente mais pas non plus antipodique. Nous y viendrons.

Ce que nous allons voir

Sans rentrer autant dans les détails que le core-tutoriel je vais tacher de vous présenter Git, à travers ses commandes de base ainsi que certaines commandes avancées.

Le premier chapitre (Git 102) couvrira les commandes de base : initialisation d'un dépôt, ajout de fichiers (et suppression), commit, diff, status.

Le deuxième chapitre (Git 103) couvrira les commandes utlisées pour créer des branches, des tags et j'en profiterai pour présenter leur utilité.

Le troisième chapitre (Git 104) couvrira des commandes plus avancées et néanmoins indispensables : pull, push ainsi que celles permettant de débloquer des fichiers, résoudre les conflits, faire un dépôt etc ... Ce chapitre vous donnera les clefs pour pouvoir travailler avec d'autres gens (oui oui même le monsieur à lunettes du 3ième etage).

Le quatrième chapitre (Git 105) sera une présentation de principes à connaître pour travailler à plusieurs avec un scm décentralisé. Quelque peu simpliste, basé sur les conseils donnés dans le core tutoriel et mes pensées sur le sujet il n'a pas vocation d'évangile. J'essayerai juste de faire passer des idées et principes qui devraient vous permettre de trouver des façons de faire qui collent relativement bien à l'outil.

D'autres chapitres sont prévus, notament à propos des interactions avec svn, cvs, les migrations depuis ceux ci, les hooks, l'utilisation de certaines fonctions avancées de git (bisect), ... Mais pour le moment, eh beh, faudra attendre :)

A l'issu de tout ça vous devriez avoir une bonne compréhension de comment se servir de Git tous les jours voir les jours un peu particuliers quand tout d'un coup trois personnes vous disent qu'ils ont codé des trucs sur leur repos git a eux et que oui ils voudraient bien se synchroniser avec vous.

Un détour par Limoges

Une critique qui revient souvent est que Git est compliqué difficile à utiliser. Et oui c'est, en un sens, vrai. Vous allez voir qu'il est différent d'autres scm mais pas si difficile a prendre en main. Néanmoins pour faciliter la vie plusieurs projets annexes à git ont vu le jour. Désignés par le terme porcelain ces projets sont des scripts au dessus des programmes principaux de git, écrits de façon à faciliter l'usage de celui ci.

Je n'utiliserai pas réellement de porcelain dans ce tutoriel, j'utilise surtout directement git, et vous verrez que c'est tout à fait utilisable (et que c'est pas si compliqué que ça).

Chapter 2. Git 102


        Tu sais pourquoi je veux etre celebre ?
        Non
        Parce que quand on est celebre on baise plein de nanas
        Oh ?
        Ouai et on peut bouffer des trucs vachement meilleurs
        Comme ?
        Des quiches Lorraines
        Des ouiches
        Hum ?
        Des Ouiches Lorraines, on dit des Ouiches Lorraines.
      

-- R Redford, D Hoffman , "Le grand detournement, la Classe Americaine"

Cette section couvre la prise en main rapide de Git, une sorte de "Fiche d'apprentissage rapide" pour connaitre les commandes minim ales. Le genre de chose qui fait bon a connaitre pour briller en societe ... Si vous trouvez laquelle faites moi signe.

Initialisation d'un depot

L'initialisation d'un depot (et donc de votre environnement de travail initial) se fait d'une maniere simple :

  • creer un repertoire

  • initialiser le depot

Ce qui correspond aux commandes suivantes :

         #> mkdir mygit
         #> cd mygit
         #> git-init-db
         defaulting to local storage area
       

Le gentil Git va vous avoir cree un repertoire .git dans lequel il a mis ses affaires (attention meme s'il deborde pas du tout de son panier il a tendance a prendre de la place).

Voila c'est fait, ca va ? Je vous sens un peu tendu la.

Ajouter/Supprimer un fichier, un repertoire

L'ajout et la suppression de fichiers du depot se font sans trop de douleurs :

          #> git add file1 file2 ...
          #> git remove file1 file2 ...
        

Oui, je vous ai entendu "comme avec svn/cvs".

Creeons donc deux fichiers : hello, et exemple avec du contenu plus ou moins utile :

          #> echo "hello world" > hello
          #> echo "my taylor is rich" > exemple
        

Evidement notre ami git les voit apparaitre dans son jardin, mais il se demande quoi en faire. Tout d'abord verifions qu'il les voit. Utilisons la commande status :

          #> git status
          #
          # Initial commit
          #
          #
          # Untracked files:
          #   (use "git add" to add to commit)
          #
          #       exemple
          #       hello
          nothing to commit
          #>
        

Reponse : oui il les voit. Ajoutons les et verifions avec git status.

          #> git add hello exemple
          #> git status
          #
          # Initial commit
          #
          #
          # Updated but no checked in:
          #   (will commit)
          #
          #      new file: exemple
          #      new file: hello
          #
          #>
        

Commit

Nous avons rajoute des fichiers. Commitons donc.

          #> git commit
        

Git lance alors votre editeur prefere et vous demande de bien vouloir taper un commentaire pour ce commit. L'option -m suivie d'un commentaire (court) peut remplacer ce lancement d'editeur. Tapez un commentaire : "premier commit", "le gant est jete", ...

          #> git commit
          Commiting initial tree b32fc....
        

Git vous a donc entendu et vous repond, bon c'est pas forcement intelligible sur la fin. La jolie chaine de caratere qui reside en fin du message est le resultat d'un hash SHA1 du ... commit. Pour vous c'est pas comprehensible, pour git, c'est indispensable.

Note

Ces hash, que vous allez voir regulierement sont les identifiants uniques de chaque objet geres par Git. Si vous connaissez md5, SHA1 n'est autre qu'un algo. Dans tous les cas il vous suffit de savoir que l'on ne peut pas avoir deux hash identiques pour des fichiers de contenu different. Un hash sha1 est un tres bon moyen d'obtenir un identifiant unique pour un fichier. Git n'est pas le seul a utiliser ce principe : Monotone fait de meme.

Voila c'est commite

Et sinon, je peux faire un diff ?

Bien sur Jacques, tu peux savoir ce que tu as modifie depuis le dernier commit. git status te dira les fichiers qui ont ete modifies, changes, ajoutes ou supprimes. git diff te dira ce qui s'est passe exactement.

Juste apres un commit, le status dira qu'il n'a rien a commiter. Logique. Donc modifions exemple. Rajoutons du texte. Et faisons un status apres.

          #> echo "ceci est une ligne de plus" >> exemple
          #> git status
          #
          # Changed but not updated:
          #  (use git-update-index to mark for commit)
          #
          #      modified: exemple
          #
          nothing to commit
        

Et oui il nous dit la meme chose : nothing to commit. Mais il nous dit aussi qu'il y a eu des changements mais que vous ne lui avez qu'il faut les prendre en compte. En effet, par defaut, git ne considere pas les modifications d'un fichier comme une inscription de facto sur la liste des fichiers a commiter. C'est peut etre discutable, ou peut etre pas. Dans le doute il s'abstient. Mieux vaut ne pas commiter des changements que d'en commiter alors que le developpeur ne veut pas les voir commiter pour le moment. C'est plus modulaire.

Mais qu'est ce qu'il raconte la avec sa commande ? Tres simple git stoque dans un fichier denome index la liste complete des fichiers et repertoires qu'il gere. Chaque fichier est jumele avec son hash sha1. Si le hash ne colle plus c'est qu'il a ete modifie. Donc qu'il y a des commit a faire. Bon, le git-update-index permet de specifier a git les fichiers qu'il faut commiter. Mettons donc l'index a jour pour ce fichier et faisons un status ensuite.

          #> git-update-index exemple
          #> git status
          ...
          # Updated but not checked in:
          #   (will commit)
          #
          #       modified: exemple
          #
        

On peut desormais commiter :

          #> git commit -m "modification du fichier exemple"
        

Tu nous a toujours pas montre le diff

Mince mais vous suivez ? Fichtre. Bon, d'accord. Le diff c'est bien, ca permet de faire des patches et de les envoyer aux gens. Remodifions notre fichier (et hello avec) et faisons donc un diff derriere.

          #> echo "pour jacques" >> exemple
          #> echo "es tu la ?" >> hello
          #> git diff
          # liste les differences dans tous les fichiers
          #> git diff -p
          # meme chose
          #> git diff exemple
          # seulement pour le fichier exemple
        

Plutot pratique, plutot complet. Pour obtenir un patch a mailer il suffit de rediriger la sortie standard vers un fichier (ou le programme mail pour les plus violents d'entre vous) :

        #> git diff > ~/mypatch.diff
        # ou
        #> git diff | mail milord
        

Marquons donc les deux fichiers pour le commit et faisons le commit.

          #> git-update-index exemple hello
          #> git commit -m "voila, le diff c'est fait"
        

Les ptis gateaux avec le the

Bien nous avons vu pas mal de choses mine de rien.

  • git-init-db : pour initialiser le depot.

  • git status : pour avoir un compte rendu simple de ce qui a ete fait. Fichiers modifies, ajoutes , supprimes, fichiers rajoutes dans la commit list ou non, il sait tout ou presque.

  • git add : ajouter un fichier ou un repertoire du depot.

  • git remove : supprimer un fichier ou un repertoire du depot.

  • git-update-index : ajouter un fichier dans la commit list.

  • git commit : commit les changements dans le depot.

  • git diff : affiche le diff d'un, plusieurs, ou de la totalite des fichiers modifies. La version de reference est le dernier commit fait avant les modifications , ie HEAD.

Vous savez desormais vous debrouiller tout seul pour faire les taches de base. Prochaine etape ? Utiliser les tags et les branches. Il est important de savoir s'en servir dans tout scm.

Bon ben voila, vous voyez c'etait pas si mechant, allez vous en reprendrez bien un bout ? Allez Jacques, je te vois baver d'ici.

Chapter 3. Git 103

Jesus, petit il l'etait deja


      

Ce chapitre couvre l'utilisation de branches et de tags, notions importantes que ce soit avec git ou d'autres scm qu'ils soient decentralises ou non.

L'autre pistonne la ...

L'une des raisons qui m'ont fait reflechir au fait de delaisser un scm centralise au profit d'un decentralise est la possibilite de pouvoir avoir tous les benefices d'un scm ou que je sois et quel que soit mon degre de connectivite a internet, ou plus generiquement au serveur hebergeant mes depots.

Subversion est un outil remarquable : pratique, puissant, efficace. Mais il a un defaut (a mon gout) : pour beneficier de ses avantages il faut etre connectable au serveur. Ayant recement pris de nouvelles habitudes et methodes de developpement je ne suis plus tout le temps connecte au serveur. Du coup je ne peux beneficier des avantages que donne un scm : commit, revert, update, etc ...

Darcs, monotone, git (et d'autres) le permettent, cela implique certaines methodes pour travailler avec des gens puisque le travail est beaucoup plus dans le style "autiste", "chacun dans son coin" mais je pense que c'est tout aussi valable que des methodes appliquees avec des scm centralisees. Ce sont des questions d'habitudes et d'organisations.

Parmis ces methodes et ces habitudes les branches et les tags prennent toute leur importance : ils vont permettre a chaque developpeur de structurer son code, et son developpement sans forcement a avoir a attendre les autres, tout en leur permettant a tous d'avoir un tronc de code commun.

Les tags vont permettre de "tagguer", marquer, avec un joli drapeau un etat particulier du tronc ou d'une branche. Les branches sont, un chti peu plus importantes en terme de methode : elles correspondent a la possibilite de maintenir en parallele plusieurs branches de developpement d'un meme projet.

Si Si il y avait un treizieme apotre ...

... meme qu'il etait noir et s'appellait Rufus.

Un tag est un "flag" sur le code a un moment precis : une release, l'arrivee d'un nouveau commiteur, des fleurs de Mme Michu, vos problemes de couple ... J'en passe. Cela permettra ensuite de s'en servir comme point de repere pour des git diff ou des creations de branches (par exemple). Nous verrons donc : creation d'un tag simple, d'un tag annote, d'un tag annote et signe via gpg (et ouai ca rigole pas), suppression d'un tag, utilisation d'un tag dans un diff.

Light Tag

Les tags simples ou 'light' servent a creer une simple marque d'avancement sur l'arbre. Vous avez fini de coder un bon morceau, vous avez commite le tout sur votre depot, mais vous voudriez marquer cet etat particulier avant d'aller plus loin, juste pour info. Une fois un tag de creer vous pourrez faire un diff entre ce tag et le HEAD ou un autre tag, une branche, ... etc.

Comment le faire ? (Jacques) Tres simple :

          #> git tag mon-premier-tag
        

Facile hein ? Vous pouvez continuer a coder tranquille, commiter autant que voulu, et lorsque la curiosite vous en prend faites un :

          #> git diff mon-premier-tag
        

(evidement mon-premier-tag est un texte choisi au hasard).

Note

Un light tag n'est rien de plus qu'une branche (sauf qu'il ne s'utilise pas de la meme facon), elle est simplement mise dans .git/refs/tags au lieu de l'appeller un 'head'.

Annotated tag

Voila qui est plus interessant me direz vous. Si si, c'est interessant. La commande git tag peut prendre une ou plusieurs des options suivantes :

  • -a : cree un annotated tag non signe

  • -s : cree un annotated tag signe en utilisant la clef gpg de l'adresse par defaut.

  • -u key-id : cree un annotated tag en utilisant la clef gpg dont l'id est passe.

  • -f tag : remplace le tag existant dont le nom est donne

  • -d tag : supprime le tag dont le nom est donne

  • -m msg : utilise le message donne comme commentaire au lieu de le demander apres

Ce qui nous interesse ici sont les options -a, -s et -u.

L'option -a permet de creer un annotated tag simple, les options -s et -u permettent de signer avec une clef gpg le tag cree. Pourquoi vouloir signer un tag ? (Henry) Comme je l'ai explique precedement les tags permettent de mettre des flags a des endroits precis du developpement, pour les besoins d'un ou plusieurs developpeurs ou de tous. Un tres bon exemple de ce dernier cas est la creation d'un tag pour marquer l'arbre lors d'une release. Les developpeurs decident que l'etat de l'arbre convient pour une release, le lead developer (par exemple) cree donc un tag dont le nom correspond a la release, le commente et le signe via sa clef gpg. Ainsi on est sur que c'est bien lui qui a marque le developpement a cet instant t correspondant a la release.

Il prit le pain et le rompit

Pourquoi je melange des histoires de Jesus et d'arbres ? (Jacques) Tu vas voir.

Le terme "arbre de commits" n'est pas innocent. En effet, en general les scm conservent les commits effectues sous la forme (plus ou moins virtuelle) d'un arbre. Le tronc de l'arbre est appelle trunk (generalement) sous svn, master (generalement) avec git. On peut tres bien, comme sur un vrai arbre (vous savez les trucs marrons avec plein de feuilles) avoir des branches qui decoulent de plus ou moins haut du tronc principal.

Oui Jacques, schematiquement c'est comme un vrai arbre. C'est fou hein ? Si tu savais qu'on utilise aussi des fourmis en informatique ... Si Si, mais la n'est pas le sujet.

Pour du code ca correspond a une separation du travail lorsque, par exemple, un developpeur souhaite essayer une implementation d'une fonctionnalite, ou une correction de bug, sans pour autant modifier le code du tronc principal et continuer a bosser sur celui ci. Il souhaite donc copier une premiere fois le code pour bosser sur le code du tronc a un moment donne. Il voudra pouvoir renvoyer du code de cette branche vers le tronc principal, du tronc principal vers cette branche si besoin. Une fois son boulot finit, ou si ses modifs sont ok il voudra supprimer la branche ou integrer les modifs dans le tronc principal (merge).

C'est tout cela que nous allons voir : creation d'une branche, ecriture de code dans la branche, dans le tronc, comparaison de l'une a l'autre, de l'autre a l'une, passage de code limite, merge complet, suppression de branche.

En quoi ca a un rapport avec Jesus ? (quelqu'un dans le fond) Ben heu, juste rompre le code et que le code c'est notre pain de tous les jours a nous developpeurs ... Vous comprenez pas ? Heu ben, pas grave tant que vous comprenez les branches et les tags, c'est le principal. Oui oui on vient a la pratique, ces jeunes ... toujours presses de passer a la pratique ...

Rompons donc, rompons

Creer une branche est relativement simple. Il suffit de faire un checkout :

          #> git checkout -b mabranche
        

Ce qui creera une branche en partant de l'etat actuel du HEAD. Il est aussi possible de creer une branche a partir d'un etat precedent identifie par un commit. Pour cela il suffit de preciser le SHA1 du commit.

          #> git checkout -b mabranche sha1-d-un-commit
        

Ce checkout va creer la branche et vous "placer" dedans, vous pouvez alors bosser sans craindre que ce que vous faites modifie quoi que ce soit dans la branche principale (appellee 'master' par defaut), ou toutes les autres branches.

Pour repasser au master ou a une autre branche il suffit de refaire un checkout, mais sans le -b :

          #> git checkout master
        

Si vous ne vous rappellez plus les noms exacts (ou toutes les branches que vous avez deja cree) il vous suffit d'utiliser la commande branch.

          #> git branch
        

La branche actuellemt "active" (sur laquelle vous travaillez) sera reperee avec un '*' dans la marge.

Et supposons que je veuille creer une branche avec l'etat de mon arbre a un moment donne sans pour autant tout de suite bosser dessus. Faire une sorte d'ajout dans ma todo list en y attachant la matiere premiere necessitee. Est ce possible ? (Hector)

Oui c'est prevu, pour cela il suffit d'utiliser la commande branch :

          #> git branch nomdebranche [pointdedepart]
        

Comme avec le checkout -b la precision du point de depart est optionnelle. Apres cette commande, une branche aura ete creee en utilisant l'etat du HEAD au point depart donne (ou l'actuel par defaut) mais l'environnement de travail ne sera pas deplace dans cette branche.

Et la les deux branches n'en refont qu'une

Nous allons voir le merge, mais plutot que de chercher a vous expliquer comment ca se passe nous allons pratiquer ... Je savais que ca allait vous plaire.

Le merge consiste a reinserer le code d'une branche dans une autre. Commencons par creer une branche et regardons tout de suite la liste des branches en utilisant la commande git branch :

          #> git checkout -b branche2
          #> git branch
          * branche2
            master
          #>
        

Nous avons donc cree une nouvelle branche et nous travaillons desormais dedans. Travaillons dans cette branche, ie modifions des fichiers puis commitons :

          #> echo "il faut bosser">>hello
          #> git commit -m "une modif" hello
        

(vous pouvez remarquer que j'ai zappe la commande git-update-index en passant directement a la commande commit le nom du fichier a inclure dans le commit.

Repassons dans le master et faisons de meme.

          #> git checkout master
          #> echo "je prefere jouer">>hello
          #> echo "un autre ?">>exemple
          #> git commit -m "testons" hello exemple
        

Nos deux branches sont donc dans un etat bien different l'une de l'autre. Comment allons nous faire ?

Le merge se fait via la commande merge en precisant les branches a merger entre elles.

          #> git merge "merge d'une branche" HEAD branche2
          Trying really trivial in-index merge...
          fatal: Merge requires file-level merging
          Nope.
          Merging HEAD with bfbfefa4d9116beff394ad29e2721b1ab6118df0
          Merging: 
          9633612e4fc1432a035b0208d8cb980172576e5c testons 
          bfbfefa4d9116beff394ad29e2721b1ab6118df0 une modif 
          found 1 common ancestor(s): 
          f6edb3e924cb2f06b5860fd52690c1d7d4e42c13 voila, le diff c'est fait 
          Auto-merging hello 
          CONFLICT (content): Merge conflict in hello 
          
          Automatic merge failed; fix up by hand
          #>
        

Decortiquons un peu ce qui s'est passe. Git a d'abord essaye de faire un merge trivial (simple) et comme il n'a pas marche il a essaye de faire un merge automatique. Ce dernier n'a pas marche non plus car il y a des conflits dans le fichier 'hello'. Il vous invite donc a les corriger a la main.

Et c'est tout ? On s'arrete la ?(Lucie)

Non non, ca arrive ca arrive. Editons donc le fichier en question. On va retouver un format connu de ceux utilisant cvs, svn, ...

        hello world
        es tu la
        <<<<<<< HEAD/hello
        je prefere jouer
        =======
        toto
        il faut bosser
        >>>>>>> bfbf....
        

Les chevrons vous indique a quel commit/branche appartient le morceau le suivant ou precedent (tout depend si on est au dessus ou en dessous de la ligne de signes '='). Nous allons garder les lignes "je prefere jouer" et "il faut bosser" (et donc supprimer les lignes avec les chevrons, les '=' et la ligne "toto").

        hello world
        es tu la
        je prefere jouer
        il faut bosser
        

Une fois cette modif faites enregistrez et quittez l'editeur puis commiter le tout.

          #> git commit -m "commit post merge" hello
        

Voila, vous savez tout.

Alors la marmotte tu vois ...

Nous avons couvert pas mal de commandes dans ce chapitre.

  • git tag un_nom : pour creer un tag simple

  • git -a/-s/-u : pour creer un annotated tag signe

  • git checkout -b mabranche : pour creer une branche et se placer dedans pour travailler

  • git checkout master : pour repasser dans la branche master

  • git branch : pour avoir une liste des branches existantes, et la branche active identifiee par '*'

  • git branch unebranche unpointdedepart : pour creer une branche a partir de unpointdedepart sans l'activer

  • git merge HEAD mabranche : pour merger deux la branche active avec mabranche

Ce qui conclut ce chapitre. Vous avez desormais de quoi couvrir la la quasi totalite de vos besoins si vous developpez seul dans votre coin. Ceci dit on developpe rarement seul dans son coin, c'est pourquoi le prochain chapitre abordera les notions et commandes necessaires au travail a plusieurs.

Chapter 4. Git 104

Faire commerce avec l'exterieur


        tuttt ttuuuttt (sonnerie de telephone)
        - Paul Harkeides, bonjour
        - Bonjour, ca serait pour de la farine
        - bien sur quelle quantite ?
        - hum, une demi tonne environ
        - ok, no probleme
        - vous avez un depot publique ou je puisse venir chercher ca ?
        - bien sur
      

Ce chapitre couvre la mise en place d'un depot publique, son utilisation et comment recuperer une copie d'un depot distant.

Git est un scm non centralise, a la difference des scm centralises tel que svn ou cvs (ou il faut avoir une connection possible avec le serveur pour pouvoir faire des commits, branches et tags) tout est faisable en local. C'est une des raisons pour laquelle Linus Torvalds a toujours prefere utiliser un scm decentralise plutot qu'un centralise. Certaines fonctionnalites l'ont meme fait choisir un produit proprietaire (BitKeeper), ce qui a longtemps fait les choux gras de differentes mailings listes, channels irc et sites web. 2005 a d'ailleurs ete une tres mauvaise annee pour ce genre de troll comme me le faisait remarquer un ami : YAST2 libre, le developpement de linux qui est desormais gere par un logiciel libre, ...

Mais comment on peut travailler avec les gens ? S'il n'y a pas de serveur central, comment on peut echanger du code entre developpeurs ? (Eric)

C'est un des points importants que nous n'aborderons pas tout de suite, je reserve ces notions pour le prochain chapitre. Ce chapitre ci sera essentiellement pratique, le suivant sera plus theorique.

Hello world, here is something for you

Avant toute chose il vous faut trouver une machine accessible par les gens. Que ce soit une cafetiere sous netbsd, un poweredgde sous openbsd ou un sunfire sous linux, peu importe. Il vous faut au moins SSHD dessus (et un compte evidement), git (si si je vous assure) et optionnellement http ou rsync.

Tout d'abord il vous faut avoir un acces correct sur le serveur en question. Par correct j'entend que vous pouvez soit creer des utilisateurs, soit modifier la configuration de l'apache ou du rsync. Au besoin demandez a votre gentil admin systeme de service.

Dans tous les cas il y a un certain nombre de taches que vous pouvez faire vous meme, seul. Creez a un endroit tranquille de votre serveur un repertoire astucieusement nomme "mon-git.git".

        #> mkdir mon-git.git
      

Bien. Maintenant initialisons le bigniou :

        #> GIT_DIR=mon-git.git git-init-db
      

Bien, maintenant il ne vous reste plus qu'a faire un push de votre depot local de developpement. Pour cela il faut utiliser la commande git push. Cette commande utilise ssh, vous devez avoir un acces en ecriture sur la machine via ssh.

        #> cd /mon/depot/detaff/
        #> git push lehost:/lechemin/du/depot/mon-git.git
      

Et hop ca synchronise. C'est fou.

Quand Jean veut que Jeanne puisse acceder a son depot

Eh ben oui les jeunes partagent des choses, beaucoup de choses. Pour cet article nous resterons au partage de code, la physique des fluides n'est pas un domaine couvert par ce document. Bien vous avez donc copie de la data (de la bonne data cela va sans dire) sur une machine a laquelle des gens de chez le Nain Ternet peuvent acceder d'une maniere pas tres propre (http) ou plus propre (ssh).

Hep, hep tiens v'la de la bonne stuff etranger !

Le http c'est simple, c'est rapide et tout, mais c'est anonyme. Enfin c'est bien l'anonymite, hein, surtout quand c'est juste pour laisser des gens se connecter juste pour lire votre data. Donc pour ca c'est tres bien, et il vous suffit d'avoir un serveur http pour le faire. Peut importe ce que c'est (tapez dans le libre quand meme : thttpd, lighttpd, apache, caudium, ...) tant que ca fait du http. Creez un host ou un alias ou simplement definissez le Document Index (ou similaire) sur le repertoire qui contient votre depot public. Et hop c'est bon les gens peuvent faire un clone sur http://mondomaine.dom/mon-git.git :

          #> git clone http://mondomaine.dom/mon-git.git
        

Et puis de temps en temps, lorsque vous faites des push vers votre depot publique, les gens ils peuvent alors mettre a jour leur copie chez eux. Pour cela deux commandes : git pull et git fetch (suivi de l'url du depot). Git pull va recuperer les mises a jours et merger celles ci avec votre branche principale. Cela peut parfois etre ennuyeux hein ;) C'est pour cela qu'il y a git fetch (ma phrase fait un peu reclame de produit d'entretien non ?). Cette derniere fait la meme chose que pull mais sans merger ce qui est recupere avec votre master a vous. Jeanne se sent mieux tout d'un coup on dirait.

Hep ! Messire ?! J'aurai quelques pillules pour vous !

Dans le meme genre de truc simple, juste pour faire du clone et du pull (et du fetch) dessus il y a un truc qui s'appelle git-daemon. C'est un daemon TCP tout bete qui ecoute (par defaut) sur le port 9418. Lorsqu'une connection est etabli il execute git-upload-pack et envoi donc la stuff au gen a l'autre bout de la connection. Bien que simple il est malin le bougre. Par exemple il verifie ce qu'on lui demande : si le gen au bout de la connection lui demande des choses qui vont pas bien ou qui ont pas de sens il les enverra bouler. Ca s'arrete pas la, en effet, pour qu'il accepte d'exporter un depot git il faudra que celui ci contienne un fichier ascutieusement nomme (je sais ca fait deux fois que je la fais celle la) git-daemon-export-ok.

Bon alors comment ca marche ? Pas bien dur :

          'git-daemon' [--verbose] [--syslog] [--inetd | --port=n]
            [--timeout=n] [--init-timeout=n][--strict-paths]
            [--base-path=path] [directory...]
        

  • --syslog : envoi les logs a syslog au lieu de stderr.

  • --verbose : log les details des connections entrantes et des fichiers demandes

  • --inetd : ajoute le serveur aux services geres par inetd

  • --timeout : timeout pour les requetes du client

  • --init-timeout : timeout entre le moment d'etablissement de la connection et la reception des commandes.

  • --port : le port a ecouter

  • --strict-paths : oblige le daemon a ne matcher que les ports exacts. ie : refuse "foo/repo" quand le depot est en realite foo/repo.git ou goo/repo/.git

  • --base-path : permet de definir un root relatif. ie : --base-path=/srv/git permettra d'acceder au depot /srv/git/hello.git via git://mondomaine.dom/hello.git.

  • directory : un repertoire a rajouter dans la liste blanche des repertoires authorises. Si --strict-paths n'est pas precise ca incluera aussi tout sous repertoire de chaque repertoire passe ainsi en option. Oui directory peut etre une liste.

  • --export-all : authorise les pulls sur tous les repertoires qui ressemblent a des depots git (s'ils ont des repertoires objects et refs) meme s'ils n'ont pas de fichier 'git-daemon-export-ok'.

Oui je sais, ca rox grave des ours capilotractes (Dreamgazer si tu me lis ...). Donc en gros pour mettre accessible au monde entier vos depots git situes dans le repertoire /var/depots il vous suffit d'un truc du genre :

          git-daemon --syslog --verbose --base-path=/var/depots 
        

Et la les gens chez le Nain Ternet ils peuvent recuperer vos depots via git://mondomaine.dom/undepot.git avec un clone puis des fetch ou des pull.

What does the H stand for in 'SSH' ?

Non mais c'est vrai c'est une bonne question, qu'est ce qu'il veut dire ? Habits ? Pour "Safe Sex Habits" ? (Arthur)

En ssh en fait c'est uber simple. Ca permet deja a vos gens de pouvoir aussi faire du push (ouai bon on va eviter hein) mais aussi de limiter le public qui a acces a vos depots. Ca peut etre pratique pour faire des trucs sales, mais ca peut surtout etre utilise par des developpeurs du bien lors des premieres phases de dev pendant que le code et le projet n'ont pas atteints une taille et un poids critique.

En pratique il suffit de creer un user pour chaque personne que vous voulez faire participer au dev. Creez un home etc... Generalement je laisse la personne se connecter en lui donnant un mot de passe temporaire ('toto'), et lui donnant ainsi la possibilite de changer celui ci en quelque chose de mieux. Une fois que c'est fait changer le shell du user en question en git-shell (avec le chemin absolu evidement). Ce binaire qui vient avec git permet de n'autoriser que deux commandes au gen : git-receive-pack et git-upload-pack. La premiere permet de faire des pushs vers ce depot publique, la deuxieme des clone/pull/fetch.

Pull, pull, mais ... mais, comment on fait ?

Une fois que vous avez un depot publique (ou semi publique) des gens peuvent y acceder. Pour cela il leur suffit de faire (la premiere fois seulement) :

        #> git clone user@monhost.mondomaine.dom:/chemin/vers/depot.git
      

Ce qui fera un checkout de votre depot. A partir de la ils ont un environnement de travail dans lequel ils vont pouvoir travailler.

Les fois suivantes ils auront simplement besoin de lancer la commande git fetch ou git pull en precisant l'url du depot voulu. git fetch recuperera les modifications sans ecraser le master sur lequel travaillait votre probable camarade. git pull recupera les modifications et les mergera avec le boulot qu'il a fait (enfin il essayera).

Je reviendrai plus longuement sur une facon de travailler avec un scm distribue dans un prochain chapitre.

Enl4rg3 your d3p0t !

Nous avons vu comment mettre en place un depot git publique. Le probleme c'est que ben, git utilise des objets, pleins de fichiers quoi. En quoi ca pose un probleme mesdames, mesdemoiselles, messieurs ?

Parce que beaucoup de fichiers ca veut dire plus genant a transporter sur certains protocoles comme le http ? (Jean)

Tout a fait, c'est pour ca que git dispose d'une commande qui permet de packager (en quelque sorte) les objets : git repack . Pour cela il suffit de se placer dans le repertoire qui contient le depot a traiter et faire :

        #> GIT_DIR=mon-depot.git git repack
      

Ce qui va faire le pack (jetez un oeil dans le repertoire git/objects/pack), compose de deux fichiers, l'un qui va contenir les objets et l'autre qui est un index permettant un acces aleatoire aux objets. Une fois ce pack fait, vous pouvez nettoyer un peu le depot grace a la commande git prune-packed qui supprimera les objets qui ont ete packaged.

        #> GIT_DIR=mon-depot.git git prune-packed
      

Eviter les urls ...

Afin d'eviter les URL a retenir il y a un bon pti truc a connaitre. Creez un repertoire remotes dans le repertoire .git a la racine de votre depot de travail. Et creez un fichier "monserveur" en y mettant une simple ligne du genre :

        URL: monhost.mondomaine.dom:/chemin/vers/depot
      

Desormais vous pourrez faire :

        #> git push monserveur
      

Et hop ! direct il saura ce que vous voulez dire, c'est fou. Ca marche aussi pour les fetch, pull, ...

Et c'est quoi ce bouton la ?

Comme nous le verrons dans un prochain chapitre il est deconseille a vos amis de faire un push vers votre depot publique. De preference demandez leur de vous demander de faire un pull ou un fetch de leur depot publique (ca fera un lecteur de plus pour cet article en plus). Vous travaillerez alors avec des branches , des merges, etc .. pour incorporer leurs travaux.

Donc au final c'est pas bien complique de mettre un depot publique en place, de preference utilisez ssh si vous avez besoin d'authentifier les gens et/ou de limiter l'acces au depot. Dans le cas ou c'est simplement pour permettre aux gens de clone/pull/fetch votre depot le git-daemon est parfait, un serveur http peut aussi convenir.

Vu le caractere faible en matiere grasse de ce chapitre je ne ferai pas un listing des commandes vues.