git magique - blynn/gitmagic/intl/fr/book.pdf · git magique ben lynn août 2007 préface...

50
Git Magique Ben Lynn Août 2007 Préface Git est un couteau suisse de la gestion de versions. Un outil de gestion de révi- sions multi-usage, pratique et fiable, dont la flexibilité en rend l’apprentissage pas si simple, sans parler de le maîtriser ! Comme Arthur C. Clarke le fait observer, toute technologie suffisamment avancée se confond avec la magie. C’est une approche intéressante pour Git : les débutants peuvent ignorer ses mécanismes internes et l’utiliser comme une baguette magique afin d’époustoufler les amis et rendre furieux les ennemis par ses fabuleuses capacités. Plutôt que de rentrer dans le détails, nous donnons des instructions pour obtenir tel ou tel effet. À force d’utilisation, petit à petit, vous comprendrez comment fonctionne chaque truc et comment composer vos propres recettes pour répondre à vos besoins. • Chinois (Simplifié) : par JunJie, Meng et JiangWei. • Française : par Alexandre Garel, Paul Gaborit et Nicolas Deram. Hébergé aussi chez itaapy. • Allemande : par Benjamin Bellee et Armin Stebich. Hébergé aussi sur le site web d’Armin. • Italien : par Mattia Rigotti. • Portugaise : par Leonardo Siqueira Rodrigues [version ODT]. • Russe: par Tikhon Tarnavsky, Mikhail Dymskov et d’autres. • Espagnole : par Rodrigo Toledo et Ariset Llerena Tapia. • Vietnamienne: par Trần Ngọc Quân. Hébergé aussi sur son site Web. • sur une seule page web : HTML nu, sans CSS ; • fichier PDF : version imprimable. 1

Upload: lenhan

Post on 10-Oct-2018

218 views

Category:

Documents


0 download

TRANSCRIPT

Git Magique

Ben Lynn

Aoucirct 2007

Preacuteface

Git est un couteau suisse de la gestion de versions Un outil de gestion de reacutevi-sions multi-usage pratique et fiable dont la flexibiliteacute en rend lrsquoapprentissagepas si simple sans parler de le maicirctriser

Comme Arthur C Clarke le fait observer toute technologie suffisammentavanceacutee se confond avec la magie Crsquoest une approche inteacuteressante pour Git les deacutebutants peuvent ignorer ses meacutecanismes internes et lrsquoutiliser comme unebaguette magique afin drsquoeacutepoustoufler les amis et rendre furieux les ennemis parses fabuleuses capaciteacutes

Plutocirct que de rentrer dans le deacutetails nous donnons des instructions pour obtenirtel ou tel effet Agrave force drsquoutilisation petit agrave petit vous comprendrez commentfonctionne chaque truc et comment composer vos propres recettes pour reacutepondreagrave vos besoins

bull Chinois (Simplifieacute) par JunJie Meng et JiangWei

bull Franccedilaise par Alexandre Garel Paul Gaborit et Nicolas Deram Heacutebergeacuteaussi chez itaapy

bull Allemande par Benjamin Bellee et Armin Stebich Heacutebergeacute aussi sur lesite web drsquoArmin

bull Italien par Mattia Rigotti

bull Portugaise par Leonardo Siqueira Rodrigues [version ODT]

bull Russe par Tikhon Tarnavsky Mikhail Dymskov et drsquoautres

bull Espagnole par Rodrigo Toledo et Ariset Llerena Tapia

bull Vietnamienne par Trần Ngọc Quacircn Heacutebergeacute aussi sur son site Web

bull sur une seule page web HTML nu sans CSS

bull fichier PDF version imprimable

1

bull package Debian package Ubuntu obtenez rapidement une copie localede ce site Pratique lorsque ce serveur est arrecircteacute

bull un vrai livre [Amazoncom] 64 pages 1524cm x 2286cm noir et blancen anglais Pratique en cas de panne courant

Merci

Je reste modeste devant le travail fourni par tant de monde pour traduire cespages Jrsquoappreacutecie beaucoup drsquoeacutelargir mon audience gracircce aux efforts des person-nes deacutejagrave citeacutees

Dustin Sallings Alberto Bertogli James Cameron Douglas LivingstoneMichael Budde Richard Albury Tarmigan Derek Mahar Frode AannevikKeith Rarick Andy Somerville Ralf Recker Oslashyvind A Holm Miklos VajnaSeacutebastien Hinderer Thomas Miedema Joe Malin et Tyler Breisacher ontcontribueacute aux corrections et aux ameacuteliorations

Franccedilois Marier maintient le paquet Debian creacuteeacute agrave lrsquoorigine par Daniel Baumarr

Ma gratitude va eacutegalement agrave beaucoup drsquoautres pour leurs encouragements etcompliments Je suis tenteacute de vous citer ici toutefois ceci risquerait de portervos attentes agrave des sommets ridicules

Si par erreur je vous ai oublieacute merci de me le signaler ou plus simplementenvoyez-moi un patch

bull httprepoorcz heacuteberge des projets libres Crsquoest le premier heacuteberge-ment Git fondeacute et maintenu par les premiers deacuteveloppeurs Git

bull httpgitoriousorg est un autre site drsquoheacutebergement Git fait pour lesprojets Open-Source

bull httpgithubcom heacuteberge des projets Open-Source gratuitement et desprojets priveacutes contre paiement

Un grand merci agrave ces sites pour lrsquoheacutebergement de ce guide

Licence

Ce guide est publieacute sous la GNU General Public License version 3 Bien eacutevide-ment les sources sont dans un deacutepocirct Git et peuvent ecirctre obtenues en saisissant

$ git clone gitrepoorczgitmagicgit Pour creacuteer le dossier gitmagic

ou agrave partir drsquoun des miroirs

$ git clone gitgithubcomblynngitmagicgit$ git clone gitgitoriousorggitmagicmainlinegit

2

Introduction

Je vais me servir drsquoune analogie pour preacutesenter la gestion de versions Reacutefeacuterez-vous agrave la page de wikipedia sur la gestion de versions pour une explication pluscenseacutee

Le travail comme un jeu

Jrsquoai joueacute agrave des jeux videacuteos presque toute ma vie Par contre je nrsquoai commenceacuteagrave utiliser des systegravemes de gestion de versions qursquoagrave lrsquoacircge adulte Je pense ne pasecirctre le seul dans ce cas et la comparaison entre les deux peut rendre les conceptsplus simples agrave expliquer et agrave comprendre

Pensez agrave lrsquoeacutedition de votre code ou de votre document comme srsquoil srsquoagissaitde jouer agrave un jeu Quand vous avez bien progresseacute vous aimeriez faire unesauvegarde Pour cela vous cliquez sur le bouton enregistrer de votre fidegraveleeacutediteur

Mais ceci va eacutecraser lrsquoancienne version Crsquoest comme ces anciens jeux quinrsquoavaient qursquoun emplacement oui vous pouviez faire une sauvegarde mais vousne pouviez pas revenir dans un eacutetat preacuteceacutedent Quel dommage vu que votresauvegarde preacuteceacutedente pouvait eacuteventuellement ecirctre situeacutee agrave un passage du jeuparticuliegraverement amusant sur lequel vous seriez bien revenu un de ces jours Ouencore pire votre seule sauvegarde eacutetait dans un eacutetat qui ne permettait pas degagner et vous deviez tout recommencer agrave zeacutero

Gestion de versions

Lorsque vous modifiez un document dans le but de conserver les anciennesversions vous pouvez lrsquordquoEnregistrer Soushelliprdquo un nom de fichier diffeacuterent ou lerecopier ailleurs avant de lrsquoenregistrer Vous pouvez mecircme compresser ces copiespour gagner de lrsquoespace Crsquoest une forme primitive et laborieuse de gestion deversions Les jeux videacuteo se sont ameacutelioreacutes sur ce point depuis longtemps puisquela plupart proposent diffeacuterents emplacements de sauvegarde automatiquementhorodateacutes

Rendons le problegraveme leacutegegraverement plus coriace Imaginez que vous ayez un en-semble de fichiers qui vont ensemble comme le code source drsquoun projet ou lesfichiers drsquoun site web Dans ce cas si vous voulez conserver une ancienne versionvous devez archiver le dossier en entier Conserver un grand nombre de versionsagrave la main nrsquoest pas pratique et devient rapidement fastidieux

Dans le cas de certains jeux videacuteo lrsquoenregistrement drsquoune partie est reacuteellementconstitueacute drsquoun dossier rempli de fichiers Ces jeux cachent ce deacutetail au joueur etpreacutesentent une interface adapteacutee pour geacuterer diffeacuterentes versions de ce dossier

3

Les systegravemes de gestion de versions ne font pas autre chose Ils offrent tous unebelle interface pour geacuterer un dossier rempli de plein de choses Vous pouvezenregistrer lrsquoeacutetat du dossier aussi souvent que vous voulez et plus tard vouspouvez recharger lrsquoun des eacutetats enregistreacutes Agrave la diffeacuterence de la plupart desjeux videacuteos ils sont geacuteneacuteralement habiles pour eacuteconomiser lrsquoespace neacutecessaireTypiquement seuls quelques fichiers changent drsquoune version agrave une autre et pasde beaucoup Stocker ces diffeacuterences au lieu des nouvelles copies complegraveteseacuteconomise de lrsquoespace

Gestion distribueacutee

Imaginez maintenant un jeu videacuteo tregraves difficile Si difficile agrave terminer que plein dejoueurs expeacuterimenteacutes de toute la planegravete deacutecident de faire eacutequipe et de partagerleurs parties enregistreacutees pour essayer drsquoen venir agrave bout Les Speedruns en sontun exemple concret des joueurs qui se speacutecialisent dans diffeacuterents niveaux dumecircme jeu collaborent pour produire des reacutesultats surprenants

Quel systegraveme mettriez-vous en place pour qursquoils puissent acceacuteder facilement auxsauvegardes des uns et des autres Et pour qursquoils puissent en teacuteleacuteverser denouvelles

Dans le passeacute tous les projets utilisaient une gestion de versions centraliseacuteeQuelque part un serveur contenait lrsquoensemble des sauvegardes du jeu et personnedrsquoautre Chaque joueur conservait au plus quelques sauvegardes de parties surleur machine Quand un joueur voulait progresser il teacuteleacutechargeait les derniegraveressauvegardes du serveur jouait un moment puis sauvegardait et teacuteleacuteversait sesnouvelles sauvegardes vers le serveur pour les mettre agrave disposition de tous lesautres

Qursquoen eacutetait-il si pour une raison quelconque des joueurs voulaient obtenir unepartie enregistreacutee anteacuterieurement Peut-ecirctre la sauvegarde actuelle de la partieeacutetait-elle dans un eacutetat sans possibiliteacute de victoire parce que quelqursquoun avaitoublieacute de prendre un objet au niveau trois et voulaient-ils retrouver la derniegraverepartie enregistreacutee au moment ougrave la partie pouvait encore ecirctre gagneacutee Ou peut-ecirctre souhaitaient-ils comparer deux parties enregistreacutees preacuteceacutedemment pour voirle travail reacutealiseacute par un joueur preacutecis

Il peut y avoir de nombreuses raisons de vouloir reacutecupeacuterer une ancienne versionmais le reacutesultat est le mecircme ils devaient demander au serveur central cettepartie preacuteceacutedemment sauvegardeacutee Et plus ils voulaient de parties sauvegardeacuteesplus ils devaient communiquer

La nouvelle geacuteneacuteration des systegravemes de gestion de versions dont Git fait partiesont dits systegravemes distribueacutes et peuvent ecirctre vus comme une geacuteneacuteralisation dessystegravemes centraliseacutes Quand les joueurs teacuteleacutechargent du serveur principal ilsobtiennent toutes les parties sauvegardeacutees pas uniquement la derniegravere Crsquoestcomme srsquoils faisaient un miroir du serveur central

4

Cette opeacuteration initiale de clonage peut ecirctre coucircteuse surtout srsquoil y a un long his-torique mais ccedila paie sur le long terme Un avantage immeacutediat est que lorsqursquoondeacutesire une partie enregistreacutee quelle qursquoen soit la raison aucune communicationavec le serveur central nrsquoest neacutecessaire

Une superstition idiote

Un croyance populaire veut que les systegravemes distribueacutes ne soient pas adapteacutesaux projets qui ont besoin drsquoun deacutepocirct central officiel Rien nrsquoest moins vraiPhotographier quelqursquoun nrsquoa jamais eu pour effet de voler son acircme De mecircmecloner le deacutepocirct principal ne diminue pas son importance

Une premiegravere approximation assez bonne est que tout ce qursquoun systegraveme central-iseacute de gestion de versions peut faire un systegraveme distribueacute bien conccedilu peut lefaire en mieux Les ressources reacuteseau sont simplement plus coucircteuses que lesressources locales Bien que nous verrons plus loin qursquoil peut y avoir quelquesinconveacutenients agrave lrsquoapproche distribueacutee il y a moins de risques de faire des com-paraisons erroneacutees en utilisant cette approximation

Un petit projet peut ne neacutecessiter qursquoune fraction des fonctionnaliteacutes offertespar un tel systegraveme mais utiliser un systegraveme qui nrsquoautorise pas les changementsdrsquoeacutechelle pour les petits projets crsquoest comme utiliser les chiffres romains pour lescalculs sur des petits nombres

De plus votre projet peut grossir au-delagrave de vos preacutevisions initiales UtiliserGit mecircme pour les cas simples est comparable au fait drsquoavoir sur soi un couteauSuisse que vous utilisez surtout pour deacuteboucher des bouteilles Le jour ougrave vousavez besoin drsquoun tournevis vous ecirctes content drsquoavoir plus qursquoun simple tire-bouchon

Conflits fusionnels

Pour aborder ce sujet notre analogie avec le jeu videacuteo serait trop tireacutee par lescheveux En revanche revenons au cas de lrsquoeacutedition drsquoun document

Imaginons que Alice insegravere une ligne au deacutebut drsquoun fichier et que Bob en ajouteune agrave la fin de sa propre copie Ils envoient tout les deux leurs modifications Laplupart des systegravemes vont automatiquement deacuteduire un traitement raisonnabledes actions accepter et fusionner leur modifications ainsi les modifications deAlice et de Bob sont appliqueacutees

Maintenant imaginez que Alice et Bob ont fait des modifications diffeacuterentes surla mecircme ligne Il devient alors impossible de proceacuteder sans intervention humaineCelui qui envoie ses modifications en second est informeacute drsquoun conflit de fusion(merge conflict) et doit choisir lrsquoune des deux versions de la ligne ou revoircomplegravetement cette ligne

5

Des situations plus complexes peuvent se preacutesenter Les systegravemes de gestion deversions srsquooccupent eux mecircme des cas les plus simples et laissent les cas difficilesaux humains Geacuteneacuteralement leur comportement est configurable

Astuces de base

Plutocirct que de plonger dans lrsquooceacutean des commandes Git utilisez ces commandeseacuteleacutementaires pour commencer en vous trempant les pieds Malgreacute leur simpliciteacutechacune drsquoelles est utile En effet lors de mon premier mois drsquoutilisation de Gitje ne me suis jamais aventureacute au-delagrave de ce qui est exposeacute dans ce chapitre

Enregistrer lrsquoeacutetat courant

Vous ecirctes sur le point drsquoeffectuer une opeacuteration drastique Avant de le fairereacutealisez une capture de tous les fichiers du dossier courant

$ git init$ git add $ git commit -m Ma premiegravere sauvegarde

Si jamais votre opeacuteration tourne mal vous pouvez retrouver votre version ini-tiale immaculeacutee

$ git reset --hard

Pour enregistrer un nouvel eacutetat

$ git commit -a -m Une autre sauvegarde

Ajouter supprimer renommer

Les commandes ci-dessus ne font que garder traces des fichiers qui eacutetaientpreacutesents lorsque vous avez executeacute git add pour la premiegravere fois Si vousajoutez de nouveaux fichiers ou sous-dossiers il faut le signaler agrave Git

$ git add readmetxt Documentation

De mecircme si vous voulez que Git oublie certains fichiers

$ git rm kludgeh obsoletec$ git rm -r incriminatingevidence

Git supprime les fichiers pour vous si vous ne lrsquoavez pas encore fait

Renommer un fichier revient agrave supprimer lrsquoancien nom et ajouter le nouveau Ily a eacutegalement le raccourci git mv qui a la mecircme syntaxe que la commande mvPar exemple

6

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

bull package Debian package Ubuntu obtenez rapidement une copie localede ce site Pratique lorsque ce serveur est arrecircteacute

bull un vrai livre [Amazoncom] 64 pages 1524cm x 2286cm noir et blancen anglais Pratique en cas de panne courant

Merci

Je reste modeste devant le travail fourni par tant de monde pour traduire cespages Jrsquoappreacutecie beaucoup drsquoeacutelargir mon audience gracircce aux efforts des person-nes deacutejagrave citeacutees

Dustin Sallings Alberto Bertogli James Cameron Douglas LivingstoneMichael Budde Richard Albury Tarmigan Derek Mahar Frode AannevikKeith Rarick Andy Somerville Ralf Recker Oslashyvind A Holm Miklos VajnaSeacutebastien Hinderer Thomas Miedema Joe Malin et Tyler Breisacher ontcontribueacute aux corrections et aux ameacuteliorations

Franccedilois Marier maintient le paquet Debian creacuteeacute agrave lrsquoorigine par Daniel Baumarr

Ma gratitude va eacutegalement agrave beaucoup drsquoautres pour leurs encouragements etcompliments Je suis tenteacute de vous citer ici toutefois ceci risquerait de portervos attentes agrave des sommets ridicules

Si par erreur je vous ai oublieacute merci de me le signaler ou plus simplementenvoyez-moi un patch

bull httprepoorcz heacuteberge des projets libres Crsquoest le premier heacuteberge-ment Git fondeacute et maintenu par les premiers deacuteveloppeurs Git

bull httpgitoriousorg est un autre site drsquoheacutebergement Git fait pour lesprojets Open-Source

bull httpgithubcom heacuteberge des projets Open-Source gratuitement et desprojets priveacutes contre paiement

Un grand merci agrave ces sites pour lrsquoheacutebergement de ce guide

Licence

Ce guide est publieacute sous la GNU General Public License version 3 Bien eacutevide-ment les sources sont dans un deacutepocirct Git et peuvent ecirctre obtenues en saisissant

$ git clone gitrepoorczgitmagicgit Pour creacuteer le dossier gitmagic

ou agrave partir drsquoun des miroirs

$ git clone gitgithubcomblynngitmagicgit$ git clone gitgitoriousorggitmagicmainlinegit

2

Introduction

Je vais me servir drsquoune analogie pour preacutesenter la gestion de versions Reacutefeacuterez-vous agrave la page de wikipedia sur la gestion de versions pour une explication pluscenseacutee

Le travail comme un jeu

Jrsquoai joueacute agrave des jeux videacuteos presque toute ma vie Par contre je nrsquoai commenceacuteagrave utiliser des systegravemes de gestion de versions qursquoagrave lrsquoacircge adulte Je pense ne pasecirctre le seul dans ce cas et la comparaison entre les deux peut rendre les conceptsplus simples agrave expliquer et agrave comprendre

Pensez agrave lrsquoeacutedition de votre code ou de votre document comme srsquoil srsquoagissaitde jouer agrave un jeu Quand vous avez bien progresseacute vous aimeriez faire unesauvegarde Pour cela vous cliquez sur le bouton enregistrer de votre fidegraveleeacutediteur

Mais ceci va eacutecraser lrsquoancienne version Crsquoest comme ces anciens jeux quinrsquoavaient qursquoun emplacement oui vous pouviez faire une sauvegarde mais vousne pouviez pas revenir dans un eacutetat preacuteceacutedent Quel dommage vu que votresauvegarde preacuteceacutedente pouvait eacuteventuellement ecirctre situeacutee agrave un passage du jeuparticuliegraverement amusant sur lequel vous seriez bien revenu un de ces jours Ouencore pire votre seule sauvegarde eacutetait dans un eacutetat qui ne permettait pas degagner et vous deviez tout recommencer agrave zeacutero

Gestion de versions

Lorsque vous modifiez un document dans le but de conserver les anciennesversions vous pouvez lrsquordquoEnregistrer Soushelliprdquo un nom de fichier diffeacuterent ou lerecopier ailleurs avant de lrsquoenregistrer Vous pouvez mecircme compresser ces copiespour gagner de lrsquoespace Crsquoest une forme primitive et laborieuse de gestion deversions Les jeux videacuteo se sont ameacutelioreacutes sur ce point depuis longtemps puisquela plupart proposent diffeacuterents emplacements de sauvegarde automatiquementhorodateacutes

Rendons le problegraveme leacutegegraverement plus coriace Imaginez que vous ayez un en-semble de fichiers qui vont ensemble comme le code source drsquoun projet ou lesfichiers drsquoun site web Dans ce cas si vous voulez conserver une ancienne versionvous devez archiver le dossier en entier Conserver un grand nombre de versionsagrave la main nrsquoest pas pratique et devient rapidement fastidieux

Dans le cas de certains jeux videacuteo lrsquoenregistrement drsquoune partie est reacuteellementconstitueacute drsquoun dossier rempli de fichiers Ces jeux cachent ce deacutetail au joueur etpreacutesentent une interface adapteacutee pour geacuterer diffeacuterentes versions de ce dossier

3

Les systegravemes de gestion de versions ne font pas autre chose Ils offrent tous unebelle interface pour geacuterer un dossier rempli de plein de choses Vous pouvezenregistrer lrsquoeacutetat du dossier aussi souvent que vous voulez et plus tard vouspouvez recharger lrsquoun des eacutetats enregistreacutes Agrave la diffeacuterence de la plupart desjeux videacuteos ils sont geacuteneacuteralement habiles pour eacuteconomiser lrsquoespace neacutecessaireTypiquement seuls quelques fichiers changent drsquoune version agrave une autre et pasde beaucoup Stocker ces diffeacuterences au lieu des nouvelles copies complegraveteseacuteconomise de lrsquoespace

Gestion distribueacutee

Imaginez maintenant un jeu videacuteo tregraves difficile Si difficile agrave terminer que plein dejoueurs expeacuterimenteacutes de toute la planegravete deacutecident de faire eacutequipe et de partagerleurs parties enregistreacutees pour essayer drsquoen venir agrave bout Les Speedruns en sontun exemple concret des joueurs qui se speacutecialisent dans diffeacuterents niveaux dumecircme jeu collaborent pour produire des reacutesultats surprenants

Quel systegraveme mettriez-vous en place pour qursquoils puissent acceacuteder facilement auxsauvegardes des uns et des autres Et pour qursquoils puissent en teacuteleacuteverser denouvelles

Dans le passeacute tous les projets utilisaient une gestion de versions centraliseacuteeQuelque part un serveur contenait lrsquoensemble des sauvegardes du jeu et personnedrsquoautre Chaque joueur conservait au plus quelques sauvegardes de parties surleur machine Quand un joueur voulait progresser il teacuteleacutechargeait les derniegraveressauvegardes du serveur jouait un moment puis sauvegardait et teacuteleacuteversait sesnouvelles sauvegardes vers le serveur pour les mettre agrave disposition de tous lesautres

Qursquoen eacutetait-il si pour une raison quelconque des joueurs voulaient obtenir unepartie enregistreacutee anteacuterieurement Peut-ecirctre la sauvegarde actuelle de la partieeacutetait-elle dans un eacutetat sans possibiliteacute de victoire parce que quelqursquoun avaitoublieacute de prendre un objet au niveau trois et voulaient-ils retrouver la derniegraverepartie enregistreacutee au moment ougrave la partie pouvait encore ecirctre gagneacutee Ou peut-ecirctre souhaitaient-ils comparer deux parties enregistreacutees preacuteceacutedemment pour voirle travail reacutealiseacute par un joueur preacutecis

Il peut y avoir de nombreuses raisons de vouloir reacutecupeacuterer une ancienne versionmais le reacutesultat est le mecircme ils devaient demander au serveur central cettepartie preacuteceacutedemment sauvegardeacutee Et plus ils voulaient de parties sauvegardeacuteesplus ils devaient communiquer

La nouvelle geacuteneacuteration des systegravemes de gestion de versions dont Git fait partiesont dits systegravemes distribueacutes et peuvent ecirctre vus comme une geacuteneacuteralisation dessystegravemes centraliseacutes Quand les joueurs teacuteleacutechargent du serveur principal ilsobtiennent toutes les parties sauvegardeacutees pas uniquement la derniegravere Crsquoestcomme srsquoils faisaient un miroir du serveur central

4

Cette opeacuteration initiale de clonage peut ecirctre coucircteuse surtout srsquoil y a un long his-torique mais ccedila paie sur le long terme Un avantage immeacutediat est que lorsqursquoondeacutesire une partie enregistreacutee quelle qursquoen soit la raison aucune communicationavec le serveur central nrsquoest neacutecessaire

Une superstition idiote

Un croyance populaire veut que les systegravemes distribueacutes ne soient pas adapteacutesaux projets qui ont besoin drsquoun deacutepocirct central officiel Rien nrsquoest moins vraiPhotographier quelqursquoun nrsquoa jamais eu pour effet de voler son acircme De mecircmecloner le deacutepocirct principal ne diminue pas son importance

Une premiegravere approximation assez bonne est que tout ce qursquoun systegraveme central-iseacute de gestion de versions peut faire un systegraveme distribueacute bien conccedilu peut lefaire en mieux Les ressources reacuteseau sont simplement plus coucircteuses que lesressources locales Bien que nous verrons plus loin qursquoil peut y avoir quelquesinconveacutenients agrave lrsquoapproche distribueacutee il y a moins de risques de faire des com-paraisons erroneacutees en utilisant cette approximation

Un petit projet peut ne neacutecessiter qursquoune fraction des fonctionnaliteacutes offertespar un tel systegraveme mais utiliser un systegraveme qui nrsquoautorise pas les changementsdrsquoeacutechelle pour les petits projets crsquoest comme utiliser les chiffres romains pour lescalculs sur des petits nombres

De plus votre projet peut grossir au-delagrave de vos preacutevisions initiales UtiliserGit mecircme pour les cas simples est comparable au fait drsquoavoir sur soi un couteauSuisse que vous utilisez surtout pour deacuteboucher des bouteilles Le jour ougrave vousavez besoin drsquoun tournevis vous ecirctes content drsquoavoir plus qursquoun simple tire-bouchon

Conflits fusionnels

Pour aborder ce sujet notre analogie avec le jeu videacuteo serait trop tireacutee par lescheveux En revanche revenons au cas de lrsquoeacutedition drsquoun document

Imaginons que Alice insegravere une ligne au deacutebut drsquoun fichier et que Bob en ajouteune agrave la fin de sa propre copie Ils envoient tout les deux leurs modifications Laplupart des systegravemes vont automatiquement deacuteduire un traitement raisonnabledes actions accepter et fusionner leur modifications ainsi les modifications deAlice et de Bob sont appliqueacutees

Maintenant imaginez que Alice et Bob ont fait des modifications diffeacuterentes surla mecircme ligne Il devient alors impossible de proceacuteder sans intervention humaineCelui qui envoie ses modifications en second est informeacute drsquoun conflit de fusion(merge conflict) et doit choisir lrsquoune des deux versions de la ligne ou revoircomplegravetement cette ligne

5

Des situations plus complexes peuvent se preacutesenter Les systegravemes de gestion deversions srsquooccupent eux mecircme des cas les plus simples et laissent les cas difficilesaux humains Geacuteneacuteralement leur comportement est configurable

Astuces de base

Plutocirct que de plonger dans lrsquooceacutean des commandes Git utilisez ces commandeseacuteleacutementaires pour commencer en vous trempant les pieds Malgreacute leur simpliciteacutechacune drsquoelles est utile En effet lors de mon premier mois drsquoutilisation de Gitje ne me suis jamais aventureacute au-delagrave de ce qui est exposeacute dans ce chapitre

Enregistrer lrsquoeacutetat courant

Vous ecirctes sur le point drsquoeffectuer une opeacuteration drastique Avant de le fairereacutealisez une capture de tous les fichiers du dossier courant

$ git init$ git add $ git commit -m Ma premiegravere sauvegarde

Si jamais votre opeacuteration tourne mal vous pouvez retrouver votre version ini-tiale immaculeacutee

$ git reset --hard

Pour enregistrer un nouvel eacutetat

$ git commit -a -m Une autre sauvegarde

Ajouter supprimer renommer

Les commandes ci-dessus ne font que garder traces des fichiers qui eacutetaientpreacutesents lorsque vous avez executeacute git add pour la premiegravere fois Si vousajoutez de nouveaux fichiers ou sous-dossiers il faut le signaler agrave Git

$ git add readmetxt Documentation

De mecircme si vous voulez que Git oublie certains fichiers

$ git rm kludgeh obsoletec$ git rm -r incriminatingevidence

Git supprime les fichiers pour vous si vous ne lrsquoavez pas encore fait

Renommer un fichier revient agrave supprimer lrsquoancien nom et ajouter le nouveau Ily a eacutegalement le raccourci git mv qui a la mecircme syntaxe que la commande mvPar exemple

6

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Introduction

Je vais me servir drsquoune analogie pour preacutesenter la gestion de versions Reacutefeacuterez-vous agrave la page de wikipedia sur la gestion de versions pour une explication pluscenseacutee

Le travail comme un jeu

Jrsquoai joueacute agrave des jeux videacuteos presque toute ma vie Par contre je nrsquoai commenceacuteagrave utiliser des systegravemes de gestion de versions qursquoagrave lrsquoacircge adulte Je pense ne pasecirctre le seul dans ce cas et la comparaison entre les deux peut rendre les conceptsplus simples agrave expliquer et agrave comprendre

Pensez agrave lrsquoeacutedition de votre code ou de votre document comme srsquoil srsquoagissaitde jouer agrave un jeu Quand vous avez bien progresseacute vous aimeriez faire unesauvegarde Pour cela vous cliquez sur le bouton enregistrer de votre fidegraveleeacutediteur

Mais ceci va eacutecraser lrsquoancienne version Crsquoest comme ces anciens jeux quinrsquoavaient qursquoun emplacement oui vous pouviez faire une sauvegarde mais vousne pouviez pas revenir dans un eacutetat preacuteceacutedent Quel dommage vu que votresauvegarde preacuteceacutedente pouvait eacuteventuellement ecirctre situeacutee agrave un passage du jeuparticuliegraverement amusant sur lequel vous seriez bien revenu un de ces jours Ouencore pire votre seule sauvegarde eacutetait dans un eacutetat qui ne permettait pas degagner et vous deviez tout recommencer agrave zeacutero

Gestion de versions

Lorsque vous modifiez un document dans le but de conserver les anciennesversions vous pouvez lrsquordquoEnregistrer Soushelliprdquo un nom de fichier diffeacuterent ou lerecopier ailleurs avant de lrsquoenregistrer Vous pouvez mecircme compresser ces copiespour gagner de lrsquoespace Crsquoest une forme primitive et laborieuse de gestion deversions Les jeux videacuteo se sont ameacutelioreacutes sur ce point depuis longtemps puisquela plupart proposent diffeacuterents emplacements de sauvegarde automatiquementhorodateacutes

Rendons le problegraveme leacutegegraverement plus coriace Imaginez que vous ayez un en-semble de fichiers qui vont ensemble comme le code source drsquoun projet ou lesfichiers drsquoun site web Dans ce cas si vous voulez conserver une ancienne versionvous devez archiver le dossier en entier Conserver un grand nombre de versionsagrave la main nrsquoest pas pratique et devient rapidement fastidieux

Dans le cas de certains jeux videacuteo lrsquoenregistrement drsquoune partie est reacuteellementconstitueacute drsquoun dossier rempli de fichiers Ces jeux cachent ce deacutetail au joueur etpreacutesentent une interface adapteacutee pour geacuterer diffeacuterentes versions de ce dossier

3

Les systegravemes de gestion de versions ne font pas autre chose Ils offrent tous unebelle interface pour geacuterer un dossier rempli de plein de choses Vous pouvezenregistrer lrsquoeacutetat du dossier aussi souvent que vous voulez et plus tard vouspouvez recharger lrsquoun des eacutetats enregistreacutes Agrave la diffeacuterence de la plupart desjeux videacuteos ils sont geacuteneacuteralement habiles pour eacuteconomiser lrsquoespace neacutecessaireTypiquement seuls quelques fichiers changent drsquoune version agrave une autre et pasde beaucoup Stocker ces diffeacuterences au lieu des nouvelles copies complegraveteseacuteconomise de lrsquoespace

Gestion distribueacutee

Imaginez maintenant un jeu videacuteo tregraves difficile Si difficile agrave terminer que plein dejoueurs expeacuterimenteacutes de toute la planegravete deacutecident de faire eacutequipe et de partagerleurs parties enregistreacutees pour essayer drsquoen venir agrave bout Les Speedruns en sontun exemple concret des joueurs qui se speacutecialisent dans diffeacuterents niveaux dumecircme jeu collaborent pour produire des reacutesultats surprenants

Quel systegraveme mettriez-vous en place pour qursquoils puissent acceacuteder facilement auxsauvegardes des uns et des autres Et pour qursquoils puissent en teacuteleacuteverser denouvelles

Dans le passeacute tous les projets utilisaient une gestion de versions centraliseacuteeQuelque part un serveur contenait lrsquoensemble des sauvegardes du jeu et personnedrsquoautre Chaque joueur conservait au plus quelques sauvegardes de parties surleur machine Quand un joueur voulait progresser il teacuteleacutechargeait les derniegraveressauvegardes du serveur jouait un moment puis sauvegardait et teacuteleacuteversait sesnouvelles sauvegardes vers le serveur pour les mettre agrave disposition de tous lesautres

Qursquoen eacutetait-il si pour une raison quelconque des joueurs voulaient obtenir unepartie enregistreacutee anteacuterieurement Peut-ecirctre la sauvegarde actuelle de la partieeacutetait-elle dans un eacutetat sans possibiliteacute de victoire parce que quelqursquoun avaitoublieacute de prendre un objet au niveau trois et voulaient-ils retrouver la derniegraverepartie enregistreacutee au moment ougrave la partie pouvait encore ecirctre gagneacutee Ou peut-ecirctre souhaitaient-ils comparer deux parties enregistreacutees preacuteceacutedemment pour voirle travail reacutealiseacute par un joueur preacutecis

Il peut y avoir de nombreuses raisons de vouloir reacutecupeacuterer une ancienne versionmais le reacutesultat est le mecircme ils devaient demander au serveur central cettepartie preacuteceacutedemment sauvegardeacutee Et plus ils voulaient de parties sauvegardeacuteesplus ils devaient communiquer

La nouvelle geacuteneacuteration des systegravemes de gestion de versions dont Git fait partiesont dits systegravemes distribueacutes et peuvent ecirctre vus comme une geacuteneacuteralisation dessystegravemes centraliseacutes Quand les joueurs teacuteleacutechargent du serveur principal ilsobtiennent toutes les parties sauvegardeacutees pas uniquement la derniegravere Crsquoestcomme srsquoils faisaient un miroir du serveur central

4

Cette opeacuteration initiale de clonage peut ecirctre coucircteuse surtout srsquoil y a un long his-torique mais ccedila paie sur le long terme Un avantage immeacutediat est que lorsqursquoondeacutesire une partie enregistreacutee quelle qursquoen soit la raison aucune communicationavec le serveur central nrsquoest neacutecessaire

Une superstition idiote

Un croyance populaire veut que les systegravemes distribueacutes ne soient pas adapteacutesaux projets qui ont besoin drsquoun deacutepocirct central officiel Rien nrsquoest moins vraiPhotographier quelqursquoun nrsquoa jamais eu pour effet de voler son acircme De mecircmecloner le deacutepocirct principal ne diminue pas son importance

Une premiegravere approximation assez bonne est que tout ce qursquoun systegraveme central-iseacute de gestion de versions peut faire un systegraveme distribueacute bien conccedilu peut lefaire en mieux Les ressources reacuteseau sont simplement plus coucircteuses que lesressources locales Bien que nous verrons plus loin qursquoil peut y avoir quelquesinconveacutenients agrave lrsquoapproche distribueacutee il y a moins de risques de faire des com-paraisons erroneacutees en utilisant cette approximation

Un petit projet peut ne neacutecessiter qursquoune fraction des fonctionnaliteacutes offertespar un tel systegraveme mais utiliser un systegraveme qui nrsquoautorise pas les changementsdrsquoeacutechelle pour les petits projets crsquoest comme utiliser les chiffres romains pour lescalculs sur des petits nombres

De plus votre projet peut grossir au-delagrave de vos preacutevisions initiales UtiliserGit mecircme pour les cas simples est comparable au fait drsquoavoir sur soi un couteauSuisse que vous utilisez surtout pour deacuteboucher des bouteilles Le jour ougrave vousavez besoin drsquoun tournevis vous ecirctes content drsquoavoir plus qursquoun simple tire-bouchon

Conflits fusionnels

Pour aborder ce sujet notre analogie avec le jeu videacuteo serait trop tireacutee par lescheveux En revanche revenons au cas de lrsquoeacutedition drsquoun document

Imaginons que Alice insegravere une ligne au deacutebut drsquoun fichier et que Bob en ajouteune agrave la fin de sa propre copie Ils envoient tout les deux leurs modifications Laplupart des systegravemes vont automatiquement deacuteduire un traitement raisonnabledes actions accepter et fusionner leur modifications ainsi les modifications deAlice et de Bob sont appliqueacutees

Maintenant imaginez que Alice et Bob ont fait des modifications diffeacuterentes surla mecircme ligne Il devient alors impossible de proceacuteder sans intervention humaineCelui qui envoie ses modifications en second est informeacute drsquoun conflit de fusion(merge conflict) et doit choisir lrsquoune des deux versions de la ligne ou revoircomplegravetement cette ligne

5

Des situations plus complexes peuvent se preacutesenter Les systegravemes de gestion deversions srsquooccupent eux mecircme des cas les plus simples et laissent les cas difficilesaux humains Geacuteneacuteralement leur comportement est configurable

Astuces de base

Plutocirct que de plonger dans lrsquooceacutean des commandes Git utilisez ces commandeseacuteleacutementaires pour commencer en vous trempant les pieds Malgreacute leur simpliciteacutechacune drsquoelles est utile En effet lors de mon premier mois drsquoutilisation de Gitje ne me suis jamais aventureacute au-delagrave de ce qui est exposeacute dans ce chapitre

Enregistrer lrsquoeacutetat courant

Vous ecirctes sur le point drsquoeffectuer une opeacuteration drastique Avant de le fairereacutealisez une capture de tous les fichiers du dossier courant

$ git init$ git add $ git commit -m Ma premiegravere sauvegarde

Si jamais votre opeacuteration tourne mal vous pouvez retrouver votre version ini-tiale immaculeacutee

$ git reset --hard

Pour enregistrer un nouvel eacutetat

$ git commit -a -m Une autre sauvegarde

Ajouter supprimer renommer

Les commandes ci-dessus ne font que garder traces des fichiers qui eacutetaientpreacutesents lorsque vous avez executeacute git add pour la premiegravere fois Si vousajoutez de nouveaux fichiers ou sous-dossiers il faut le signaler agrave Git

$ git add readmetxt Documentation

De mecircme si vous voulez que Git oublie certains fichiers

$ git rm kludgeh obsoletec$ git rm -r incriminatingevidence

Git supprime les fichiers pour vous si vous ne lrsquoavez pas encore fait

Renommer un fichier revient agrave supprimer lrsquoancien nom et ajouter le nouveau Ily a eacutegalement le raccourci git mv qui a la mecircme syntaxe que la commande mvPar exemple

6

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Les systegravemes de gestion de versions ne font pas autre chose Ils offrent tous unebelle interface pour geacuterer un dossier rempli de plein de choses Vous pouvezenregistrer lrsquoeacutetat du dossier aussi souvent que vous voulez et plus tard vouspouvez recharger lrsquoun des eacutetats enregistreacutes Agrave la diffeacuterence de la plupart desjeux videacuteos ils sont geacuteneacuteralement habiles pour eacuteconomiser lrsquoespace neacutecessaireTypiquement seuls quelques fichiers changent drsquoune version agrave une autre et pasde beaucoup Stocker ces diffeacuterences au lieu des nouvelles copies complegraveteseacuteconomise de lrsquoespace

Gestion distribueacutee

Imaginez maintenant un jeu videacuteo tregraves difficile Si difficile agrave terminer que plein dejoueurs expeacuterimenteacutes de toute la planegravete deacutecident de faire eacutequipe et de partagerleurs parties enregistreacutees pour essayer drsquoen venir agrave bout Les Speedruns en sontun exemple concret des joueurs qui se speacutecialisent dans diffeacuterents niveaux dumecircme jeu collaborent pour produire des reacutesultats surprenants

Quel systegraveme mettriez-vous en place pour qursquoils puissent acceacuteder facilement auxsauvegardes des uns et des autres Et pour qursquoils puissent en teacuteleacuteverser denouvelles

Dans le passeacute tous les projets utilisaient une gestion de versions centraliseacuteeQuelque part un serveur contenait lrsquoensemble des sauvegardes du jeu et personnedrsquoautre Chaque joueur conservait au plus quelques sauvegardes de parties surleur machine Quand un joueur voulait progresser il teacuteleacutechargeait les derniegraveressauvegardes du serveur jouait un moment puis sauvegardait et teacuteleacuteversait sesnouvelles sauvegardes vers le serveur pour les mettre agrave disposition de tous lesautres

Qursquoen eacutetait-il si pour une raison quelconque des joueurs voulaient obtenir unepartie enregistreacutee anteacuterieurement Peut-ecirctre la sauvegarde actuelle de la partieeacutetait-elle dans un eacutetat sans possibiliteacute de victoire parce que quelqursquoun avaitoublieacute de prendre un objet au niveau trois et voulaient-ils retrouver la derniegraverepartie enregistreacutee au moment ougrave la partie pouvait encore ecirctre gagneacutee Ou peut-ecirctre souhaitaient-ils comparer deux parties enregistreacutees preacuteceacutedemment pour voirle travail reacutealiseacute par un joueur preacutecis

Il peut y avoir de nombreuses raisons de vouloir reacutecupeacuterer une ancienne versionmais le reacutesultat est le mecircme ils devaient demander au serveur central cettepartie preacuteceacutedemment sauvegardeacutee Et plus ils voulaient de parties sauvegardeacuteesplus ils devaient communiquer

La nouvelle geacuteneacuteration des systegravemes de gestion de versions dont Git fait partiesont dits systegravemes distribueacutes et peuvent ecirctre vus comme une geacuteneacuteralisation dessystegravemes centraliseacutes Quand les joueurs teacuteleacutechargent du serveur principal ilsobtiennent toutes les parties sauvegardeacutees pas uniquement la derniegravere Crsquoestcomme srsquoils faisaient un miroir du serveur central

4

Cette opeacuteration initiale de clonage peut ecirctre coucircteuse surtout srsquoil y a un long his-torique mais ccedila paie sur le long terme Un avantage immeacutediat est que lorsqursquoondeacutesire une partie enregistreacutee quelle qursquoen soit la raison aucune communicationavec le serveur central nrsquoest neacutecessaire

Une superstition idiote

Un croyance populaire veut que les systegravemes distribueacutes ne soient pas adapteacutesaux projets qui ont besoin drsquoun deacutepocirct central officiel Rien nrsquoest moins vraiPhotographier quelqursquoun nrsquoa jamais eu pour effet de voler son acircme De mecircmecloner le deacutepocirct principal ne diminue pas son importance

Une premiegravere approximation assez bonne est que tout ce qursquoun systegraveme central-iseacute de gestion de versions peut faire un systegraveme distribueacute bien conccedilu peut lefaire en mieux Les ressources reacuteseau sont simplement plus coucircteuses que lesressources locales Bien que nous verrons plus loin qursquoil peut y avoir quelquesinconveacutenients agrave lrsquoapproche distribueacutee il y a moins de risques de faire des com-paraisons erroneacutees en utilisant cette approximation

Un petit projet peut ne neacutecessiter qursquoune fraction des fonctionnaliteacutes offertespar un tel systegraveme mais utiliser un systegraveme qui nrsquoautorise pas les changementsdrsquoeacutechelle pour les petits projets crsquoest comme utiliser les chiffres romains pour lescalculs sur des petits nombres

De plus votre projet peut grossir au-delagrave de vos preacutevisions initiales UtiliserGit mecircme pour les cas simples est comparable au fait drsquoavoir sur soi un couteauSuisse que vous utilisez surtout pour deacuteboucher des bouteilles Le jour ougrave vousavez besoin drsquoun tournevis vous ecirctes content drsquoavoir plus qursquoun simple tire-bouchon

Conflits fusionnels

Pour aborder ce sujet notre analogie avec le jeu videacuteo serait trop tireacutee par lescheveux En revanche revenons au cas de lrsquoeacutedition drsquoun document

Imaginons que Alice insegravere une ligne au deacutebut drsquoun fichier et que Bob en ajouteune agrave la fin de sa propre copie Ils envoient tout les deux leurs modifications Laplupart des systegravemes vont automatiquement deacuteduire un traitement raisonnabledes actions accepter et fusionner leur modifications ainsi les modifications deAlice et de Bob sont appliqueacutees

Maintenant imaginez que Alice et Bob ont fait des modifications diffeacuterentes surla mecircme ligne Il devient alors impossible de proceacuteder sans intervention humaineCelui qui envoie ses modifications en second est informeacute drsquoun conflit de fusion(merge conflict) et doit choisir lrsquoune des deux versions de la ligne ou revoircomplegravetement cette ligne

5

Des situations plus complexes peuvent se preacutesenter Les systegravemes de gestion deversions srsquooccupent eux mecircme des cas les plus simples et laissent les cas difficilesaux humains Geacuteneacuteralement leur comportement est configurable

Astuces de base

Plutocirct que de plonger dans lrsquooceacutean des commandes Git utilisez ces commandeseacuteleacutementaires pour commencer en vous trempant les pieds Malgreacute leur simpliciteacutechacune drsquoelles est utile En effet lors de mon premier mois drsquoutilisation de Gitje ne me suis jamais aventureacute au-delagrave de ce qui est exposeacute dans ce chapitre

Enregistrer lrsquoeacutetat courant

Vous ecirctes sur le point drsquoeffectuer une opeacuteration drastique Avant de le fairereacutealisez une capture de tous les fichiers du dossier courant

$ git init$ git add $ git commit -m Ma premiegravere sauvegarde

Si jamais votre opeacuteration tourne mal vous pouvez retrouver votre version ini-tiale immaculeacutee

$ git reset --hard

Pour enregistrer un nouvel eacutetat

$ git commit -a -m Une autre sauvegarde

Ajouter supprimer renommer

Les commandes ci-dessus ne font que garder traces des fichiers qui eacutetaientpreacutesents lorsque vous avez executeacute git add pour la premiegravere fois Si vousajoutez de nouveaux fichiers ou sous-dossiers il faut le signaler agrave Git

$ git add readmetxt Documentation

De mecircme si vous voulez que Git oublie certains fichiers

$ git rm kludgeh obsoletec$ git rm -r incriminatingevidence

Git supprime les fichiers pour vous si vous ne lrsquoavez pas encore fait

Renommer un fichier revient agrave supprimer lrsquoancien nom et ajouter le nouveau Ily a eacutegalement le raccourci git mv qui a la mecircme syntaxe que la commande mvPar exemple

6

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Cette opeacuteration initiale de clonage peut ecirctre coucircteuse surtout srsquoil y a un long his-torique mais ccedila paie sur le long terme Un avantage immeacutediat est que lorsqursquoondeacutesire une partie enregistreacutee quelle qursquoen soit la raison aucune communicationavec le serveur central nrsquoest neacutecessaire

Une superstition idiote

Un croyance populaire veut que les systegravemes distribueacutes ne soient pas adapteacutesaux projets qui ont besoin drsquoun deacutepocirct central officiel Rien nrsquoest moins vraiPhotographier quelqursquoun nrsquoa jamais eu pour effet de voler son acircme De mecircmecloner le deacutepocirct principal ne diminue pas son importance

Une premiegravere approximation assez bonne est que tout ce qursquoun systegraveme central-iseacute de gestion de versions peut faire un systegraveme distribueacute bien conccedilu peut lefaire en mieux Les ressources reacuteseau sont simplement plus coucircteuses que lesressources locales Bien que nous verrons plus loin qursquoil peut y avoir quelquesinconveacutenients agrave lrsquoapproche distribueacutee il y a moins de risques de faire des com-paraisons erroneacutees en utilisant cette approximation

Un petit projet peut ne neacutecessiter qursquoune fraction des fonctionnaliteacutes offertespar un tel systegraveme mais utiliser un systegraveme qui nrsquoautorise pas les changementsdrsquoeacutechelle pour les petits projets crsquoest comme utiliser les chiffres romains pour lescalculs sur des petits nombres

De plus votre projet peut grossir au-delagrave de vos preacutevisions initiales UtiliserGit mecircme pour les cas simples est comparable au fait drsquoavoir sur soi un couteauSuisse que vous utilisez surtout pour deacuteboucher des bouteilles Le jour ougrave vousavez besoin drsquoun tournevis vous ecirctes content drsquoavoir plus qursquoun simple tire-bouchon

Conflits fusionnels

Pour aborder ce sujet notre analogie avec le jeu videacuteo serait trop tireacutee par lescheveux En revanche revenons au cas de lrsquoeacutedition drsquoun document

Imaginons que Alice insegravere une ligne au deacutebut drsquoun fichier et que Bob en ajouteune agrave la fin de sa propre copie Ils envoient tout les deux leurs modifications Laplupart des systegravemes vont automatiquement deacuteduire un traitement raisonnabledes actions accepter et fusionner leur modifications ainsi les modifications deAlice et de Bob sont appliqueacutees

Maintenant imaginez que Alice et Bob ont fait des modifications diffeacuterentes surla mecircme ligne Il devient alors impossible de proceacuteder sans intervention humaineCelui qui envoie ses modifications en second est informeacute drsquoun conflit de fusion(merge conflict) et doit choisir lrsquoune des deux versions de la ligne ou revoircomplegravetement cette ligne

5

Des situations plus complexes peuvent se preacutesenter Les systegravemes de gestion deversions srsquooccupent eux mecircme des cas les plus simples et laissent les cas difficilesaux humains Geacuteneacuteralement leur comportement est configurable

Astuces de base

Plutocirct que de plonger dans lrsquooceacutean des commandes Git utilisez ces commandeseacuteleacutementaires pour commencer en vous trempant les pieds Malgreacute leur simpliciteacutechacune drsquoelles est utile En effet lors de mon premier mois drsquoutilisation de Gitje ne me suis jamais aventureacute au-delagrave de ce qui est exposeacute dans ce chapitre

Enregistrer lrsquoeacutetat courant

Vous ecirctes sur le point drsquoeffectuer une opeacuteration drastique Avant de le fairereacutealisez une capture de tous les fichiers du dossier courant

$ git init$ git add $ git commit -m Ma premiegravere sauvegarde

Si jamais votre opeacuteration tourne mal vous pouvez retrouver votre version ini-tiale immaculeacutee

$ git reset --hard

Pour enregistrer un nouvel eacutetat

$ git commit -a -m Une autre sauvegarde

Ajouter supprimer renommer

Les commandes ci-dessus ne font que garder traces des fichiers qui eacutetaientpreacutesents lorsque vous avez executeacute git add pour la premiegravere fois Si vousajoutez de nouveaux fichiers ou sous-dossiers il faut le signaler agrave Git

$ git add readmetxt Documentation

De mecircme si vous voulez que Git oublie certains fichiers

$ git rm kludgeh obsoletec$ git rm -r incriminatingevidence

Git supprime les fichiers pour vous si vous ne lrsquoavez pas encore fait

Renommer un fichier revient agrave supprimer lrsquoancien nom et ajouter le nouveau Ily a eacutegalement le raccourci git mv qui a la mecircme syntaxe que la commande mvPar exemple

6

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Des situations plus complexes peuvent se preacutesenter Les systegravemes de gestion deversions srsquooccupent eux mecircme des cas les plus simples et laissent les cas difficilesaux humains Geacuteneacuteralement leur comportement est configurable

Astuces de base

Plutocirct que de plonger dans lrsquooceacutean des commandes Git utilisez ces commandeseacuteleacutementaires pour commencer en vous trempant les pieds Malgreacute leur simpliciteacutechacune drsquoelles est utile En effet lors de mon premier mois drsquoutilisation de Gitje ne me suis jamais aventureacute au-delagrave de ce qui est exposeacute dans ce chapitre

Enregistrer lrsquoeacutetat courant

Vous ecirctes sur le point drsquoeffectuer une opeacuteration drastique Avant de le fairereacutealisez une capture de tous les fichiers du dossier courant

$ git init$ git add $ git commit -m Ma premiegravere sauvegarde

Si jamais votre opeacuteration tourne mal vous pouvez retrouver votre version ini-tiale immaculeacutee

$ git reset --hard

Pour enregistrer un nouvel eacutetat

$ git commit -a -m Une autre sauvegarde

Ajouter supprimer renommer

Les commandes ci-dessus ne font que garder traces des fichiers qui eacutetaientpreacutesents lorsque vous avez executeacute git add pour la premiegravere fois Si vousajoutez de nouveaux fichiers ou sous-dossiers il faut le signaler agrave Git

$ git add readmetxt Documentation

De mecircme si vous voulez que Git oublie certains fichiers

$ git rm kludgeh obsoletec$ git rm -r incriminatingevidence

Git supprime les fichiers pour vous si vous ne lrsquoavez pas encore fait

Renommer un fichier revient agrave supprimer lrsquoancien nom et ajouter le nouveau Ily a eacutegalement le raccourci git mv qui a la mecircme syntaxe que la commande mvPar exemple

6

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git mv bugc featurec

AnnulerReprendre avanceacute

Parfois vous voulez seulement revenir en arriegravere et oublier les modificationseffectueacutees depuis un certain temps parce qursquoelles sont toutes fausses Dans cecas

$ git log

vous montre une liste des commits reacutecents accompagneacutes de leur empreinteSHA1

commit 766f9881690d240ba334153047649b8b8f11c664Author Bob ltbobexamplecomgtDate Tue Mar 14 015926 2000 -0800

Remplacement de prinf() par write()

commit 82f5ea346a2e651544956a8653c0f58dc151275cAuthor Alice ltaliceexamplecomgtDate Thu Jan 1 000000 1970 +0000

Commit initial

Les premiers caractegraveres de lrsquoempreinte sont suffisants pour speacutecifier un commit ou alors copiez et collez lrsquoempreinte en entier Saisissez

$ git reset --hard 766f

pour restaurer lrsquoeacutetat correspondant au commit donneacute et supprimer de maniegraverepermanente tous les commits plus reacutecents de lrsquoenregistrement

Parfois vous ne voulez faire qursquoun bref saut dans un eacutetat preacuteceacutedent Dans cecas saisissez

$ git checkout 82f5

Ceci vous ramegravene en arriegravere dans le temps tout en conservant les commitsreacutecents Toutefois comme pour le voyage temporel de la science-fiction si vousfaites des modifications suivies drsquoun commit vous entrerez dans une reacutealiteacuteparallegravele puisque vos actions sont diffeacuterentes de ce qursquoelles eacutetaient la premiegraverefois

Cette reacutealiteacute parallegravele est appeleacutee une branche (branch) et nous en dirons plusapregraves Pour le moment rappelez-vous simplement que

$ git checkout master

vous ramegravenera dans le preacutesent De plus pour eacuteviter que Git se plaigne reacutealiseztoujours un commit ou un reset de vos modifications avant de faire un checkout

7

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Pour reprendre lrsquoanalogie du jeu videacuteo

bull git reset --hard recharge une ancienne sauvegarde et supprime toutesles sauvegardes plus reacutecentes

bull git checkout recharge une ancienne partie mais si vous jouez aveclrsquoeacutetat de la partie va diffeacuterer des enregistrement suivants que vous aviezreacutealiseacutes la premiegravere fois Chaque nouvelle sauvegarde sera sur une brancheseacutepareacutee repreacutesentant la reacutealiteacute parallegravele dans laquelle vous ecirctes entreacute Onsrsquoen occupe plus loin

Vous pouvez choisir de ne restaurer que certains fichiers et sous-dossiers en lesnommant agrave la suite de la commande

$ git checkout 82f5 unfichier un-autrefichier

Faites attention car cette forme de checkout peut eacutecraser vos fichiers sans aver-tissement Pour eacuteviter les accidents faites un commit avant toute commandecheckout surtout quand vous deacutebutez avec Git En geacuteneacuteral quand vous nrsquoecirctespas sucircr des conseacutequences drsquoune opeacuteration et pas seulement des commandes Gitfaites drsquoabord un git commit -a

Vous nrsquoaimez pas copier et coller les empreintes Alors utilisez

$ git checkout Ma premiegravere s

pour arriver sur le commit qui commence avec ce message Vous pouvez aussidemander la cinquiegraveme sauvegarde en arriegravere

$ git checkout master~5

Reprise (revert)

Dans une cour de justice certains eacutevegravenements peuvent ecirctre effaceacutes du procegravesverbal De mecircme vous pouvez seacutelectionner des commits speacutecifiques agrave deacutefaire

$ git commit -a$ git revert 1b6d

deacutefera le dernier commit ayant cette empreinte La reprise est enregistreacutee commeun nouveau commit ce que vous pourrez constater en lanccedilant un git log

Geacuteneacuteration du journal des modifications (changelog)

Certains projets demandent un changelog Creacuteez-le en tapant

$ git log gt ChangeLog

8

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Teacuteleacutecharger des fichiers

Faites une copie drsquoun projet geacutereacute par Git en saisissant

$ git clone gitserveurcheminverslesfichiers

Par exemple pour reacutecupeacuterer les fichiers utiliseacutes pour creacuteer ce site

$ git clone gitgitorczgitmagicgit

Nous aurons beaucoup agrave dire sur la commande clone drsquoici peu

Le dernier cri

Si vous avez deacutejagrave teacuteleacutechargeacute une copie drsquoun projet en utilisant git clone vouspouvez la mettre agrave jour vers la derniegravere version avec

$ git pull

Publication instantaneacutee

Imaginez que vous avez eacutecrit un script que vous voudriez partager avec drsquoautresVous pourriez leur dire de le teacuteleacutecharger de votre ordinateur mais srsquoils le fontau moment ougrave vous ecirctes en train drsquoameacuteliorer le script ou drsquoy effectuer desmodifications expeacuterimentales ils peuvent se retrouver dans la panade Biensucircr crsquoest pour cela qursquoon a creacuteeacute la publication de versions successives Lesdeacuteveloppeurs peuvent travailler sur un projet freacutequemment mais ils ne rendentle code disponible quand lorsqursquoils le trouvent preacutesentable

Pour faire ccedila avec Git dans le dossier qui contient votre script

$ git init$ git add $ git commit -m Premiegravere publication

Ensuite vous pouvez dire agrave vos utilisateurs de lancer

$ git clone votreordinateurcheminverslescript

pour teacuteleacutecharger votre script En consideacuterant qursquoils ont accegraves agrave votre ordinateurvia ssh Sinon lancez git daemon et dites plutocirct agrave vos utilisateurs de lancer

$ git clone gitvotreordinateurcheminverslescript

Agrave partir de maintenant chaque fois que votre script est precirct agrave ecirctre publieacuteexeacutecutez

$ git commit -a -m Nouvelle version

et vos utilisateurs peuvent mettre agrave jour leur version en allant dans leur dossiercontenant votre script et en saisissant

9

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git pull

Vos utilisateurs ne se retrouveront jamais avec une version de votre script quevous ne vouliez pas leur montrer

Qursquoai-je fait

Retrouvez les modifications faites depuis le dernier commit avec

$ git diff

Ou depuis hier

$ git diff yesterday

Ou entre une version speacutecifique et la version deux commits en arriegravere

$ git diff 1b6d master~2

Dans chacun de ces cas la sortie est un patch (rustine) qui peut ecirctre appliqueacuteen utilisant git apply Vous pouvez aussi essayer

$ git whatchanged --since=2 weeks ago

Souvent je parcours plutocirct lrsquohistorique avec qgit pour sa pimpante interfacephotogeacutenique ou tig une interface en mode texte qui fonctionne mecircme sur lesconnexions lentes Autrement installez un serveur web lancez git instawebet deacutegainez nrsquoimporte quel navigateur internet

Exercice

Soit A B C D quatre commits successifs ougrave B est identique agrave A agrave lrsquoexceptionde quelques fichiers qui ont eacuteteacute supprimeacutes Nous voudrions remettre les fichiersen D Comment faire

Il y a au moins trois solutions En consideacuterant que nous sommes agrave D

1 La diffeacuterence entre A et B sont les fichiers supprimeacutes Nous pouvons creacuteerun patch repreacutesentant cette diffeacuterence et lrsquoappliquer

$ git diff B A | git apply

2 Vu que nous avions enregistreacute les fichiers en A nous pouvons les reprendre

$ git checkout A fooc barh

3 Nous pouvons aussi voir le chemin de A agrave B comme une modification agravedeacutefaire

$ git revert B

10

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Quel est le meilleur choix Celui que vous preacutefeacuterez Crsquoest facile drsquoobtenir ceque vous voulez avec Git et souvent il y a plein de maniegraveres de le faire

Clonons gaiement

Avec les anciens systegravemes de gestion de versions lrsquoopeacuteration standard pourobtenir des fichiers est le checkout Vous obtenez un ensemble de fichiers corre-spondant agrave un eacutetat particulier preacuteceacutedemment enregistreacute

Avec Git et drsquoautres systegravemes distribueacutes de gestion de versions le clonage estlrsquoopeacuteration standard Pour obtenir des fichiers on creacutee un clone du deacutepocirct entierEn drsquoautres termes il srsquoagit de faire un miroir du serveur central Tout ce quipeut se faire sur le deacutepocirct central peut ecirctre fait sur le vocirctre

Synchronisation entre machines

Je peux imaginer faire des archives tar ou utiliser rsync pour des sauvegardesou une synchronisation simple Mais parfois jrsquoeacutedite sur mon portable drsquoautresfois sur mon fixe et les deux peuvent ne pas avoir communiqueacute entre temps

Initialisez un deacutepocirct Git et faites un commit de vos fichiers depuis une machineEnsuite sur lrsquoautre

$ git clone autreordinateurcheminverslesfichiers

pour creacuteer une deuxiegraveme copie de ces fichiers et du deacutepocirct Git

Agrave partir de ce moment

$ git commit -a$ git pull autreordinateurcheminverslesfichiers HEAD

ira chercher lrsquoeacutetat des fichiers sur lrsquoautre ordinateur pour mettre agrave jour celuisur lequel vous travaillez Si reacutecemment vous avez fait des modifications drsquounmecircme fichier en conflit entre elles Git vous le signalera et vous devrez reacutepeacuteteragrave nouveau le commit apregraves avoir reacutesolu ces conflits

Gestion classique des sources

Initialisez le deacutepocirct Git de vos fichiers

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

Sur le serveur central initialisez un deacutepocirct nu (bare dans la terminologie Git)dans un dossier quelconque

11

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ mkdir projgit$ cd projgit$ git init --bare$ variante en une ligne GIT_DIR=projgit git init

Si besoin deacutemarrez le deacutemon (service)

$ git daemon --detach peut ecirctre tourne-t-il deacutejagrave

Pour les services drsquoheacutebergement en ligne suivez les instructions fournies pourmettre en place le deacutepocirct Git initialement vide En geacuteneacuteral il srsquoagit de remplirun formulaire sur une page web

Poussez votre projet vers le serveur central en utilisant

$ git push gitserveurcentralcheminduprojgit HEAD

Pour obtenir les sources un deacuteveloppeur saisit

$ git clone gitserveurcentralcheminduprojgit

Apregraves avoir fait des modifications le deacuteveloppeur les enregistre en local

$ git commit -a

Pour se mettre agrave jour par rapport agrave la derniegravere version

$ git pull

Tout conflit lors de la fusion doit ecirctre reacutesolu puis valideacute

$ git commit -a

Pour envoyer les modifications locales vers le deacutepocirct central

$ git push

Si le serveur principal a de nouvelles modifications dues agrave drsquoautres deacuteveloppeurslrsquoenvoi eacutechoue et le deacuteveloppeur doit se mettre agrave jour de la derniegravere versionreacutesoudre les eacuteventuels conflits de fusion puis essayer agrave nouveau

Deacutepocircts nus

Un deacutepocirct nu (bare repository) est nommeacute ainsi car il nrsquoa pas de dossier detravail il ne contient que des fichiers qui sont normalement cacheacutes dans le sousdossier git En drsquoautres termes il ne conserve que lrsquohistorique drsquoun projet etne contient jamais le rendu drsquoune version donneacutee

Un deacutepocirct nu joue un rocircle similaire agrave celui du serveur principal dans un systegravemede gestion de versions centraliseacute le reacuteceptacle de vos projets Les deacuteveloppeursclonent vos projets agrave partir de celui-ci et y poussent les derniegraveres modificationsofficielles En geacuteneacuteral il est placeacute sur un serveur qui ne fait quasiment que ce

12

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

travail de distribution de lrsquoinformation Le deacuteveloppement srsquoopegravere sur les clonesde sorte que le deacutepocirct principal peut se passer drsquoun dossier de travail

Beaucoup des commandes de Git eacutechouent sur un deacutepocirct nu tant que la variabledrsquoenvironnement GIT_DIR nrsquoest pas renseigneacutee avec le chemin vers le deacutepocirct ouque lrsquooption --bare nrsquoest pas utiliseacutee

Envoi vs rapatriement (push vs pull)

Pourquoi a-t-on introduit la commande push (pousser ou envoyer) au lieu de secontenter de la commande pull (tirer ou rapatrier) plus familiegravere Premiegravere-ment la commande pull eacutechoue sur un deacutepocirct nu il faut y utiliser la commandefetch dont nous parlerons plus tard Mais mecircme si nous conservions un deacutepocirctstandard sur le serveur central y rapatrier les modifications serait peu pratiqueNous devrions drsquoabord nous connecter au serveur et donner en argument agrave lacommande pull lrsquoadresse de la machine depuis laquelle nous souhaitons rapa-trier des modifications Des pare-feux peuvent eacuteventuellement nous embecircter etcomment faire si nous nrsquoavons pas drsquoaccegraves shell au serveur

Quoi qursquoil en soit ce cas mis agrave part nous deacutecourageons lrsquoenvoi ( en compara-ison du rapatriement ) parce que cela peut entraicircner des confusions lorsque ladestination possegravede un dossier de travail

En reacutesumeacute pendant votre phase drsquoapprentissage de Git nrsquoutilisez lrsquoenvoi ( push )que lorsque la destination est un deacutepocirct nu sinon rapatriez ( pull )

Forker un projet

Vous en avez marre de la maniegravere dont est geacutereacute un projet Vous pensez pouvoirfaire mieux Dans ce cas sur votre serveur

$ git clone gitserveurprincipalcheminverslesfichiers

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

Par la suite vous pouvez fusionner les modifications venant du projet originelgracircce agrave

$ git pull

Systegraveme ultime de sauvegarde

Vous voulez des archives redondantes et geacuteographiquement distribueacutees permet-tant de faire face agrave un deacutesastre Si votre projet a beaucoup de deacuteveloppeursne faites rien Chaque clone de votre code est de fait une sauvegarde Nonseulement de lrsquoeacutetat actuel mais de lrsquohistorique complet Gracircce aux empreintes

13

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

cryptographiques si le clone de quelqursquoun est corrompu il sera repeacutereacute degraves qursquoiltentera de communiquer avec drsquoautres

Si votre projet nrsquoest pas si populaire trouvez autant de serveurs que possibleafin drsquoheacuteberger vos clones

Le vrai paranoiumlaque devrait toujours noter la derniegravere empreinte SHA1 de 20octets du HEAD dans un endroit sucircr Ce doit ecirctre sucircr pas priveacute Par exemplela publier dans un quotidien marcherait bien parce qursquoil est difficile de reacutealiserune attaque modifiant lrsquoensemble des exemplaires drsquoun journal

Le multi-tacircche agrave la vitesse de la lumiegravere

Imaginons que vous souhaitiez travailler sur plusieurs fonctionnaliteacutes en parallegraveleDans ce cas validez (commit) votre projet et lancez

$ git clone unnouveaudossier

Gracircce aux liens mateacuteriels les clones locaux sont creacuteeacutes plus rapidement et occu-pent moins de place que de simples copies

Vous pouvez maintenant travailler simultaneacutement sur deux fonctionnaliteacutes in-deacutependantes Par exemple vous pouvez modifier lrsquoun des clones pendant quelrsquoautre est en cours de compilation Agrave tout moment vous pouvez valider (commit)vos modifications puis rapatrier (pull) les modifications depuis lrsquoautre clone

$ git pull monautreclone HEAD

Gueacuterilla de la gestion de versions

Alors que vous travaillez sur un projet qui utilise un autre systegraveme de gestionde versions Git vous manque Dans ce cas initialisez un deacutepocirct Git dans votredossier de travail

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

puis clonez-le

$ git clone unnouveaudossier

Allez ensuite dans le nouveau dossier et travaillez plutocirct lagrave utilisant Git commevous le voulez De temps agrave autre quand vous voulez vous synchroniser avec lesautres rendez-vous dans le dossier de deacutepart synchronisez-le en utilisant lrsquoautresystegraveme de gestion de version puis saisissez

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

14

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Ensuite allez dans le nouveau dossier et lancez

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

La proceacutedure pour partager vos modifications avec les autres deacutepend de lrsquoautresystegraveme de gestion de versions Le nouveau dossier contient les fichiers avecvos modifications Lancez toute commande de lrsquoautre systegraveme de gestion deversions neacutecessaire pour les envoyer au deacutepocirct central

Subversion qui est peut ecirctre le meilleur systegraveme de gestion de versions centraliseacuteest utiliseacute par drsquoinnombrables projets La commande git svn automatise laproceacutedure ci-dessus pour les deacutepocircts Subversion et peut aussi ecirctre utiliseacutee pourexporter un projet Git vers un deacutepocirct Subversion

Mercurial

Mercurial est un systegraveme de gestion de versions similaire qui peut travaillerquasiment sans heurt avec Git Avec le plugin hg-git un utilisateur de Mercurialpeut sans rien perdre envoyer (push) vers ou rapatrier (pull) depuis un dossierGit

Teacuteleacutechargez le plugin hg-git avec Git

$ git clone gitgithubcomschaconhg-gitgit

ou Mercurial

$ hg clone httpbitbucketorgdurin42hg-git

Malheureusement il ne semble pas y avoir de plugin analogue pour Git Pourcette raison il semble preacutefeacuterable drsquoutiliser Git plutocirct que Mercurial pour ledeacutepocirct principal Avec un deacutepocirct Mercurial il faut geacuteneacuteralement un volontairequi maintienne un deacutepocirct Git en parallegravele alors que gracircce au plugin hg-git undeacutepocirct Git fait lrsquoaffaire mecircme pour les utilisateurs de Mercurial

Bien que ce plugin puisse convertir un deacutepocirct Mercurial en un deacutepocirct Git enle poussant dans un deacutepocirct vide cette tacircche est plus simple avec le scripthg-fast-export-git disponible via

$ git clone gitrepoorczfast-exportgit

Pour faire une conversion dans un nouveau dossier

$ git init$ hg-fast-exportsh -r depothg

ceci apregraves avoir ajouteacute le script agrave votre $PATH

15

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Bazaar

Nous allons rapidement eacutevoquer Bazaar parce que crsquoest le systegraveme de gestionde versions distribueacute libre le plus populaire apregraves Git et Mercurial

Bazaar agrave lrsquoavantage drsquoavoir plus de recul eacutetant donneacute qursquoil est relativementjeune ses concepteurs ont pu tirer les leccedilons du passeacute et eacuteviter des petitseacutecueils historiques De plus ses deacuteveloppeurs ont le souci de la portabiliteacute et delrsquointeropeacuterabiliteacute avec les autres systegravemes de gestion de versions

Un plugin bzr-git permet aux utilisateurs de Bazaar de travailler avec lesdeacutepocircts Git dans une certaine mesure et permet de le faire de maniegravere increacutemen-tale tandis que bzr-fast-export est fait pour les conversions uniques

Pourquoi jrsquoutilise Git

Au deacutepart jrsquoai choisi Git parce que jrsquoai entendu qursquoil geacuterait lrsquoinimaginablementingeacuterable source du noyaux Linux Je nrsquoai jamais ressenti le besoin drsquoen changerGit mrsquoa rendu de fiers services et je ne me suis toujours pas heurteacute agrave ses limitesComme jrsquoutilise surtout Linux les eacuteventuels problegravemes sur drsquoautres plateformesnrsquoentrent pas en ligne de compte

De plus je preacutefegravere les programmes C et les scripts bash aux exeacutecutables commeles scripts Pythons il y a moins de deacutependances et je suis accro aux tempsdrsquoexeacutecution rapides

Jrsquoai reacutefleacutechi agrave la maniegravere drsquoameacuteliorer Git allant jusqursquoagrave eacutecrire mes propres outilsde type Git mais uniquement agrave des fins de recherche Mecircme si jrsquoavais termineacutece projet jrsquoaurais tout de mecircme continueacute avec Git vu que les avantages sont troppeu significatifs pour justifier lrsquoutilisation drsquoun systegraveme farfelu

Bien sur vos besoins et envies diffegraverent sucircrement et vous pouvez tregraves bien voustrouver mieux avec un autre systegraveme Neacuteanmoins vous ne pouvez pas faire unegrosse erreur en choisissant Git

La sorcellerie des branches

Des branchements et des fusions quasi-instantaneacutes sont les fonctionnaliteacutes lesplus puissantes qui font de Git un vrai tueur

Problegraveme des facteurs externes amegravenent neacutecessairement agrave des changementsde contexte Un gros bug se manifeste sans avertissement dans la version deacute-ployeacutee La date limite pour une fonctionnaliteacute particuliegravere est avanceacutee Undeacuteveloppeur qui vous aidait pour une partie cleacute du projet nrsquoest plus disponibleBref en tous cas vous devez brusquement arrecircter la tacircche en cours pour vousfocaliser sur une tacircche tout autre

16

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Interrompre votre reacuteflexion peut ecirctre nuisible agrave votre productiviteacute et le change-ment de contexte amegravene encore plus de perte Avec un systegraveme de gestion deversions centraliseacute il faudrait teacuteleacutecharger une nouvelle copie de travail depuis leserveur central Un systegraveme de gestion de versions deacutecentraliseacute est bien meilleurpuisqursquoil peut cloner localement la version voulue

Mais un clone implique encore la copie de tout le dossier de travail ainsi quede lrsquohistorique complet jusqursquoau point voulu Mecircme si Git reacuteduit ce coucirct gracircceaux fichiers partageacutes et au liens mateacuteriels les fichiers du projet doivent tout demecircme ecirctre entiegraverement recreacuteeacutes dans le nouveau dossier de travail

Solution dans ce genre de situations Git offre un outil bien meilleur puisqueplus rapide et moins consommateur drsquoespace disque les branches

Gracircce agrave un mot magique les fichiers de votre dossier se transforment drsquoune ver-sion agrave une autre Cette transformation peut ecirctre bien plus qursquoun simple voyagedans lrsquohistorique Vos fichiers peuvent se transformer de la derniegravere version sta-ble vers une version expeacuterimentale vers la version courante de deacuteveloppementvers la version drsquoun collegravegue etc

La touche du chef

Nrsquoavez-vous jamais joueacute agrave lrsquoun de ces jeux qui agrave lrsquoappui drsquoune touche particuliegravere(la laquotouche du chefraquo) affiche instantaneacutement une feuille de calcul Ceci vouspermet de cacher votre eacutecran de jeu degraves que le chef arrive

Dans un dossier vide

$ echo Je suis plus intelligent que mon chef gt myfiletxt$ git init$ git add $ git commit -m Commit initial

Vous venez de creacuteer un deacutepocirct Git qui gegravere un fichier contenant un messageMaintenant tapez

$ git checkout -b chef rien ne semble avoir changeacute$ echo Mon chef est plus intelligent que moi gt myfiletxt$ git commit -a -m Un autre commit

Tout se preacutesente comme si vous aviez reacuteeacutecrit votre fichier et inteacutegrer (commit)ce changement Mais ce nrsquoest qursquoune illusion Tapez

$ git checkout master bascule vers la version originale du fichier

et ccedila y est Le fichier texte est restaureacute Et si le chef repasse pour regardervotre dossier tapez

$ git checkout chef bascule vers la version visible par le chef

17

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Vous pouvez basculer entre ces deux versions autant de fois que voulu et inteacutegrer(commit) vos changements agrave chacune drsquoelles indeacutependamment

Travail temporaire

Supposons que vous travailliez sur une fonctionnaliteacute et que pour une raisonquelconque vous ayez besoin de revenir trois versions en arriegravere afin drsquoajoutertemporairement quelques instructions drsquoaffichage pour voir comment quelquechose fonctionne Faites

$ git commit -a$ git checkout HEAD~3

Maintenant vous pouvez ajouter votre code temporaire lagrave ougrave vous le souhaitezVous pouvez mecircme inteacutegrer (commit) vos changements Lorsque vous aveztermineacute tapez

$ git checkout master

pour retourner agrave votre travail drsquoorigine Notez que tous les changement noninteacutegreacutes sont deacutefinitivement perdus (NdT les changements inteacutegreacutes via commitsont conserveacutes quelques jours et sont accessibles en connaissant leur empreinteSHA1)

Que faire si vous voulez nommer ces changements temporaires Rien de plussimple

$ git checkout -b temporaire

et faites un commit avant de rebasculer vers la branche master Lorsque voussouhaitez revenir agrave vos changements temporaires tapez simplement

$ git checkout temporaire

Nous aborderons la commande checkout plus en deacutetail lorsque nous parlerons duchargement drsquoanciens eacutetats Mais nous pouvons tout de mecircme en dire quelquesmots les fichiers sont bien ameneacutes dans lrsquoeacutetat demandeacute mais en quittant labranche master Agrave ce moment tout commit poussera nos fichiers sur une routediffeacuterente qui pourra ecirctre nommeacutee plus tard

En drsquoautres termes apregraves un checkout vers un eacutetat ancien Git nous place au-tomatiquement dans une nouvelle branche anonyme qui pourra ecirctre nommeacutee etenregistreacutee gracircce agrave git checkout -b

Corrections rapides

Vous travaillez sur une tacircche particuliegravere et on vous demande de tout laissertomber pour corriger un nouveau bug deacutecouvert dans la version lsquo1b6dhelliplsquo

18

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git commit -a$ git checkout -b correction 1b6d

Puis quand vous avez corrigeacute le bug saisissez

$ git commit -a -m Bug corrigeacute$ git checkout master

pour vous ramener agrave votre tacircche originale Vous pouvez mecircme fusionner (merge)avec la correction de bug toute fraicircche

$ git merge correction

Fusionner

Dans certains systegravemes de gestion de versions la creacuteation de branches est facilemais les fusionner est difficile Avec Git la fusion est si simple que vous nrsquoyprecircterez plus attention

En fait nous avons deacutejagrave rencontreacute la fusion La commande pull ramegravene (fetch)une seacuterie de versions puis les fusionne (merge) dans votre branche courante Sivous nrsquoavez effectueacute aucun changement local alors la fusion est un simple bonen avant (un fast forward) un cas deacutegeacuteneacutereacute qui srsquoapparente au rapatriement dela derniegravere version dans un systegraveme de gestion de versions centraliseacute Si vousavez effectueacute des changements locaux Git les fusionnera automatiquement etpreacuteviendra srsquoil y a des conflits

Habituellement une version agrave une seule version parente qursquoon appelle la versionpreacuteceacutedente Une fusion de branches entre elles produit une version avec plusieursparents Ce qui pose la question suivante agrave quelle version se reacutefegravere lsquoHEAD~10lsquo Puisqursquoune version peut avoir plusieurs parents par quel parent remonterons-nous

Il srsquoavegravere que cette notation choisit toujours le premier parent Crsquoest souhaitablepuisque la branche courante devient le premier parent lors drsquoune fusion Nousnous inteacuteressons plus freacutequemment aux changements que nous avons faits dansla branche courante qursquoagrave ceux fusionneacutes depuis drsquoautres branches

Vous pouvez choisir un parent speacutecifique gracircce agrave lrsquoaccent circonflexe Voici parexemple comment voir le log depuis le deuxiegraveme parent

$ git log HEAD^2

Vous pouvez omettre le numeacutero pour le premier parent Voici par exemplecomment voir les diffeacuterences avec le premier parent

$ git diff HEAD^

Vous pouvez combiner cette notation avec les autres Par exemple

$ git checkout 1b6d^^2~10 -b ancien

19

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

deacutemarre la nouvelle branche laquoancienraquo dans lrsquoeacutetat correspondant agrave 10 versionsen arriegravere du deuxiegraveme parent du premier parent de la version 1b6d

Workflow sans interruption

La plupart du temps dans un projet de reacutealisation mateacuterielle la seconde eacutetapedu plan ne peut commencer que lorsque la premiegravere eacutetape est termineacutee Unevoiture en reacuteparation reste bloqueacutee au garage jusqursquoagrave la livraison drsquoune piegraveceLe montage drsquoun prototype est suspendu en attendant la fabrication drsquoune puce

Les projets logiciels peuvent ecirctre similaires La deuxiegraveme partie drsquoune nouvellefonctionnaliteacute doit attendre que la premiegravere partie soit sortie et testeacutee Certainsprojets exigent une validation de votre code avant son acceptation vous ecirctesdonc obligeacute drsquoattendre que la premiegravere partie soit valideacutee avant de commencerla seconde

Gracircce aux branches et aux fusions faciles vous pouvez contourner les regravegles ettravailler sur la partie 2 avant que la partie 1 soit officiellement precircte Supposonsque vous ayez termineacute la version correspondant agrave la partie 1 et que vous lrsquoayezenvoyeacutee pour validation Supposons aussi que vous soyez dans la branche masterAlors branchez-vous

$ git checkout -b part2

Ensuite travaillez sur la partie 2 et inteacutegrez (via commit) vos changementsautant que neacutecessaire Lrsquoerreur eacutetant humaine vous voudrez parfois revenir enarriegravere pour effectuer des corrections dans la partie 1 Eacutevidemment si vous ecircteschanceux ou tregraves bon vous pouvez sauter ce passage

$ git checkout master Retour agrave la partie 1$ correction_des_bugs$ git commit -a Inteacutegration de la correction$ git checkout part2 Retour agrave la partie 2$ git merge master Fusion de la correction

Finalement la partie 1 est valideacutee

$ git checkout master Retour agrave la partie 1$ diffusion des fichiers Diffusion au reste du monde $ git merge part2 Fusion de la partie 2$ git branch -d part2 Suppression de la branche part2

Agrave cet instant vous ecirctes agrave nouveau dans la branche master avec la partie 2 dansvotre dossier de travail

Il est facile drsquoeacutetendre cette astuce agrave de nombreuses branches Il est aussi facilede creacuteer une branche reacutetroactivement imaginons qursquoapregraves 7 commits vousvous rendiez compte que vous auriez ducirc creacuteer une branche Tapez alors

20

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git branch -m master part2 Renommer la branche master en part2$ git branch master HEAD~7 Recreacuteer une branche master 7 commits en arriegravere

La branche master contient alors uniquement la partie 1 et la branche part2 con-tient le reste nous avons creacuteeacute master sans basculer vers elle car nous souhaitonscontinuer agrave travailler sur part2 Ce nrsquoest pas tregraves courant Jusqursquoagrave preacutesent nousavions toujours basculeacute vers une branche degraves sa creacuteation comme dans

$ git checkout HEAD~7 -b master Creacuteer une branche et basculer vers elle

Reacuteorganiser le foutoir

Peut-ecirctre aimez-vous travailler sur tous les aspects drsquoun projet dans la mecircmebranche Vous souhaitez que votre travail en cours ne soit accessible qursquoagrave vous-mecircme et donc que les autres ne puissent voir vos versions que lorsqursquoelles sontproprement organiseacutees Commencez par creacuteer deux branches

$ git branch propre Creacuteer une branche pour les versions propres$ git checkout -b foutoir Creacuteer et basculer vers une branche pour le foutoir

Ensuite faites tout ce que vous voulez corriger des bugs ajouter des fonction-naliteacutes ajouter du code temporaire et faites-en des versions autant que vouluPuis

$ git checkout propre$ git cherry-pick foutoir^^

applique les modifications de la version grand-megravere de la version courante dulaquofoutoirraquo agrave la branche laquopropreraquo Avec les cherry-picks approprieacutes vous pouvezconstruire une branche qui ne contient que le code permanent et ougrave toutes lesmodifications qui marchent ensemble sont regroupeacutees

Gestion des branches

Pour lister toutes les branches tapez

$ git branch

Par deacutefaut vous commencez sur la branche nommeacutee laquomasterraquo Certains preacute-conisent de laisser la branche laquomasterraquo telle quelle et de creacuteer de nouvellesbranches pour vos propres modifications

Les options -d et -m vous permettent de supprimer et renommer les branchesVoir git help branch

La branche laquomasterraquo est une convention utile Les autres supposent que votredeacutepocirct possegravede une telle branche et qursquoelle contient la version officielle de votreprojet Bien qursquoil soit possible de renommer ou drsquoeffacer cette branche laquomasterraquoil peut-ecirctre utile de respecter les traditions

21

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Les branches temporaires

Apregraves un certain temps drsquoutilisation vous vous apercevrez que vous creacuteezfreacutequemment des branches eacutepheacutemegraveres toujours pour les mecircmes raisons ellesvous servent juste agrave sauvegarder lrsquoeacutetat courant vous permettant ainsi de revenirmomentaneacutement agrave eacutetat preacuteceacutedent pour corriger un bug

Crsquoest exactement comme si vous zappiez entre deux chaicircnes de teacuteleacutevision Maisau lieu de presser deux boutons il vous faut creacuteer basculer fusionner et sup-primer des branches temporaires Par chance Git propose un raccourci qui estaussi pratique que la teacuteleacutecommande de votre teacuteleacutevision

$ git stash

Cela meacutemorise lrsquoeacutetat courant dans un emplacement temporaire (un stash) etrestaure lrsquoeacutetat preacuteceacutedent Votre dossier courant apparaicirct alors exactementcomme il eacutetait avant que vous ne commenciez agrave faire des modifications et vouspouvez corriger des bugs aller rechercher (pull) une modification de deacutepocirctcentral ou toute autre chose Lorsque vous souhaitez revenir agrave lrsquoeacutetat meacutemoriseacutedans votre stash tapez

$ git stash apply Peut-ecirctre faudra-t-il reacutesoudre quelques conflits

Vous pouvez avoir plusieurs stash et les manipuler de diffeacuterents maniegraveres Voirgit help stash Comme vous lrsquoaurez devineacute pour faire ces tours de magiedans les coulisses Git gegravere des branches

Travailler comme il vous chante

Vous vous demandez sans doute si lrsquousage des branches en vaut la peine Apregravestout des clones sont tout aussi rapides et vous pouvez basculer de lrsquoun agrave lrsquoautrepar un simple cd au lieu de commandes Git eacutesoteacuteriques

Consideacuterez les navigateurs Web Pourquoi proposer plusieurs onglets ainsi queplusieurs fenecirctres Parce proposer les deux permet de srsquoadapter agrave une largegamme drsquoutilisations Certains preacutefegraverent nrsquoavoir qursquoune seule fenecirctre avec pleindrsquoonglets Drsquoautres font tout le contraire plein de fenecirctres avec un seul ongletDrsquoautres encore meacutelangent un peu des deux

Les branches ressemblent agrave des onglets de votre dossier de travail et les clonesressemblent aux diffeacuterents fenecirctres de votre navigateur Ces opeacuterations sonttoutes rapides et locales Alors expeacuterimentez pour trouver la combinaison quivous convient Git vous laisse travailler exactement comme vous le souhaitez

22

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Les leccedilons de lrsquohistoire

Lrsquoune des conseacutequences de la nature distribueacutee de Git est qursquoil est facile de mod-ifier lrsquohistorique Mais si vous reacuteeacutecrivez le passeacute faites attention ne modifiezque la partie de lrsquohistorique que vous ecirctes le seul agrave posseacuteder Sinon commedes nations qui se battent eacuteternellement pour savoir qui a commis telle ou telleatrociteacute si quelqursquoun drsquoautre possegravede un clone dont lrsquohistorique diffegravere du vocirctrevous aurez des difficulteacutes agrave vous reacuteconcilier lorsque vous interagirez

Certains deacuteveloppeurs insistent tregraves fortement pour que lrsquohistorique soit consid-eacutereacute comme immuable Drsquoautres pensent au contraire que les historiques doiventecirctre rendus preacutesentables avant drsquoecirctre preacutesenteacutes publiquement Git srsquoaccommodedes deux points de vue Comme les clones les branches et les fusions la reacuteeacutecri-ture de lrsquohistorique est juste un pouvoir suppleacutementaire que vous donne GitCrsquoest agrave vous de lrsquoutiliser agrave bon escient

Je me corrigehellip

Que faire si vous avez fait un commit mais que vous souhaitez y attacher unmessage diffeacuterent Pour modifier le dernier message tapez

$ git commit --amend

Vous apercevez-vous que vous avez oublieacute un fichier Faites git add pourlrsquoajouter puis exeacutecutez la commande ci-dessus

Voulez-vous ajouter quelques modifications suppleacutementaires au dernier commit Faites ces modifications puis exeacutecutez

$ git commit --amend -a

hellip et bien plus

Supposons que le problegraveme preacuteceacutedent est dix fois pire Apregraves une longue seacuteancevous avez effectueacute une seacuterie de commits Mais vous nrsquoecirctes pas satisfait de lamaniegravere dont ils sont organiseacutes et certains des messages associeacutes doivent ecirctrerevus Tapez alors

$ git rebase -i HEAD~10

et les dix derniers commits apparaissent dans votre $EDITOR favori Voici unpetit extrait

pick 5c6eb73 Added repoorcz linkpick a311a64 Reordered analogies in Work How You Wantpick 100834f Added push target to Makefile

Ensuite

23

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

bull Supprimez un commit en supprimant sa ligne

bull Reacuteordonnez des commits en reacuteordonnant leurs lignes

bull Remplacez pick par

ndash edit pour marquer ce commit pour amendement

ndash reword pour modifier le message associeacute

ndash squash pour fusionner ce commit avec le preacuteceacutedent

ndash fixup pour fusionner ce commit avec le preacuteceacutedent en supprimant lemessage associeacute

Sauvegardez et quittez Si vous avez marqueacute un commit pour amendement alorstapez

$ git commit --amend

Sinon tapez

$ git rebase --continue

Donc faites des commits tregraves tocirct et faites-en souvent vous pourrez tout rangerplus tard gracircce agrave rebase

Les changements locaux en dernier

Vous travaillez sur un projet actif Vous faites quelques commits locaux puisvous vous resynchronisez avec le deacutepocirct officiel gracircce agrave une fusion (merge) Cecycle se reacutepegravete jusqursquoau moment ougrave vous ecirctes precirct agrave pousser vos contributionsvers le deacutepocirct central

Mais agrave cet instant lrsquohistorique de votre clone Git local est un fouillis infacircmemeacutelangeant les modifications officielles et les vocirctres Vous preacutefeacutereriez que toutesvos modifications soient contigueumls et se situent apregraves toutes les modificationsofficielles

Crsquoest un boulot pour git rebase comme deacutecrit ci-dessus Dans la plupart descas vous pouvez utilisez lrsquooption --onto et eacuteviter les interactions

Lisez git help rebase pour des exemples deacutetailleacutes sur cette merveilleuse com-mande Vous pouvez scinder des commits Vous pouvez mecircme reacutearranger desbranches de lrsquoarbre

Reacuteeacutecriture de lrsquohistoire

De temps en temps vous avez besoin de faire des modifications eacutequivalentes agrave lasuppression drsquoune personne drsquoune photo officielle la gommant ainsi de lrsquohistoiredrsquoune maniegravere quasi Stalinienne Supposons que vous ayez publieacute un projet mais

24

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

en y inteacutegrant un fichier que vous auriez ducirc conserver secret Par exemple vousavez accidentellement ajouteacute un fichier texte contenant votre numeacutero de cartede creacutedit Supprimer ce fichier nrsquoest pas suffisant puisqursquoil pourra encore ecirctreretrouveacute via drsquoanciennes versions du projet Vous devez supprimer ce fichierdans toutes les versions

$ git filter-branch --tree-filter rm topsecretfichier HEAD

La documentation git help filter-branch explique cette exemple et donneune meacutethode plus rapide De maniegravere geacuteneacuterale filter-branch vous permet demodifier des pans entiers de votre historique gracircce agrave une seule commande

Apregraves cela le dossier gitrefsoriginal contiendra lrsquoeacutetat de votre deacutepocirctavant lrsquoopeacuteration Veacuterifiez que la commande filter-branch a bien fait ce que voussouhaitiez puis effacer ce dossier si vous voulez appliquer drsquoautres commandesfilter-branch

Finalement remplacez tous les clones de votre projet par votre version reacuteviseacuteesi vous voulez pouvoir interagir avec eux plus tard

Faire lrsquohistoire

Voulez-vous faire migrer un projet vers Git Srsquoil est geacutereacute par lrsquoun des systegravemesbien connus alors il y a de grandes chances que quelqursquoun ait deacutejagrave eacutecrit un scriptafin drsquoimporter lrsquoensemble de lrsquohistorique dans Git

Sinon regarder du cocircteacute de git fast-import qui lit un fichier texte dans unformat speacutecifique pour creacuteer un historique Git agrave partir de rien Typiquementun script utilisant cette commande est un script jetable qui ne servira qursquouneseule fois pour migrer le projet drsquoun seul coup

Agrave titre drsquoexemple collez le texte suivant dans un fichier temporaire(tmphistorique)

commit refsheadsmastercommitter Alice ltaliceexamplecomgt Thu 01 Jan 1970 000000 +0000data ltltEOTCommit initialEOT

M 100644 inline hellocdata ltltEOTinclude ltstdiohgt

int main() printf(Hello worldn)return 0

25

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

EOT

commit refsheadsmastercommitter Bob ltbobexamplecomgt Tue 14 Mar 2000 015926 -0800data ltltEOTRemplacement de printf() par write()EOT

M 100644 inline hellocdata ltltEOTinclude ltunistdhgt

int main() write(1 Hello worldn 14)return 0

EOT

Puis creacuteez un deacutepocirct Git agrave partir de ce fichier temporaire en tapant

$ mkdir projet cd projet git init$ git fast-import --date-format=rfc2822 lt tmphistorique

Vous pouvez extraire la derniegravere version de ce projet avec

$ git checkout master

La commande git fast-export peut convertir nrsquoimporte quel deacutepocirct Git en unfichier au format git fast-import ce qui vous permet de lrsquoeacutetudier pour eacutecriredes scripts drsquoexportation mais vous permet aussi de transporter un deacutepocirct dansun format lisible Ces commandes permettent aussi drsquoenvoyer un deacutepocirct via uncanal qui nrsquoaccepte que du texte pur

Qursquoest-ce qui a tout casseacute

Vous venez tout juste de deacutecouvrir un bug dans une fonctionnaliteacute de votreprogramme et pourtant vous ecirctes sucircr qursquoelle fonctionnait encore parfaitement ily a quelques mois Zut Drsquoougrave provient ce bug Si seulement vous aviez testeacutecette fonctionnaliteacute pendant vos deacuteveloppements

Mais il est trop tard En revanche en supposant que vous avez fait des commitssuffisamment souvent Git peut cerner le problegraveme

$ git bisect start$ git bisect bad HEAD$ git bisect good 1b6d

26

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Git extrait un eacutetat agrave mi-chemin entre ces deux versions (HEAD et 1b6d) Testezla fonctionnaliteacute et si le bug se manifeste

$ git bisect bad

Si elle ne se manifeste pas remplacer rdquobadrdquo (mauvais) par rdquogoodrdquo (bon) Gitvous transporte agrave nouveau dans un eacutetat agrave mi-chemin entre la bonne et la mau-vaise version en reacuteduisant ainsi les possibiliteacutes Apregraves quelques iteacuterations cetterecherche dichotomique vous amegravenera au commit ougrave le bug est survenu Unefois vos investigations termineacutees retourner agrave votre eacutetat original en tapant

$ git bisect reset

Au lieu de tester chaque eacutetat agrave la main automatisez la recherche en tapant

$ git bisect run mon_script

Git utilise la valeur de retour du script fourni pour deacutecider si un eacutetat est bon oumauvais mon_script doit retourner 0 si lrsquoeacutetat courant est ok 125 si cet eacutetatdoit ecirctre sauteacute et nrsquoimporte quelle valeur entre 1 et 127 si lrsquoeacutetat est mauvaisUne valeur neacutegative abandonne la commande bisect

Vous pouvez faire bien plus la page drsquoaide explique comment visualiser lesbisects comment examiner ou rejouer le log drsquoun bisect et comment eacuteliminerdes changements que vous savez sans conseacutequence afin drsquoacceacuteleacuterer la recherche

Qui a tout casseacute

Comme de nombreux systegravemes de gestion de versions Git a sa commandeblame

$ git blame bugc

Cette commande annote chaque ligne du fichier afin de montrer par qui et quandelle a eacuteteacute modifieacutee la derniegravere fois Agrave lrsquoinverse de la plupart des autres systegravemescette commande marche hors-ligne et ne lit que le disque local

Expeacuterience personnelle

Avec un systegraveme de gestion de versions centraliseacute la modification de lrsquohistoriqueest une opeacuteration difficile et faisable uniquement par les administrateurs Creacuteerun clone creacuteer une branche ou en fusionner plusieurs sont des opeacuterations im-possibles agrave reacutealiser sans communication reacuteseau Il en est de mecircme pour certainsopeacuterations basiques telles que parcourir lrsquohistorique ou inteacutegrer une modificationAvec certains systegravemes des communications reacuteseaux sont mecircme neacutecessaires justepour voir ses propres modifications ou pour ouvrir un fichier avec le droit demodification

27

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Ces systegravemes centraliseacutes empecircchent le travail hors-ligne et neacutecessitent une infras-tructure reacuteseau drsquoautant plus lourde que le nombre de deacuteveloppeurs augmententPlus important encore certaines opeacuterations deviennent si lentes que les utilisa-teurs les eacutevitent agrave moins qursquoelles soient absolument indispensables Dans les casextrecircmes cela devient vrai mecircme pour les commandes les plus basiques Lorsqueles utilisateurs doivent effectuer des opeacuterations lentes la productiviteacute souffre desinterruptions reacutepeacuteteacutees

Jrsquoai moi-mecircme veacutecu ce pheacutenomegravene Git a eacuteteacute le premier systegraveme de gestionde versions que jrsquoai utiliseacute Je me suis vite accoutumeacute agrave lui tenant la plupartde ses fonctionnaliteacutes pour acquises Je pensais que les autres systegravemes eacutetaientsimilaires le choix drsquoun systegraveme de gestion de versions ne devait pas ecirctre biendiffeacuterent du choix drsquoun eacutediteur de texte ou drsquoun navigateur web

Jrsquoai eacuteteacute tregraves surpris lorsque plus tard il mrsquoa fallu utiliseacute un systegraveme centraliseacuteUne liaison internet eacutepisodique importe peu avec Git mais rend le deacuteveloppementquasi impossible lorsque le systegraveme exige qursquoelle soit aussi fiable que les accegravesau disque local De plus je me restreignais afin drsquoeacuteviter certaines commandestrop longues ce qui mrsquoempecircchait de suivre ma meacutethode de travail habituelle

Lorsqursquoil me fallait utiliser ces commandes lentes cela interrompait mes reacuteflex-ions et avait des effets pervers En attendant la fin des communications avecle serveur je me lanccedilais dans autre chose pour passer le temps comme lire mesmails ou eacutecrire de la documentation Lorsque je revenais agrave mon travail initialla commande srsquoeacutetait termineacutee depuis longtemps et je perdais du temps agrave retrou-ver le fil de mes penseacutees Les ecirctre humains ne sont pas bons pour changer decontexte

Il y a aussi un effet inteacuteressant du type laquo trageacutedie des biens communs raquo afindrsquoanticiper la congestion du reacuteseau certains vont consommer plus de bandespassantes que neacutecessaire pour effectuer des opeacuterations visant agrave reacuteduire leursattentes futures Ces efforts combineacutes vont encore augmenter la congestionincitant ces personnes agrave consommer encore plus de bande passante pour eacuteviterces deacutelais toujours plus longs

Git multijoueur

Au deacutepart jrsquoutilisais Git pour un projet priveacute ougrave jrsquoeacutetais le seul deacuteveloppeurParmi toutes les commandes lieacutees agrave la nature distribueacutee de Git je nrsquoavais besoinque de pull et clone afin de disposer de mon projet en diffeacuterents lieux

Plus tard jrsquoai voulu publier mon code via Git et inclure des modifications deplusieurs contributeurs Jrsquoai ducirc apprendre agrave geacuterer des projets avec de nombreuxdeacuteveloppeurs agrave travers le monde Heureusement crsquoest lrsquoun des points forts deGit et peut-ecirctre mecircme sa raison drsquoecirctre (en franccedilais dans le texte)

28

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Qui suis-je

Agrave chaque commit sont associeacutes le nom et le mail de lrsquoauteur ceux qui sontmontreacutes par git log Par deacutefaut Git utilise les valeurs fournies par le systegravemepour remplir ces champs Pour les configurer explicitement tapez

$ git config --global username John Doe$ git config --global useremail johndoeexamplecom

Supprimer lrsquooption --global pour que ces valeurs soient locales au deacutepocirctcourant

Git via SSH et HTTP

Supposez que vous ayez un accegraves SSH agrave un serveur Web sur lequel Git nrsquoestpas installeacute Bien que ce soit moins efficace que le protocole natif Git saitcommuniquer par dessus HTTP

Teacuteleacutecharger compiler et installer Git sur votre compte et creacuteer un deacutepocirct dansvotre dossier web

$ GIT_DIR=projgit git init$ cd projgit$ git --bare update-server-info$ cp hookspost-updatesample hookspost-update

Avec les vieilles versions de Git la commande de copie eacutechoue et vous devezfaire

$ chmod a+x hookspost-update

Maintenant vous pouvez transmettre vos modifications via SSH depuisnrsquoimporte lequel de vos clones

$ git push webserverpathtoprojgit master

et nrsquoimporte qui peut reacutecupeacuterer votre projet gracircce agrave

$ git clone httpwebserverprojgit

Git via nrsquoimporte quoi

Besoin de synchroniser des deacutepocircts sans passer par un serveur ni mecircme uneconnexion reacuteseau Besoin drsquoimproviser dans lrsquourgence Nous avons deacutejagrave vuque git fast-export et git fast-import savent convertir et recreacuteer un deacutepocirctvia un simple fichier Nous pourrions utiliser des fichiers de ce type pour assurerle transport entre des deacutepocircts Git via nrsquoimporte quel canal Mais un outil pluspuissant existe git bundle

29

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Lrsquoeacutemetteur creacutee un rsquobundlersquo

$ git bundle create monbundle HEAD

puis il transmet ce bundle monbundle agrave lrsquoautre partie par nrsquoimporte quelmoyen email cleacute USB impression puis reconnaissance de caractegraveres lecturedes bits au teacuteleacutephone signaux de fumeacutee etc Le reacutecepteur retrouve les mises agravejour du bundle en tapant

$ git pull monbundle

Le reacutecepteur peut mecircme faire cela dans un deacutepocirct entiegraverement vide Malgreacute sapetite taille monbundle contient lrsquoensemble du deacutepocirct Git drsquoorigine

Pour des projets plus gros on peut reacuteduire le gaspillage en incluant dans le bun-dle uniquement les changements manquants dans lrsquoautre deacutepocirct En supposantpar exemple que le commit laquo1b6dhellipraquo est le commit le plus reacutecent partageacute parles deux deacutepocircts on peut faire

$ git bundle create monbundle HEAD ^1b6d

Si on fait cela souvent il se peut qursquoon ne sache plus quel est le dernier commitpartageacute La page drsquoaide suggegravere drsquoutiliser des tags pour reacutesoudre ce problegravemeEn pratique juste apregraves lrsquoenvoi drsquoun bundle tapez

$ git tag -f dernierbundle HEAD

et pour creacuteer un nouveau bundle faites

$ git bundle create nouveaubundle HEAD ^dernierbundle

Les patches la monnaie drsquoeacutechange globale

Les patches sont des repreacutesentations textuelles de vos modifications qui peu-vent ecirctre facilement compris par les ordinateurs comme par les humains Crsquoestce qui leur donne leur charme Vous pouvez envoyer un patch par mail agrave undeacuteveloppeur sans savoir quel systegraveme de gestion de versions il utilise Agrave partirdu moment ougrave on peut lire les mails que vous envoyez on peut voir vos mod-ifications De votre cocircteacute vous nrsquoavez besoin que drsquoun compte mail aucuneneacutecessiteacute de mettre en œuvre un deacutepocirct Git en ligne

Souvenez-vous du premier chapitre La commande

$ git diff 1b6d gt monpatch

produit un patch qui peut ecirctre colleacute dans un mail Dans un deacutepocirct Git tapez

$ git apply lt monpatch

pour appliquer le patch

Drsquoune maniegravere plus formelle lorsque le nom des auteurs et peut-ecirctre leur signa-ture doit apparaicirctre geacuteneacuterez tous les patches depuis un certain point en tapant

30

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git format-patch 1b6d

Les fichiers reacutesultants peuvent ecirctre fournis agrave git send-email ou envoyeacutes agrave lamain Vous pouvez aussi speacutecifier un intervalle entre deux commits

$ git format-patch 1b6dHEAD^^

Du cocircteacute du destinataire enregistrez un mail dans un fichier puis tapez

$ git am lt mailtxt

Ccedila appliquera le patch reccedilu mais creacuteera aussi un commit en y incluant toutesles informations telles que le nom des auteurs

Si vous utilisez un client de messagerie dans un navigateur il vous faudra sansdoute appuyer sur un bouton afin de voir le mail dans son format brut avant delrsquoenregistrer dans un fichier

Il y a de leacutegegraveres diffeacuterences dans le cas des clients de messagerie se basant sur leformat mbox mais si vous utilisez lrsquoun drsquoentre eux vous ecirctes sans aucun doutecapable de vous en deacutebrouiller facilement sans lire des tutoriels

(NdT si votre deacutepocirct contient des fichiers binaires nrsquooubliez-pas drsquoajouterlrsquooption --binary aux commandes de creacuteation de patches ci-dessus)

Le numeacutero de votre correspondant a changeacute

Apregraves la creacuteation drsquoun clone drsquoun deacutepocirct lrsquoutilisation de git push ou de gitpull se reacutefeacuterera automatiquement agrave lrsquoURL du deacutepocirct drsquoorigine Comment Gitfait-il Le secret reacuteside dans des options de configuration ajouteacutees dans le cloneJetons-y un œil

$ git config --list

Lrsquooption remoteoriginurl deacutetermine lrsquoURL de la source laquooriginraquo est unalias donneacute au deacutepocirct drsquoorigine Comme dans le cas de la branche principalequi se nomme laquomasterraquo par convention on peut changer ou supprimer cet aliasmais il nrsquoy a habituellement aucune raison de le faire

Si le deacutepocirct original change vous pouvez modifier son URL via

$ git config remoteoriginurl gitnouvelurlprojgit

Lrsquooption branchmastermerge speacutecifie le nom de la branche distante utiliseacuteepar deacutefaut par la commande git pull Lors du clonage initial le nom choisiest celui de la branche courant du deacutepocirct drsquoorigine Mecircme si le HEAD du deacutepocirctdrsquoorigine est deacuteplaceacute vers une autre branche la commande pull continuera agravesuivre fidecirclement la branche initiale

Cette option ne srsquoapplique qursquoau deacutepocirct ayant servi au clonage initial celuienregistreacute dans lrsquooption branchmasterremote Si nous effectuons un pulldepuis un autre deacutepocirct nous devrons indiquer explicitement la branche voulue

31

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git pull gitexamplecomothergit master

Les deacutetails ci-dessus expliquent pourquoi nos appels agrave push et pull dans nospreacuteceacutedents exemples nrsquoavaient pas besoin drsquoarguments

Les branches distantes

Lorsque nous clonons un deacutepocirct nous clonons aussi toutes ses branches Vous neles avez sans doute pas remarqueacutees car Git les cache vous devez explicitementdemander agrave les voir Cela empecircche les branches du deacutepocirct distant drsquointerfeacutereravec vos propres branches et cela rend aussi Git plus simple pour les deacutebutants

Listons les branches distantes

$ git branch -r

Vous devriez voir quelque chose comme

originHEADoriginmasteroriginexperimental

Ces noms sont ceux des branches et du HEAD du deacutepocirct distant et ils peuventecirctre utiliseacutes dans les commandes Git normales Supposez par exemple que vousavez reacutealiseacute de nombreux commits et que vous vouliez voir la diffeacuterence avecla derniegravere version rameneacutee par fetch Vous pourriez rechercher dans le logpour retrouver lrsquoempreinte SHA1 approprieacutee mais il est beaucoup plus simplede tapez

$ git diff originHEAD

Vous pouvez aussi voir ougrave en est rendu la branche ldquoexperimentalrdquo

$ git log originexperimental

Deacutepocircts distants multiples

Supposez que deux autres deacuteveloppeurs travaillent sur notre projet et que noussouhaitons garder un œil sur les deux Nous pouvons suivre plus drsquoun deacutepocirct agravela fois gracircce agrave

$ git remote add un_autre gitexamplecomun_depotgit$ git pull un_autre une_branche

Maintenant nous avons fusionneacute avec une branche drsquoun second deacutepocirct et nousavons accegraves facilement agrave toutes les branches de tous les deacutepocircts

$ git diff originexperimental^ un_autreune_branche~5

32

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Mais comment faire si nous souhaitons juste comparer leurs modifications sansaffecter notre travail En drsquoautres termes nous voulons examiner leurs branchessans que leurs modifications envahissent notre dossier de travail Agrave la place drsquounpull faisons

$ git fetch Rapatrier depuis le deacutepocirct dorigin par deacutefaut$ git fetch un_autre Rapatrier depuis le deacutepocirct dun_autre

Cela ne rapatrie (fetch) que les historiques Bien que notre dossier de tra-vail reste inchangeacute nous pouvons faire reacutefeacuterence agrave nrsquoimporte quelle branchede nrsquoimporte quel deacutepocirct dans nos commandes Git puisque nous en posseacutedonsmaintenant une copie locale

Rappelez-vous qursquoen coulisse un pull est simplement un fetch suivi drsquounmerge Habituellement nous faisons appel agrave pull car nous voulons fusionner(merge) les derniegraveres modifications distantes apregraves les avoir rapatrieacutees (fetch)La situation ci-dessus est une exception notable

Voir get help remote pour savoir comment supprimer des deacutepocircts distantsignorer certaines branches et bien plus encore

Mes preacutefeacuterences

Pour mes projets jrsquoaime que mes contributeurs se confectionnent un deacutepocirctdepuis lequel je peux effectuer des pull Certains services drsquoheacutebergement Gitvous permettent de creacuteer votre propre deacutepocirct clone drsquoun projet en cliquant sim-plement sur un bouton

Apregraves avoir rapatrieacute (fetch) un arbre de modifications jrsquoutilise les commandesGit pour parcourir et examiner ces modifications qui ideacutealement sont bienorganiseacutees et bien deacutecrites Je fusionne mes propres modifications et effectueparfois quelques modifications suppleacutementaires Une fois satisfait je les envoie(push) vers le deacutepocirct principal

Bien que recevant rarement des contributions je pense que mon approche estparfaitement adaptable agrave grande eacutechelle Voir ce billet par Linus Torvalds

Rester dans le monde Git est un peu plus pratique que de passer par des fichiersde patch puisque cela mrsquoeacutevite drsquoavoir agrave les convertir en commits Git De plus Gitgegravere les deacutetails tels qursquoenregistrer le nom de lrsquoauteur son adresse mail ainsi quela date et lrsquoheure et il demande agrave lrsquoauteur de deacutecrire ses propres modifications

La maicirctrise de Git

Agrave ce stade vous devez ecirctre capable de parcourir les pages de git help etcomprendre presque tout (en supposant que vous lisez lrsquoanglais) En revanche

33

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

retrouver la commande exacte qui reacutesoudra un problegraveme preacutecis peut ecirctre fasti-dieux Je peux sans doute vous aider agrave gagner un peu de temps vous trouverezci-dessous quelques-unes des recettes dont jrsquoai deacutejagrave eu besoin

Publication de sources

Dans mes projets Git gegravere exactement tous les fichiers que je veux placer dansune archive afin de la publier Pour creacuteer une telle archive jrsquoutilise

$ git archive --format=tar --prefix=proj-123 HEAD

Geacuterer le changement

Indiquer agrave Git quels fichiers ont eacuteteacute ajouteacutes supprimeacutes ou renommeacutes est parfoispeacutenible pour certains projets Agrave la place vous pouvez faire

$ git add $ git add -u

Git cherchera les fichiers du dossier courant et geacuterera tous les deacutetails toutseul En remplacement de la deuxiegraveme commande add vous pouvez utilisergit commit -a pour creacuteer un nouveau commit directement Lisez git helpignore pour savoir comment speacutecifier les fichiers qui doivent ecirctre ignoreacutes

Vous pouvez effectuer tout cela en une seule passe gracircce agrave

$ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove

Les options -z et -0 empecircchent les effets secondaires impreacutevus ducircs au noms defichiers contenant des caractegraveres eacutetranges Comme cette commande ajoutentaussi les fichiers habituellement ignoreacutes vous voudrez sucircrement utiliser les op-tions -x ou -X

Mon commit est trop gros

Avez-vous neacutegligeacute depuis longtemps de faire un commit Avez-vous codeacute fu-rieusement et tout oublieacute de la gestion de versions jusqursquoagrave preacutesent Faites-vousplein de petits changements sans rapport entre eux parce que crsquoest votre maniegraverede travailler

Pas de soucis Faites

$ git add -p

Pour chacune des modifications que vous avez faites Git vous montrera le boutde code qui a changeacute et vous demandera si elle doit faire partie du prochaincommit Reacutepondez par rdquoyrdquo (oui) ou par rdquonrdquo (non) Vous avez aussi drsquoautres

34

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

options comme celle vous permettant de reporter votre deacutecision tapez rdquordquo pouren savoir plus

Une fois satisfait tapez

$ git commit

pour faire un commit incluant exactement les modifications qui vous avez seacutelec-tionneacutees (les modifications indexeacutees) Soyez certain de ne pas utiliser lrsquooption-a sinon Git fera un commit incluant toutes vos modifications

Que faire si vous avez modifieacute de nombreux fichiers en de nombreux endroits Veacuterifier chaque modification individuellement devient alors rapidement frustrantet abrutissant Dans ce cas utilisez la commande git add -i dont lrsquointerfaceest moins facile mais beaucoup plus souple En quelques touches vous pouvezajouter ou retirer de votre index (voir ci-dessous) plusieurs fichiers drsquoun seulcoup mais aussi valider ou non chacune des modifications individuellement pourcertains fichiers Vous pouvez aussi utiliser en remplacement la commande gitcommit --interactive qui effectuera un commit automatiquement quand vousaurez termineacute

Lrsquoindex lrsquoaire drsquoassemblage

Jusqursquoici nous avons reacuteussi agrave eacuteviter de parler du fameux index de Git mais nousdevons maintenant le preacutesenter pour mieux comprendre ce qui preacutecegravede Lrsquoindexest une aire drsquoassemblage temporaire Git ne transfert que tregraves rarement dedonneacutees depuis votre dossier de travail directement vers votre historique Enfait Git copie drsquoabord ces donneacutees dans lrsquoindex puis il copie toutes ces donneacuteesdepuis lrsquoindex vers leur destination finale

Un commit -a par exemple est en fait un processus en deux temps Lapremiegravere eacutetape consiste agrave construire dans lrsquoindex un instantaneacute de lrsquoeacutetat actuelde tous les fichiers suivis par Git La seconde eacutetape enregistre cet instantaneacutede maniegravere permanente dans lrsquohistorique Effectuer un commit sans lrsquooption-a reacutealise uniquement cette deuxiegraveme eacutetape et cela nrsquoa de sens qursquoapregraves avoireffectueacute des commandes qui change lrsquoindex telle que git add

Habituellement nous pouvons ignorer lrsquoindex et faire comme si nous eacutechangionsdirectement avec lrsquohistorique Dans certaines occasions nous voulons un con-trocircle fin et nous geacuterons donc lrsquoindex Nous placcedilons dans lrsquoindex un instantaneacute decertaines modifications (mais pas toutes) et enregistrons de maniegravere permanentecet instantaneacute soigneusement construit

Ne perdez pas la tecircte

Le tag HEAD est comme un curseur qui pointe habituellement vers le toutdernier commit et qui avance agrave chaque commit Certaines commandes Git vous

35

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

permettent de le deacuteplacer Par exemple

$ git reset HEAD~3

deacuteplacera HEAD trois commits en arriegravere Agrave partir de lagrave toutes les commandesGit agiront comme si vous nrsquoaviez jamais fait ces trois commits mecircme si vosfichier restent dans leur eacutetat preacutesent Voir les pages drsquoaide pour quelques usagesinteacuteressants

Mais comment faire pour revenir vers le futur Les commits passeacutes ne saventrien du futur

Si vous connaissez lrsquoempreinte SHA1 du HEAD original faites alors

$ git reset 1b6d

Mais que faire si vous ne lrsquoavez pas regardeacute Pas de panique pour descommandes comme celle-ci Git enregistre la valeur originale de HEAD dans untag nommeacute ORIG_HEAD et vous pouvez revenir sain et sauf via

$ git reset ORIG_HEAD

Chasseur de tecircte

Peut-ecirctre que ORIG_HEAD ne vous suffit pas Peut-ecirctre venez-vous de vousapercevoir que vous avez fait une monumentale erreur et que vous devez reveniragrave une ancienne version drsquoune branche oublieacutee depuis longtemps

Par deacutefaut Git conserve un commit au moins deux semaine mecircme si vous avezdemandeacute agrave Git de deacutetruire la branche qui le contient La difficulteacute consiste agraveretrouver lrsquoempreinte approprieacutee Vous pouvez toujours explorer les diffeacuterentesvaleurs drsquoempreinte trouveacutees dans gitobjects et retrouver celle que vouscherchez par essais et erreurs Mais il existe un moyen plus simple

Git enregistre lrsquoempreinte de chaque commit qursquoil traite dans gitlogs Lesous-dossier refs contient lrsquohistorique de toute lrsquoactiviteacute de chaque branche alorsque le fichier HEAD montre chaque valeur drsquoempreinte que HEAD a pu prendreCe dernier peut donc servir agrave retrouver les commits drsquoune branche qui a eacuteteacuteaccidentellement eacutelagueacutee

La commande reflog propose une interface sympa vers ces fichiers de log Es-sayez

$ git reflog

Au lieu de copiercoller une empreinte listeacutee par reflog essayez

$ git checkout 10 minutes ago

Ou basculez vers le cinquiegraveme commit preacuteceacutedemment visiteacute via

$ git checkout 5

36

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Voir la section laquoSpecifying Revisionsraquo de git help rev-parse pour en savoirplus

Vous pouvez configurer une plus longue peacuteriode de reacutetention pour les commitscondamneacutes Par exemple

$ git config gcpruneexpire 30 days

signifie qursquoun commit effaceacute ne le sera veacuteritablement qursquoapregraves 30 jours et lorsque$git gc tournera

Vous pouvez aussi deacutesactiver le deacuteclenchement automatique de git gc

$ git config gcauto 0

auquel cas les commits ne seront veacuteritablement effaceacutes que lorsque vous lancerezgit gc manuellement

Construire au-dessus de Git

Agrave la maniegravere UNIX la conception de Git permet son utilisation comme uncomposant de bas niveau drsquoautres programmes tels que des interfaces graphiquesou web des interfaces en ligne de commandes alternatives des outils de gestionde patch des outils drsquoimportation et de conversion etc En fait certainescommandes Git sont de simples scripts srsquoappuyant sur les commandes de basecomme des nains sur des eacutepaules de geacuteants Avec un peu de bricolage vouspouvez adapter Git agrave vos preacutefeacuterences

Une astuce facile consiste agrave creacuteer des alias Git pour raccourcir les commandesque vous utilisez le plus freacutequemment

$ git config --global aliasco checkout$ git config --global --get-regexp alias affiche les alias connusaliasco checkout$ git co foo identique agrave git checkout foo

Une autre astuce consiste agrave inteacutegrer le nom de la branche courante dans votreprompt ou dans le titre de la fenecirctre Lrsquoinvocation de

$ git symbolic-ref HEAD

montre le nom complet de la branche courante En pratique vous souhaiterezprobablement enlever rdquorefsheadsrdquo et ignorer les erreurs

$ git symbolic-ref HEAD 2gt devnull | cut -b 12-

Le sous-dossier contrib de Git est une mine drsquooutils construits au-dessus de Git Un jour certains drsquoentre eux pourraient ecirctre promus aurang de commandes officielles Dans Debian et Ubuntu ce dossier estusrsharedocgit-corecontrib

37

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Lrsquoun des plus populaires de ces scripts est workdirgit-new-workdir Gracircceagrave des liens symboliques intelligents ce script creacutee un nouveau deacutepocirct dontlrsquohistorique est partageacute avec le deacutepocirct original

$ git-new-workdir unexistantdepot nouveaurepertoire

Le nouveau dossier et ses fichiers peuvent ecirctre vus comme un clone sauf quelrsquohistorique est partageacute et que les deux arbres des versions restent automatique-ment synchrones Nul besoin de merge push ou pull

Audacieuses acrobaties

Agrave ce jour Git fait tout son possible pour que lrsquoutilisateur ne puisse pas effaceraccidentellement des donneacutees Mais si vous savez ce que vous faites vous pouvezpasser outre les garde-fous des principales commandes

Checkout des modifications non inteacutegreacutees (via commit) peuvent causer lrsquoeacutechecdrsquoun checkout Pour deacutetruire vos modifications et reacuteussir quoi qursquoil arrive uncheckout drsquoun commit donneacute utilisez lrsquooption drsquoobligation

$ git checkout -f HEAD^

Inversement si vous speacutecifiez des chemins particuliers pour un checkout alorsil nrsquoy a pas de garde-fous Le contenu des chemins est silencieusement reacuteeacutecritFaites attention lorsque vous utilisez un checkout de cette maniegravere

Reset un reset eacutechoue aussi en preacutesence de modifications non inteacutegreacutees Pourpasser outre faites

$ git reset --hard 1b6d

Branch la suppression de branches eacutechoue si cela implique la perte de certainscommits Pour forcer la suppression tapez

$ git branch -D branche_morte agrave la place de -d

De maniegravere similaire une tentative visant agrave renommer une branche existantevers le nom drsquoune autre branche eacutechoue si cela amegravene la perte de commits Pourforcer le changement de nom tapez

$ git branch -M source target agrave la place de -m

Contrairement agrave checkout et reset ces deux derniegraveres commandes nrsquoeffectuentpas la suppression des informations immeacutediatement Les commits destineacutes agrave dis-paraicirctre sont encore disponibles dans le sous-dossier git et peuvent encore ecirctreretrouveacutes gracircce aux empreintes approprieacutees tel que retrouveacutees dans gitlogs(voir rdquoChasseur de tecircterdquo ci-dessus) Par deacutefaut ils sont conserveacutes au moins deuxsemaines

38

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Clean certaines commandes Git refusent de srsquoexeacutecuter pour ne pas eacutecraser desfichiers non suivis Si vous ecirctes certain que tous ces fichiers et dossiers peuventecirctre sacrifieacutes alors effacez-les sans pitieacute via

$ git clean -f -d

Ensuite la commande trop prudente fonctionnera

Se preacutemunir des commits erroneacutes

Des erreurs stupides encombrent mes deacutepocircts Les plus effrayantes sont dues agrave desfichiers manquants car oublieacutes lors des git add Drsquoautres erreurs moins gravesconcernent les espaces blancs inutiles ou les conflits de fusion non reacutesolus bienqursquoinoffensives jrsquoaimerais qursquoelles nrsquoapparaissent pas dans les versions publiques

Si seulement je mrsquoen eacutetais preacutemuni en utilisant un hook (un crochet) pourmrsquoalerter de ces problegravemes

$ cd githooks$ cp pre-commitsample pre-commit Vieilles versions de Git chmod +x pre-commit

Maintenant Git empecircchera un commit srsquoil deacutetecte des espace inutiles ou srsquoil restedes conflits de fusion non reacutesolus

Pour geacuterer ce guide jrsquoai aussi ajouteacute les lignes ci-dessous au deacutebut de mon hookpre-commit pour me preacutemunir de mes inattentions

if git ls-files -o | grep txt$ thenecho FAIL Untracked txt filesexit 1

fi

Plusieurs opeacuteration de Git acceptent les hooks voir git help hooks Nousavons deacutejagrave utiliseacute le hook post-update lorsque nous avons parleacute de Git au-dessus de HTTP Celui-ci se deacuteclenche agrave chaque mouvement de HEAD Lescript drsquoexemple post-update met agrave jour les fichiers Git neacutecessaires agrave une com-munication au-dessus de transports agnostiques tels que HTTP

Les secrets reacuteveacuteleacutes

Nous allons jeter un œil sous le capot pour comprendre comment Git reacutealise sesmiracles Je passerai sous silence la plupart des deacutetails Pour des explicationsplus deacutetailleacutees reacutefeacuterez-vous au manuel utilisateur

39

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Lrsquoinvisibiliteacute

Comment fait Git pour ecirctre si discret Mis agrave part lorsque vous faites descommits et des fusions vous pouvez travailler comme si la gestion de versionsnrsquoexistait pas Et crsquoest lorsque vous en avez besoin que vous ecirctes content de voirque Git veillait sur vous tout le temps

Drsquoautres systegravemes de gestion de versions vous mettent constamment aux prisesavec de la paperasserie et de la bureaucratie Les fichiers sont en lecture seulejusqursquoagrave lrsquoobtention depuis un serveur central du droit drsquoeacutedition de tel ou telfichier Les commandes les plus basiques voient leurs performances srsquoeacutecroulerau fur et agrave mesure que le nombre drsquoutilisateurs augmente Le travail srsquoarrecirctedegraves lors que le reacuteseau ou le serveur central est en panne

Agrave lrsquoinverse Git conserve tout lrsquohistorique de votre projet dans le sous-dossiergit de votre dossier de travail Crsquoest votre propre copie de lrsquohistorique et vouspouvez donc rester deacuteconnecteacute tant que vous ne voulez pas communiquer avecles autres Vous conservez un controcircle total sur le sort de vos fichiers puisqueGit peut aiseacutement les recreacuteer agrave tout moment agrave partir de lrsquoun des eacutetats enregistreacutesdans git

Lrsquointeacutegriteacute

La plupart des gens associent la cryptographie agrave la conservation du secretdes informations mais lrsquoun de ses buts tout aussi important est de conserverlrsquointeacutegriteacute de ces informations Un usage approprieacute des fonctions de hachagecryptographiques (celles qui calculent lrsquoempreinte drsquoun document) permetdrsquoempecirccher la corruption accidentelle ou malicieuse des donneacutees

Une empreinte SHA1 peut ecirctre vue comme un nombre de 160 bits identifiant demaniegravere unique nrsquoimporte quelle suite drsquooctets que vous rencontrerez dans votrevie On peut mecircme aller plus loin crsquoest vrai pour toutes les suites drsquooctets queles humains utiliseront sur plusieurs geacuteneacuterations

Comme une empreinte SHA1 est elle-mecircme une suite drsquooctets nous pouvons cal-culer lrsquoempreinte drsquoune suite de caractegraveres contenant drsquoautres empreintes Cettesimple observation est eacutetonnamment utile (cherchez par exemple hash chain)Nous verrons plus tard comment Git utilise cela pour garantir efficacementlrsquointeacutegriteacute des donneacutees

En bref Git conserve vos donneacutees dans le sous-dossier gitobjects mais agrave laplace des noms de fichiers normaux vous nrsquoy trouverez que des ID En utilisantces ID comme noms de fichiers et gracircce agrave quelques astucieux fichiers de verrouil-lage et drsquohorodatage Git transforme un simple systegraveme de fichiers en une basede donneacutees efficace et robuste

40

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Lrsquointelligence

Comment fait Git pour savoir que vous avez renommeacute un fichier mecircme si vousne lui avez pas dit explicitement Bien sucircr vous pouvez utiliser git mv maiscrsquoest exactement la mecircme chose que de faire git rm suivi par git add

Git a des heuristiques pour deacutebusquer les changements de noms et les copiesentre les versions successives En fait il peut mecircme deacutetecter les bouts de codequi ont eacuteteacute deacuteplaceacutes ou copieacutes drsquoun fichier agrave un autre Bien que ne couvrantpas tous les cas cela marche deacutejagrave tregraves bien et cette fonctionnaliteacute est encore encours drsquoameacutelioration Si cela eacutechoue pour vous essayez les options activant desmeacutethodes de deacutetection de copie plus coucircteuses et envisager de faire une mise agravejour

Lrsquoindexation

Pour chaque fichier suivi Git meacutemorise des informations telles que sa taille etses dates de creacuteation et de derniegraveres modifications dans un fichier appeleacute indexPour deacuteterminer si un fichier a changeacute Git compare son eacutetat courant avec ceqursquoil a meacutemoriseacute dans lrsquoindex Si cela correspond alors Git nrsquoa pas besoin derelire le fichier

Puisque les appels agrave stat sont consideacuterablement plus rapides que la lecture desfichiers si vous nrsquoavez modifieacute que quelques fichiers Git peut deacuteterminer soneacutetat en tregraves peu de temps

Nous avons dit plus tocirct que lrsquoindex eacutetait une aire drsquoassemblage Comment sepeut-il qursquoun simple fichier contant quelques informations sur les fichiers soitune aire drsquoassemblage Parce que la commande add ajoute les fichiers agrave labase de donneacutees de Git et met agrave jour lrsquoindex avec leurs informations alors quela commande commit sans option creacutee une nouvelle version baseacutee uniquementsur cet index et les fichiers deacutejagrave inclus dans la base de donneacutees

Les origines de Git

Ce message de la Mailing List du noyau Linux deacutecrit lrsquoenchaicircnement des eacutevegravene-ments ayant meneacute agrave Git Lrsquoensemble de lrsquoenfilade est un site archeacuteologiquefascinant pour les historiens de Git

La base drsquoobjets

Chacune des versions de vos donneacutees est conserveacutee dans la base drsquoobjets (objectdatabase) qui reacuteside dans le sous-dossier gitobjects le reste du contenu dudossier git repreacutesente moins de donneacutees lrsquoindex le nom des branches les

41

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

tags les options de configuration les logs lrsquoemplacement actuel de HEAD etainsi de suite La base drsquoobjets est simple mais eacuteleacutegante et constitue la sourcede la puissance de Git

Chaque fichier dans gitobjects est un objet Il y a trois sortes drsquoobjets quinous concerne les blobs les arbres (trees) et les commits

Les blobs

Tout drsquoabord faisons un peu de magie Choisissez un nom de fichierhellipnrsquoimporte quel nom de fichier Puis dans un dossier vide faites (en remplaccedilantVOTRE_NOM_DE_FICHIER par le nom que vous avez choisi)

$ echo joli gt VOTRE_NOM_DE_FICHIER$ git init$ git add $ find gitobjects -type f

Vous verrez gitobjects0680f15d4cb13a09f600a25b84eae36506167970

Comment puis-je le savoir sans connaicirctre le nom de fichier que vous avez choisi Tout simplement parce que lrsquoempreinte SHA1 de

blob SP 5 NUL joli LF

est 0680f15d4cb13a09f600a25b84eae36506167970 Ougrave SP est un espace NULest lrsquooctet de valeur nulle et LF est un passage agrave la ligne Vous pouvez veacuterifiercela en tapant

$ printf blob 5000jolin | sha1sum

Git utilise un classement par contenu les fichiers ne sont pas stockeacutes selon leurnom mais selon lrsquoempreinte des donneacutees qursquoils contiennent dans un fichier quenous appelons un objet blob Nous pouvons consideacuterer lrsquoempreinte comme unID unique du contenu drsquoun fichier Donc nous pouvons retrouver un fichier parson contenu La chaicircne initiale blob 5 est simplement un entecircte indiquant letype de lrsquoobjet et sa longueur en octets cela simplifie le classement interne

Je peux donc aiseacutement preacutedire ce que vous voyez Le nom du fichier ne comptepas pour construire lrsquoobjet blob seules comptent les donneacutees stockeacutees dans lefichier

Peut-ecirctre vous demandez-vous ce qui se produit pour des fichiers ayant le mecircmecontenu Essayez en creacuteant des copies de votre premier fichier avec des nomsquelconques Le contenu de gitobjects reste le mecircme quel que soit le nombrede copies que vous avez ajouteacutees Git ne stocke le contenu qursquoune seule fois

Agrave propos les fichiers dans gitobjects sont compresseacutes par zlib et par con-seacutequent vous ne pouvez pas en consulter le contenu directement Passez-les autravers du filtre zpipe -d ou tapez

42

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git cat-file -p 0680f15d4cb13a09f600a25b84eae36506167970

qui affiche proprement lrsquoobjet choisi

Les arbres (trees)

Mais que deviennent les noms des fichiers Ils doivent bien ecirctre stockeacutes quelquepart agrave un moment Git se preacuteoccupe des noms de fichiers lors drsquoun commit

$ git commit Tapez un message$ find gitobjects -type f

Vous devriez voir maintenant trois objets Mais lagrave je ne peux plus preacutedirele nom des deux nouveaux fichiers puisqursquoils deacutependent en partie du nom defichier que vous avez choisi Nous continuerons en supposant que vous avezchoisi laquoroseraquo Si ce nrsquoest pas le cas vous pouvez reacuteeacutecrire lrsquohistoire pour que cesoit le cas

$ git filter-branch --tree-filter mv VOTRE_NOM_DE_FICHIER rose$ find gitobjects -type f

Le fichier gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 de-vrait maintenant apparaicirctre puisque crsquoest lrsquoempreinte SHA1 du contenu suiv-ant

tree SP 32 NUL 100644 rose NUL 0x9a6a950c3b14eb1a3fb540a2749514a1cb81e206

Veacuterifiez que ce contenu est le bon en tapant

$ echo 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | git cat-file --batch

Avec zpipe il est plus simple de veacuterifier lrsquoempreinte

$ zpipe -d lt gitobjects9a6a950c3b14eb1a3fb540a2749514a1cb81e206 | sha1sum

La veacuterification de lrsquoempreinte est plus difficile via cat-file puisque cette com-mande nrsquoaffiche pas que le contenu brut du fichier apregraves deacutecompression

Cette fichier est un objet arbre (tree) une liste de tuples constitueacutes drsquoun typedrsquoun nom de fichier et drsquoune empreinte Dans notre exemple le type est 100644qui indique que rose est un fichier normal et lrsquoempreinte est celle de lrsquoobjetde type blob contenant le contenu de rose Les autres types possibles pourun fichier sont exeacutecutable lien symbolique ou dossier Dans ce dernier caslrsquoempreinte repreacutesente un autre objet de type arbre

Si vous faites appel agrave la commande filter-branch vous verrez apparaicirctre de vieuxobjets dont vous nrsquoavez pas besoin Mecircme srsquoils disparaicirctront automatiquementune fois expireacutee la peacuteriode de reacutetention nous allons les effacer degraves maintenantpour rendre notre petit exemple plus facile agrave suivre

$ rm -r gitrefsoriginal$ git reflog expire --expire=now --all

43

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

$ git prune

Sur de vrais projets vous devriez eacuteviter de telles commandes puisqursquoelles deacutetru-isent les sauvegardes Si vous voulez un dossier propre il est conseilleacute de faireun tout nouveau clone Faites aussi attention si vous manipulez directement lecontenu de git que se passera-t-il si une commande Git srsquoeffectue au mecircmemoment ou si le courant est soudainement coupeacute

De maniegravere geacuteneacuterale les refs devraient toujours ecirctre effaceacutees via git update-ref -d mecircme si on considegravere comme sans risque la suppression manuelle derefsoriginal

Les commits

Nous avons expliqueacute 2 des 3 types drsquoobjets Le troisiegraveme est lrsquoobjet commit Soncontenu deacutepend du message de commit ainsi que de la date et lrsquoheure auxquellesil a eacuteteacute creacuteeacute Pour que vous obteniez la mecircme chose qursquoici nous devons bidouillerun peu

$ git commit --amend -m Shakespeare Changement de message de commit$ git filter-branch --env-filter export

GIT_AUTHOR_DATE=Fri 13 Feb 2009 153130 -0800GIT_AUTHOR_NAME=AliceGIT_AUTHOR_EMAIL=aliceexamplecomGIT_COMMITTER_DATE=Fri 13 Feb 2009 153130 -0800GIT_COMMITTER_NAME=Bob

GIT_COMMITTER_EMAIL=bobexamplecom Trucage de la date lheure et lauteur$ find gitobjects -type f

Le fichier gitobjectsae9d1241b2b6eea90529149a065f6bc444365c2a de-vrait maintenant exister puisque crsquoest lrsquoempreinte SHA1 du contenu suivant

commit 158 NULtree 9a6a950c3b14eb1a3fb540a2749514a1cb81e206 LFauthor Alice ltaliceexamplecomgt 1234567890 -0800 LFcommitter Bob ltbobexamplecomgt 1234567890 -0800 LFLFShakespeare LF

Comme preacuteceacutedemment vous pouvez utiliser zpipe ou cat-file pour veacuterifier parvous-mecircme

Crsquoest le premier commit ce qui explique pourquoi il nrsquoy a pas de commit parentMais les commits suivants contiendront toujours au moins une ligne identifiantun commit parent

44

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Indiscernable de la magie

Les secrets de Git semblent trop simples On imagine qursquoil suffit de meacutelangerquelques scripts shell et drsquoy ajouter une pinceacutee de code C pour mitonner untel systegraveme en quelques heures un assemblage drsquoopeacuterations basiques sur lesfichiers et de calcul drsquoempreintes SHA1 garni de quelques fichiers verrou etdrsquoappels agrave fsync pour la robustesse En fait nous venons preacuteciseacutement de deacutecrireles premiegraveres versions de Git Malgreacute tout mis agrave part quelques techniquesastucieuses de compression pour gagner de la place et drsquoindexation pour gagnerdu temps nous savons maintenant comment Git transforme adroitement unsystegraveme de fichiers en une base de donneacutees parfaitement adapteacutee agrave de la gestionde versions

Par exemple si un fichier quelconque de la base drsquoobjets vient agrave ecirctre corrompupar une erreur disque alors son empreinte ne correspond plus et nous sommesalerteacutes du problegraveme En calculant lrsquoempreinte des empreintes drsquoautres objetsnous maintenons lrsquointeacutegriteacute agrave tous les niveaux Les commits sont atomiquespuisque ils ne peuvent jamais meacutemoriser des modifications partiellement stock-eacutees nous ne pouvons calculer lrsquoempreinte drsquoun commit et le stocker dans la basedrsquoobjets qursquoapregraves y avoir deacutejagrave stockeacute tous les arbres blobs et parents relatifs agravece commit La base drsquoobjets est immuniseacutee contre les interruptions inattenduestelles que les coupures de courant

Nous faisons mecircme eacutechouer les tentatives drsquoattaque les plus sournoises Sup-posez que quelqursquoun tente de modifier discregravetement le contenu drsquoun fichier danslrsquoune des anciennes versions du projet Pour rendre coheacuterent le contenu dela base drsquoobjets il lui faut changer lrsquoempreinte de lrsquoobjet blob correspondantpuisque elle doit maintenant repreacutesenter une chaicircne drsquooctets diffeacuterente Cela sig-nifie qursquoil doit aussi changer lrsquoempreinte de tous les arbres reacutefeacuterenccedilant ce blob etdonc changer lrsquoempreinte de tous les commits impliquant ces arbres ainsi que detous les descendants de ces commits Cela implique que lrsquoempreinte du HEADofficiel diffegravere de celle du HEAD drsquoun deacutepocirct corrompu En remontant la suitedrsquoempreintes erroneacutees nous pouvons localiser avec preacutecision le fichier corrompuainsi que le premier commit ougrave il lrsquoa eacuteteacute

En reacutesumeacute tant que nous sommes sucircrs des 20 octets repreacutesentant le derniercommit il est impossible drsquoalteacuterer un deacutepocirct Git

Qursquoen est-il des fameuses fonctionnaliteacutes de Git Des branchements Desfusions Des tags De simples deacutetails La tecircte courante est conserveacutee dans lefichier gitHEAD qui contient lrsquoempreinte drsquoun objet commit Cette empreintesera tenue agrave jour durant un commit ainsi que durant de nombreuses autrescommandes Les branches fonctionnent de maniegravere similaire ce sont des fichiersdans gitrefsheads Et les tags aussi ils sont dans gitrefstags maisils sont mis agrave jour par un ensemble diffeacuterent de commandes

45

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Appendix A Les lacunes de Git

Git preacutesente quelques problegravemes que jrsquoai soigneusement cacheacutes Certains peu-vent ecirctre reacutesolus par des scripts et des hooks drsquoautres neacutecessitent une reacuteorgan-isation ou une redeacutefinition du projet et pour les quelques rares ennuis restantsil vous suffit drsquoattendre Ou mieux encore de donner un coup de main

Les faiblesses de SHA1

Avec le temps les speacutecialistes de cryptographie deacutecouvrent de plus en plus defaiblesses de SHA1 Agrave ce jour la deacutecouverte de collisions drsquoempreintes sembleagrave la porteacutee drsquoorganisations bien doteacutees Et drsquoici quelques anneacutees peut-ecirctreque mecircme un simple PC aura assez de puissance de calcul pour corrompre demaniegravere indeacutetectable un deacutepocirct Git

Heureusement Git aura migreacute vers une fonction de calcul drsquoempreintes demeilleure qualiteacute avant que de futures recherches deacutetruisent SHA1

Microsoft Windows

Git sur Microsoft Windows peut ecirctre jugeacute encombrant

bull Cygwin est un environnement de type Linux dans Windows proposant unportage de Git

bull Git pour Windows est un autre choix neacutecessitant beaucoup moins de placeNeacuteanmoins quelques commandes doivent encore ecirctre ameacutelioreacutees

Des fichiers sans relation

Si votre projet est tregraves gros et contient de nombreux fichiers sans relation en-tre eux et changeant constamment Git peut ecirctre plus deacutefavoriseacute que drsquoautressystegravemes puisque les fichiers pris seacutepareacutement ne sont pas pisteacutes Git piste leschangement de lrsquoensemble du projet ce qui est habituellement beacuteneacutefique

Une solution consiste agrave deacutecouper votre projet en plusieurs parties chacune reacuteu-nissant des fichiers en relation entre eux Utilisez git submodule si voussouhaitez conserver tout cela dans un seul dossier

Qui modifie quoi

Certains systegravemes de gestion de versions vous oblige agrave marquer explicitementun fichier avant de pouvoir le modifier Bien que particuliegraverement ennuyeux

46

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

puisque pouvant impliquer une communication avec un serveur central celapreacutesente deux avantages

1 Les diffs sont plus rapides puisque seuls les fichiers marqueacutes doivent ecirctreexamineacutes

2 Quelqursquoun peut savoir qui travaille sur un fichier en demandant au serveurcentral qui lrsquoa marqueacute pour modification

Avec quelques scripts approprieacutes vous pouvez obtenir la mecircme chose avec GitCela neacutecessite la coopeacuteration du deacuteveloppeur qui doit exeacutecuter un script partic-ulier avant toute modification drsquoun fichier

Lrsquohistorique drsquoun fichier

Puisque Git enregistre les modifications de maniegravere globale au projet la recon-struction de lrsquohistorique drsquoun seul fichier demande plus de travail qursquoavec unsystegraveme de gestion de versions qui traque les fichiers individuellement

Ce surplus est geacuteneacuteralement neacutegligeable et en vaut la peine puisque cela per-met aux autres opeacuterations drsquoecirctre incroyablement efficaces Par exemple gitcheckout est plus rapide que cp -a et un delta de versions globale au projet secompresse mieux qursquoune collection de delta fichier par fichier

Le clone initial

La creacuteation drsquoun clone est plus coucircteuse que lrsquoextraction de code des autressystegravemes quand il y a un historique conseacutequent

Ce coucirct initial srsquoavegravere payant dans le temps puisque la plupart des opeacuterationsfutures srsquoeffectueront rapidement et hors-ligne En revanche dans certains sit-uations il est preacutefeacuterable de creacuteer un clone superficiel gracircce agrave lrsquooption --depth(qui limite la profondeur de lrsquohistorique) Crsquoest plus rapide mais le clone ainsicreacuteeacute offre des fonctionnaliteacutes reacuteduites

Les projets versatiles

Git a eacuteteacute conccedilu pour ecirctre rapide au regard de la taille des changements Leshumains font de petits changement de version en version Une correction debug en une ligne ici une nouvelle fonctionnaliteacute lagrave un commentaire amendeacuteailleurshellip Mais si vos fichiers changent radicalement agrave chaque reacutevision alors agravechaque commit votre historique grossit drsquoun poids eacutequivalent agrave celui de votreprojet

47

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Il nrsquoy a rien qursquoun systegraveme de gestion de versions puisse faire pour eacuteviter celamais les utilisateurs de Git en souffrent plus puisque chaque clone contienthabituellement lrsquohistorique complet

Il faut rechercher les raisons de ces changements radicaux Peut-ecirctre faut-ilchanger les formats des fichiers Des modifications mineures ne devraient modi-fier que tregraves peu de chose dans tregraves peu de fichiers

Peut-ecirctre qursquoune base donneacutees ou une solution drsquoarchivage est-elle plus adapteacuteecomme solution qursquoun systegraveme de gestion de versions Agrave titre drsquoexemple unsystegraveme de gestion de versions nrsquoest certainement pas bien tailleacute pour geacuterer desphotos prises peacuteriodiquement par une webcam

Si les fichiers doivent absolument se transformer constamment et srsquoil faut absol-ument les geacuterer par version une possibiliteacute peut ecirctre une utilisation centraliseacuteedrsquoun deacutepocirct Git Chacun ne creacutee qursquoun clone superficiel ne contenant qursquoun his-torique reacutecent voire inexistant du projet Eacutevidemment de nombreux outils Gitne seront plus utilisables et les corrections devront ecirctre fournies sous forme depatches Crsquoest sans doute acceptable sans en savoir plus sur les raisons reacuteellesde la conservation de lrsquohistorique de nombreux fichiers instables

Un autre exemple serait un projet deacutependant drsquoun firmware qui prend la formedrsquoun eacutenorme fichier binaire Lrsquohistorique de ce firmware nrsquointeacuteresse pas les util-isateur et les mises agrave jour se compressent difficilement et donc les reacutevisions dece firmware vont faire grossir inutilement le deacutepocirct

Dans ce cas le code source devrait ecirctre stockeacute dans le deacutepocirct Git et les fichiers bi-naires conserveacutes seacutepareacutement Pour rendre la vie meilleure on peut distribuer unscript qui utilisera un clone Git pour le code et rsync ou un clone Git superficielpour le firmware

Compteur global

Certains systegravemes de gestion de versions centraliseacutes gegravere un entier positif quiaugmente agrave chaque commit accepteacute Git fait reacutefeacuterence agrave un changement par sonempreinte ce qui est mieux pour de nombreuses raisons

Mais certains aiment voir ce compteur Par chance il est tregraves facile drsquoeacutecrire unscript qui se deacuteclenchera agrave chaque mise agrave jour du deacutepocirct Git central et increacute-mentera un compteur peut-ecirctre dans un tag qursquoil associera agrave lrsquoempreinte dudernier commit

Chaque clone peut geacuterer un tel compteur mais crsquoest probablement sans inteacuterecirctpuisque seul le compteur du deacutepocirct central compte

48

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Les dossiers vides

Les sous-dossiers vides ne peuvent pas ecirctre suivis Placez-y des fichiers sansinteacuterecirct pour remeacutedier agrave ce problegraveme

Cette limitation nrsquoest pas une fataliteacute due agrave la conception de Git mais un choixde lrsquoimpleacutementation actuelle Avec un peu de chance si de nombreux utilisateursle demandent cette fonctionnaliteacute pourrait ecirctre ajouteacutee

Le premier commit

Un informaticien typique compte agrave partir de 0 plutocirct que de 1 Malheureuse-ment concernant les commits Git nrsquoadhegravere pas agrave cette convention Plusieurscommandes ne fonctionnent pas avant le tout premier commit De plus certainscas limites doivent ecirctre geacutereacutes speacutecifiquement par exemple un rebasage versune branche avec un commit initial diffeacuterent

Git beacuteneacuteficierait agrave deacutefinir le commit zeacutero degraves la creacuteation drsquoun deacutepocirct HEADserait deacutefini comme la chaicircne contenant 20 octets nuls Ce commit speacutecialrepreacutesenterait un arbre vide sans parent qui serait preacutesent dans tous les deacutepocirctsGit

Ainsi lrsquoappel agrave git log par exemple pourrait indiquer agrave lrsquoutilisateur qursquoaucuncommit nrsquoa eacuteteacute fait au lieu de se terminer par une erreur fatale Il en serait demecircme pour les autres outils

Le commit initial serait un descendant implicite de ce commit zeacutero

Mais ce nrsquoest pas le cas et donc certains problegravemes peuvent se poser Si plusieursbranches avec des commits initiaux diffeacuterents sont fusionneacutees alors le rebasagedu reacutesultat requiert de nombreuses interventions manuelles

Bizarreries de lrsquointerface

Eacutetant donneacute deux commits A et B le sens des expressions rdquoABrdquo et rdquoAhellipBrdquodiffegravere selon que la commande attend deux extreacutemiteacutes ou un intervalle Voir githelp diff et git help rev-parse

Appendix B Traduire ce guide

Faites un clone du source puis creacuteer un reacutepertoire correspondant au code IETFde la langue souhaiteacutee voir lrsquoarticle du W3C concernant lrsquointernationalisationPar exemple pour lrsquoanglais crsquoest rdquoenrdquo pour le japonais crsquoest rdquojardquo et pour le chi-nois traditionnel crsquoest rdquozh-Hantrdquo Dans ce nouveau reacutepertoire traduisez chacundes fichiers txt du reacutepertoire rdquoenrdquo original

49

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide

Par exemple pour creacuteer ce guide en Klingon vous devriez faire

$ git clone gitrepoorczgitmagicgit$ cd gitmagic$ mkdir tlh tlh est le code IETF de la langue Klingon$ cd tlh$ cp enintrotxt $ edit introtxt Traduire le fichier

et ainsi de suite pour tous les fichiers Vous pouvez relire votre travail increacute-mentalement

$ make LANG=tlh$ firefox bookhtml

Faites souvent des commits pour vos modifications puis faites-le moi savoir degravesque crsquoest precirct GitHubcom propose une interface qui facilite les choses faitesun fork du projet rdquogitmagicrdquo poussez-y vos modifications et demandez-moi deles fusionner

Jrsquoaime avoir des traductions qui suivent le scheacutema ci-dessus car mes scriptspeuvent alors produire les versions HTML et PDF Et puis crsquoest pratique deconserver toutes les traductions dans le deacutepocirct officiel Mais que cela ne vousempecircche pas de faire ce qui vous convient le mieux par exemple les traducteurschinois preacutefegraverent utiliser Google Docs Je suis content tant que votre travailpermet agrave drsquoautres de profiter de mon travail

50

  • Preacuteface
    • Merci
    • Licence
      • Introduction
        • Le travail comme un jeu
        • Gestion de versions
        • Gestion distribueacutee
        • Une superstition idiote
        • Conflits fusionnels
          • Astuces de base
            • Enregistrer leacutetat courant
            • Ajouter supprimer renommer
            • AnnulerReprendre avanceacute
            • Reprise (revert)
            • Geacuteneacuteration du journal des modifications (changelog)
            • Teacuteleacutecharger des fichiers
            • Le dernier cri
            • Publication instantaneacutee
            • Quai-je fait
            • Exercice
              • Clonons gaiement
                • Synchronisation entre machines
                • Gestion classique des sources
                • Deacutepocircts nus
                • Envoi vs rapatriement (push vs pull)
                • Forker un projet
                • Systegraveme ultime de sauvegarde
                • Le multi-tacircche agrave la vitesse de la lumiegravere
                • Gueacuterilla de la gestion de versions
                • Mercurial
                • Bazaar
                • Pourquoi jutilise Git
                  • La sorcellerie des branches
                    • La touche du chef
                    • Travail temporaire
                    • Corrections rapides
                    • Fusionner
                    • Workflow sans interruption
                    • Reacuteorganiser le foutoir
                    • Gestion des branches
                    • Les branches temporaires
                    • Travailler comme il vous chante
                      • Les leccedilons de lhistoire
                        • Je me corrigehellip
                        • hellip et bien plus
                        • Les changements locaux en dernier
                        • Reacuteeacutecriture de lhistoire
                        • Faire lhistoire
                        • Quest-ce qui a tout casseacute
                        • Qui a tout casseacute
                        • Expeacuterience personnelle
                          • Git multijoueur
                            • Qui suis-je
                            • Git via SSH et HTTP
                            • Git via nimporte quoi
                            • Les patches la monnaie deacutechange globale
                            • Le numeacutero de votre correspondant a changeacute
                            • Les branches distantes
                            • Deacutepocircts distants multiples
                            • Mes preacutefeacuterences
                              • La maicirctrise de Git
                                • Publication de sources
                                • Geacuterer le changement
                                • Mon commit est trop gros
                                • Lindex laire dassemblage
                                • Ne perdez pas la tecircte
                                • Chasseur de tecircte
                                • Construire au-dessus de Git
                                • Audacieuses acrobaties
                                • Se preacutemunir des commits erroneacutes
                                  • Les secrets reacuteveacuteleacutes
                                    • Linvisibiliteacute
                                    • Linteacutegriteacute
                                    • Lintelligence
                                    • Lindexation
                                    • Les origines de Git
                                    • La base dobjets
                                    • Les blobs
                                    • Les arbres (trees)
                                    • Les commits
                                    • Indiscernable de la magie
                                      • Appendix A Les lacunes de Git
                                        • Les faiblesses de SHA1
                                        • Microsoft Windows
                                        • Des fichiers sans relation
                                        • Qui modifie quoi
                                        • Lhistorique dun fichier
                                        • Le clone initial
                                        • Les projets versatiles
                                        • Compteur global
                                        • Les dossiers vides
                                        • Le premier commit
                                        • Bizarreries de linterface
                                          • Appendix B Traduire ce guide