git magique - blynn/gitmagic/intl/fr/book.pdf · git magique ben lynn août 2007 préface...
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
-