Git 🌙
Chapters â–Ÿ 2nd Edition

5.3 Git distribuĂ© - Maintenance d’un projet

Maintenance d’un projet

En plus de savoir comment contribuer efficacement Ă  un projet, vous aurez probablement besoin de savoir comment en maintenir un. Cela peut consister Ă  accepter et appliquer les patchs gĂ©nĂ©rĂ©s via format-patch et envoyĂ©s par courriel, ou Ă  intĂ©grer des modifications dans des branches distantes de dĂ©pĂŽts distants. Que vous mainteniez le dĂ©pĂŽt de rĂ©fĂ©rence ou que vous souhaitiez aider en vĂ©rifiant et approuvant les patchs, vous devez savoir comment accepter les contributions d’une maniĂšre limpide pour vos contributeurs et soutenable Ă  long terme pour vous.

Travail dans des branches thématiques

Quand vous vous apprĂȘtez Ă  intĂ©grer des contributions, une bonne idĂ©e consiste Ă  les essayer d’abord dans une branche thĂ©matique, une branche temporaire spĂ©cifiquement crĂ©Ă©e pour essayer cette nouveautĂ©. De cette maniĂšre, il est plus facile de rectifier un patch Ă  part et de le laisser s’il ne fonctionne pas jusqu’à ce que vous disposiez de temps pour y travailler. Si vous crĂ©ez une simple branche nommĂ©e d’aprĂšs le thĂšme de la modification que vous allez essayer, telle que ruby_client ou quelque chose d’aussi descriptif, vous pouvez vous en souvenir simplement plus tard. Le mainteneur du projet Git a l’habitude d’utiliser des espaces de nommage pour ses branches, tels que sc/ruby_client, oĂč sc reprĂ©sente les initiales de la personne qui a fourni le travail. Comme vous devez vous en souvenir, on crĂ©e une branche Ă  partir de master de la maniĂšre suivante :

$ git branch sc/ruby_client master

Ou bien, si vous voulez aussi basculer immĂ©diatement dessus, vous pouvez utiliser l’option checkout -b :

$ git checkout -b sc/ruby_client master

Vous voilĂ  maintenant prĂȘt Ă  ajouter les modifications sur cette branche thĂ©matique et Ă  dĂ©terminer si c’est prĂȘt Ă  ĂȘtre fusionnĂ© dans les branches au long cours.

Application des patchs Ă  partir de courriel

Si vous recevez un patch par courriel et que vous devez l’intĂ©grer dans votre projet, vous devez l’appliquer dans une branche thĂ©matique pour l’évaluer. Il existe deux moyens d’appliquer un patch reçu par courriel : git apply et git am.

Application d’un patch avec apply

Si vous avez reçu le patch de quelqu’un qui l’a gĂ©nĂ©rĂ© avec la commande git diff ou diff Unix, vous pouvez l’appliquer avec la commande git apply. Si le patch a Ă©tĂ© sauvĂ© comme fichier /tmp/patch-ruby-client.patch, vous pouvez l’appliquer comme ceci :

$ git apply /tmp/patch-ruby-client.patch

Les fichiers dans votre copie de travail sont modifiĂ©s. C’est quasiment identique Ă  la commande patch -p1 qui applique directement les patchs mais en plus paranoĂŻaque et moins tolĂ©rant sur les concordances approximatives. Les ajouts, effacements et renommages de fichiers sont aussi gĂ©rĂ©s s’ils sont dĂ©crits dans le format git diff, ce que patch ne supporte pas. Enfin, git apply fonctionne en mode « applique tout ou refuse tout » dans lequel toutes les modifications proposĂ©es sont appliquĂ©es si elles le peuvent, sinon rien n’est modifiĂ©, lĂ  oĂč patch peut n’appliquer que partiellement les patchs, laissant le rĂ©pertoire de travail dans un Ă©tat intermĂ©diaire. git apply est par-dessus tout plus paranoĂŻaque que patch. Il ne crĂ©era pas une validation Ă  votre place : aprĂšs l’avoir lancĂ©, vous devrez indexer et valider les modifications manuellement.

Vous pouvez aussi utiliser git apply pour voir si un patch s’applique proprement avant de rĂ©ellement l’appliquer — vous pouvez lancer git apply --check avec le patch :

$ git apply --check 0001-seeing-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply

S’il n’y pas de message, le patch devrait s’appliquer proprement. Cette commande se termine avec un statut non-nul si la vĂ©rification Ă©choue et vous pouvez donc l’utiliser dans des scripts.

Application d’un patch avec am

Si le contributeur est un utilisateur de Git qui a Ă©tĂ© assez gentil d’utiliser la commande format-patch pour gĂ©nĂ©rer ses patchs, votre travail sera facilitĂ© car le patch contient alors dĂ©jĂ  l’information d’auteur et le message de validation. Si possible, encouragez vos contributeurs Ă  utiliser format-patch au lieu de patch pour gĂ©nĂ©rer les patchs qu’ils vous adressent. Vous ne devriez avoir Ă  n’utiliser git apply que pour les vrais patchs.

Pour appliquer un patch gĂ©nĂ©rĂ© par format-patch, vous utilisez git am. Techniquement, git am s’attend Ă  lire un fichier au format mbox, qui est un format texte simple permettant de stocker un ou plusieurs courriels dans un unique fichier texte. Il ressemble Ă  ceci :

From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

C’est le dĂ©but de ce que la commande format-patch affiche, comme vous avez vu dans la section prĂ©cĂ©dente. C’est aussi un format courriel mbox parfaitement valide. Si quelqu’un vous a envoyĂ© par courriel un patch correctement formatĂ© en utilisant git send-mail et que vous le tĂ©lĂ©chargez en format mbox, vous pouvez pointer git am sur ce fichier mbox et il commencera Ă  appliquer tous les patchs contenus. Si vous utilisez un client courriel qui sait sauver plusieurs messages au format mbox, vous pouvez sauver la totalitĂ© de la sĂ©rie de patchs dans un fichier et utiliser git am pour les appliquer tous en une fois.

NĂ©anmoins, si quelqu’un a dĂ©posĂ© un fichier de patch gĂ©nĂ©rĂ© via format-patch sur un systĂšme de suivi de faits techniques ou quelque chose de similaire, vous pouvez toujours sauvegarder le fichier localement et le passer Ă  git am pour l’appliquer :

$ git am 0001-limit-log-function.patch
Application : add limit to log function

Vous remarquez qu’il s’est appliquĂ© proprement et a crĂ©Ă© une nouvelle validation pour vous. L’information d’auteur est extraite des en-tĂȘtes From et Date tandis que le message de validation est repris du champ Subject et du corps (avant le patch) du message. Par exemple, si le patch est appliquĂ© depuis le fichier mbox ci-dessus, la validation gĂ©nĂ©rĂ©e ressemblerait Ă  ceci :

$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:     Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit:     Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700

   add limit to log function

   Limit log functionality to the first 20

L’information Commit indique la personne qui a appliquĂ© le patch et la date d’application. L’information Author indique la personne qui a crĂ©Ă© le patch et la date de crĂ©ation.

Il reste la possibilitĂ© que le patch ne s’applique pas proprement. Peut-ĂȘtre votre branche principale a-t’elle dĂ©jĂ  trop divergĂ© de la branche sur laquelle le patch a Ă©tĂ© construit, ou peut-ĂȘtre que le patch dĂ©pend d’un autre patch qui n’a pas encore Ă©tĂ© appliquĂ©. Dans ce cas, le processus de git am Ă©chouera et vous demandera ce que vous souhaitez faire :

$ git am 0001-seeing-if-this-helps-the-gem.patch
Application : seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Le patch a échoué à 0001.
Lorsque vous aurez résolu ce problÚme, lancez "git am --continue".
Si vous préférez sauter ce patch, lancez "git am --skip" à la place.
Pour restaurer la branche d'origine et stopper le patchage, lancez
"git am --abort".

Cette commande introduit des marqueurs de conflit dans tous les fichiers qui ont gĂ©nĂ©rĂ© un problĂšme, de la mĂȘme maniĂšre qu’un conflit de fusion ou de rebasage. Vous pouvez rĂ©soudre les problĂšmes de maniĂšre identique — Ă©ditez le fichier pour rĂ©soudre les conflits, indexez le nouveau fichier, puis lancez git am --resolved ou git am --continue pour continuer avec le patch suivant :

$ (correction du fichier)
$ git add ticgit.gemspec
$ git am --continue
Applying: seeing if this helps the gem

Si vous souhaitez que Git essaie de rĂ©soudre les conflits avec plus d’intelligence, vous pouvez passer l’option -3 qui demande Ă  Git de tenter une fusion Ă  trois sources. Cette option n’est pas active par dĂ©faut parce qu’elle ne fonctionne pas si le commit sur lequel le patch indique ĂȘtre basĂ© n’existe pas dans votre dĂ©pĂŽt. Si par contre, le patch est basĂ© sur un commit public, l’option -3 est gĂ©nĂ©ralement beaucoup plus fine pour appliquer des patchs conflictuels :

$ git am -3 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.

Dans ce cas, je cherchais Ă  appliquer un patch qui avait dĂ©jĂ  Ă©tĂ© intĂ©grĂ©. Sans l’option -3, cela aurait ressemblĂ© Ă  un conflit.

Si vous appliquez des patchs Ă  partir d’un fichier mbox, vous pouvez aussi lancer la commande am en mode interactif qui s’arrĂȘte Ă  chaque patch trouvĂ© et vous demande si vous souhaitez l’appliquer :

$ git am -3 -i mbox
Commit Body is:
--------------------------
seeing if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

C’est agrĂ©able si vous avez un certain nombre de patchs sauvegardĂ©s parce que vous pouvez voir les patchs pour vous rafraĂźchir la mĂ©moire et ne pas les appliquer s’ils ont dĂ©jĂ  Ă©tĂ© intĂ©grĂ©s.

Quand tous les patchs pour votre sujet ont été appliqués et validés dans votre branche, vous pouvez choisir si et comment vous souhaitez les intégrer dans une branche au long cours.

VĂ©rification des branches distantes

Si votre contribution a Ă©tĂ© fournie par un utilisateur de Git qui a mis en place son propre dĂ©pĂŽt public sur lequel il a poussĂ© ses modifications et vous a envoyĂ© l’URL du dĂ©pĂŽt et le nom de la branche distante, vous pouvez les ajouter en tant que dĂ©pĂŽt distant et rĂ©aliser les fusions localement.

Par exemple, si Jessica vous envoie un courriel indiquant qu’elle a une nouvelle fonctionnalitĂ© gĂ©niale dans la branche ruby-client de son dĂ©pĂŽt, vous pouvez la tester en ajoutant le dĂ©pĂŽt distant et en tirant la branche localement :

$ git remote add jessica git://github.com/jessica/monproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client

Si elle vous envoie un autre mail indiquant une autre branche contenant une autre fonctionnalité géniale, vous pouvez la récupérer et la tester simplement à partir de votre référence distante.

C’est d’autant plus utile si vous travaillez en continu avec une personne. Si quelqu’un n’a qu’un seul patch Ă  contribuer de temps en temps, l’accepter via courriel peut s’avĂ©rer moins consommateur en temps de prĂ©paration du serveur public, d’ajout et retrait de branches distantes juste pour tirer quelques patchs. Vous ne souhaiteriez sĂ»rement pas devoir gĂ©rer des centaines de dĂ©pĂŽts distants pour intĂ©grer Ă  chaque fois un ou deux patchs. NĂ©anmoins, des scripts et des services hĂ©bergĂ©s peuvent rendre cette tĂąche moins ardue. Cela dĂ©pend largement de votre maniĂšre de dĂ©velopper et de celle de vos contributeurs.

Cette approche a aussi l’avantage de vous fournir l’historique des validations. MĂȘme si vous pouvez rencontrer des problĂšmes de fusion lĂ©gitimes, vous avez l’information dans votre historique de la base ayant servi pour les modifications contribuĂ©es. La fusion Ă  trois sources est choisie par dĂ©faut plutĂŽt que d’avoir Ă  spĂ©cifier l’option -3 en espĂ©rant que le patch a Ă©tĂ© gĂ©nĂ©rĂ© Ă  partir d’un instantanĂ© public auquel vous auriez accĂšs.

Si vous ne travaillez pas en continu avec une personne mais souhaitez tout de mĂȘme tirer les modifications de cette maniĂšre, vous pouvez fournir l’URL du dĂ©pĂŽt distant Ă  la commande git pull. Cela permet de rĂ©aliser un tirage unique sans sauver l’URL comme rĂ©fĂ©rence distante :

$ git pull https://github.com/pourunefois/projet
From https://github.com/onetimeguy/project
 * branch            HEAD       -> FETCH_HEAD
Merge made by recursive.

DĂ©terminer les modifications introduites

Vous avez maintenant une branche thĂ©matique qui contient les contributions. À partir de lĂ , vous pouvez dĂ©terminer ce que vous souhaitez en faire. Cette section revisite quelques commandes qui vont vous permettre de faire une revue de ce que vous allez exactement introduire si vous fusionnez dans la branche principale.

Faire une revue de tous les commits dans cette branche s’avĂšre souvent d’une grande aide. Vous pouvez exclure les commits de la branche master en ajoutant l’option --not devant le nom de la branche. C’est Ă©quivalent au format master..contrib utilisĂ© plus haut. Par exemple, si votre contributeur vous envoie deux patchs et que vous crĂ©ez une branche appelĂ©e contrib et y appliquez ces patchs, vous pouvez lancer ceci :

$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Oct 24 09:53:59 2008 -0700

    seeing if this helps the gem

commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date:   Mon Oct 22 19:38:36 2008 -0700

    updated the gemspec to hopefully work better

Pour visualiser les modifications que chaque commit introduit, souvenez-vous que vous pouvez passer l’option -p à git log et elle ajoutera le diff introduit à chaque commit.

Pour visualiser un diff complet de ce qui arriverait si vous fusionniez cette branche thématique avec une autre branche, vous pouvez utiliser un truc bizarre pour obtenir les résultats corrects. Vous pourriez penser à lancer ceci :

$ git diff master

Cette commande affiche un diff mais elle peut ĂȘtre trompeuse. Si votre branche master a avancĂ© depuis que vous avez crĂ©Ă© la branche thĂ©matique, vous obtiendrez des rĂ©sultats apparemment Ă©tranges. Cela arrive parce que Git compare directement l’instantanĂ© de la derniĂšre validation sur la branche thĂ©matique et celui de la derniĂšre validation sur la branche master. Par exemple, si vous avez ajoutĂ© une ligne dans un fichier sur la branche master, une comparaison directe donnera l’impression que la branche thĂ©matique va retirer cette ligne.

Si master est un ancĂȘtre directe de la branche thĂ©matique, ce n’est pas un problĂšme. Si les deux historiques ont divergĂ©, le diff donnera l’impression que vous ajoutez toutes les nouveautĂ©s de la branche thĂ©matique et retirez tout ce qui a Ă©tĂ© fait depuis dans la branche master.

Ce que vous souhaitez voir en fait, ce sont les modifications ajoutĂ©es sur la branche thĂ©matique — le travail que vous introduirez si vous fusionnez cette branche dans master. Vous obtenez ce rĂ©sultat en demandant Ă  Git de comparer le dernier instantanĂ© de la branche thĂ©matique avec son ancĂȘtre commun Ă  la branche master le plus rĂ©cent.

Techniquement, c’est rĂ©alisable en dĂ©terminant exactement l’ancĂȘtre commun et en lançant la commande diff dessus :

$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

ou de maniÚre plus concise :

$ git diff $(git merge-base contrib master)

NĂ©anmoins, comme ce n’est pas trĂšs commode, Git fournit un raccourci pour rĂ©aliser la mĂȘme chose : la syntaxe Ă  trois points. Dans le contexte de la commande diff, vous pouvez placer trois points aprĂšs une autre branche pour rĂ©aliser un diff entre le dernier instantanĂ© de la branche sur laquelle vous vous trouvez et son ancĂȘtre commun avec une autre branche :

$ git diff master...contrib

Cette commande ne vous montre que les modifications que votre branche thĂ©matique a introduites depuis son ancĂȘtre commun avec master. C’est une syntaxe trĂšs simple Ă  retenir.

Intégration des contributions

Lorsque tout le travail de votre branche thĂ©matique est prĂȘt Ă  ĂȘtre intĂ©grĂ© dans la branche principale, il reste Ă  savoir comment le faire. De plus, il faut connaĂźtre le mode de gestion que vous souhaitez pour votre projet. Vous avez de nombreux choix et je vais en traiter quelques-uns.

Modes de fusion

Un mode simple fusionne votre travail dans la branche master. Dans ce scĂ©nario, vous avez une branche master qui contient le code stable. Quand vous avez des modifications prĂȘtes dans une branche thĂ©matique, vous la fusionnez dans votre branche master puis effacez la branche thĂ©matique, et ainsi de suite. Si vous avez un dĂ©pĂŽt contenant deux branches nommĂ©es ruby_client et php_client qui ressemble Ă  Historique avec quelques branches thĂ©matiques. et que vous fusionnez ruby_client en premier, suivi de php_client, alors votre historique ressemblera Ă  la fin Ă  AprĂšs fusion des branches thĂ©matiques..

Historique avec quelques branches thématiques.
Figure 72. Historique avec quelques branches thématiques.
AprÚs fusion des branches thématiques.
Figure 73. AprÚs fusion des branches thématiques.

C’est probablement le mode le plus simple mais cela peut s’avĂ©rer problĂ©matique si vous avez Ă  gĂ©rer des dĂ©pĂŽts ou des projets plus gros pour lesquels vous devez ĂȘtre circonspect sur ce que vous acceptez.

Si vous avez plus de dĂ©veloppeurs ou un projet plus important, vous souhaiterez probablement utiliser un cycle de fusion Ă  deux Ă©tapes. Dans ce scĂ©nario, vous avez deux branches au long cours, master et develop, dans lequel vous dĂ©terminez que master est mis Ă  jour seulement lors d’une version vraiment stable et tout le nouveau code est intĂ©grĂ© dans la branche develop. Vous poussez rĂ©guliĂšrement ces deux branches sur le dĂ©pĂŽt public. Chaque fois que vous avez une nouvelle branche thĂ©matique Ă  fusionner (Avant la fusion d’une branche thĂ©matique.), vous la fusionnez dans develop (AprĂšs la fusion d’une branche thĂ©matique.). Puis, lorsque vous Ă©tiquetez une version majeure, vous mettez master Ă  niveau avec l’état stable de develop en avance rapide (AprĂšs une publication d’une branche thĂ©matique.).

Avant la fusion d’une branche thĂ©matique.
Figure 74. Avant la fusion d’une branche thĂ©matique.
AprĂšs la fusion d’une branche thĂ©matique.
Figure 75. AprĂšs la fusion d’une branche thĂ©matique.
AprĂšs une publication d’une branche thĂ©matique.
Figure 76. AprĂšs une publication d’une branche thĂ©matique.

Ainsi, lorsque l’on clone le dĂ©pĂŽt de votre projet, on peut soit extraire la branche master pour construire la derniĂšre version stable et mettre Ă  jour facilement ou on peut extraire la branche develop qui reprĂ©sente le nec plus ultra du dĂ©veloppement.

Vous pouvez aussi continuer ce concept avec une branche d’intĂ©gration oĂč tout le travail est fusionnĂ©. Alors, quand la base de code sur cette branche est stable et que les tests passent, vous la fusionnez dans la branche develop. Quand cela s’est avĂ©rĂ© stable pendant un certain temps, vous mettez Ă  jour la branche master en avance rapide.

Gestions avec nombreuses fusions

Le projet Git dispose de quatre branches au long cours : master, next, pu (proposed updates : propositions) pour les nouveaux travaux et maint pour les backports de maintenance. Quand une nouvelle contribution est proposĂ©e, elle est collectĂ©e dans des branches thĂ©matiques dans le dĂ©pĂŽt du mainteneur d’une maniĂšre similaire Ă  ce que j’ai dĂ©crit (SĂ©rie complexe de branches thĂ©matiques contribuĂ©es en parallĂšle.). À ce point, les fonctionnalitĂ©s sont Ă©valuĂ©es pour dĂ©terminer si elles sont stables et prĂȘtes Ă  ĂȘtre consommĂ©es ou si elles nĂ©cessitent un peaufinage. Si elles sont stables, elles sont fusionnĂ©es dans next et cette branche est poussĂ©e sur le serveur public pour que tout le monde puisse essayer les fonctionnalitĂ©s intĂ©grĂ©es ensemble.

Série complexe de branches thématiques contribuées en parallÚle.
Figure 77. Série complexe de branches thématiques contribuées en parallÚle.

Si les fonctionnalitĂ©s nĂ©cessitent encore du travail, elles sont fusionnĂ©es plutĂŽt dans pu. Quand elles sont considĂ©rĂ©es comme totalement stables, elles sont re-fusionnĂ©es dans master et sont alors reconstruites Ă  partir des fonctionnalitĂ©s qui rĂ©sidaient dans next mais n’ont pu intĂ©grer master. Cela signifie que master Ă©volue quasiment toujours en mode avance rapide, tandis que next est rebasĂ© assez souvent et pu est rebasĂ© encore plus souvent :

Fusion des branches thématiques dans les branches à long terme.
Figure 78. Fusion des branches thématiques dans les branches à long terme.

Quand une branche thĂ©matique a finalement Ă©tĂ© fusionnĂ©e dans master, elle est effacĂ©e du dĂ©pĂŽt. Le projet Git a aussi une branche maint qui est crĂ©Ă©e Ă  partir de la derniĂšre version pour fournir des patchs correctifs en cas de besoin de version de maintenance. Ainsi, quand vous clonez le dĂ©pĂŽt de Git, vous avez quatre branches disponibles pour Ă©valuer le projet Ă  diffĂ©rentes Ă©tapes de dĂ©veloppement, selon le niveau de dĂ©veloppement que vous souhaitez utiliser ou pour lequel vous souhaitez contribuer. Le mainteneur a une gestion structurĂ©e qui lui permet d’évaluer et sĂ©lectionner les nouvelles contributions.

Gestion par rebasage et sélection de commit

D’autres mainteneurs prĂ©fĂšrent rebaser ou sĂ©lectionner les contributions sur le sommet de la branche master, plutĂŽt que les fusionner, de maniĂšre Ă  conserver un historique Ă  peu prĂšs linĂ©aire. Lorsque plusieurs modifications sont prĂ©sentes dans une branche thĂ©matique et que vous souhaitez les intĂ©grer, vous vous placez sur cette branche et vous lancez la commande rebase pour reconstruire les modifications Ă  partir du sommet courant de la branche master (ou develop, ou autre). Si cela fonctionne correctement, vous pouvez faire une avance rapide sur votre branche master et vous obtenez finalement un historique de projet linĂ©aire.

L’autre moyen de dĂ©placer des modifications introduites dans une branche vers une autre consiste Ă  les sĂ©lectionner ou les picorer (cherry-pick). Un picorage dans Git ressemble Ă  un rebasage appliquĂ© Ă  un commit unique. Cela consiste Ă  prendre le patch qui a Ă©tĂ© introduit lors d’une validation et Ă  essayer de l’appliquer sur la branche sur laquelle on se trouve. C’est trĂšs utile si on a un certain nombre de commits sur une branche thĂ©matique et que l’on veut n’en intĂ©grer qu’un seul, ou si on n’a qu’un commit sur une branche thĂ©matique et qu’on prĂ©fĂšre le sĂ©lectionner plutĂŽt que de lancer rebase. Par exemple, supposons que vous ayez un projet ressemblant Ă  ceci :

Historique d’exemple avant une sĂ©lection.
Figure 79. Historique d’exemple avant une sĂ©lection.

Si vous souhaitez tirer le commit e43a6 dans votre branche master, vous pouvez lancer :

$ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
 3 files changed, 17 insertions(+), 3 deletions(-)

La mĂȘme modification que celle introduite en e43a6 est tirĂ©e mais vous obtenez une nouvelle valeur de SHA-1 car les dates d’application sont diffĂ©rentes. À prĂ©sent, votre historique ressemble Ă  ceci :

Historique aprĂšs sĂ©lection d’un _commit_ dans une branche thĂ©matique.
Figure 80. Historique aprĂšs sĂ©lection d’un commit dans une branche thĂ©matique.

Maintenant, vous pouvez effacer votre branche thĂ©matique et abandonner les commits que vous n’avez pas tirĂ©s dans master.

Rerere

Si vous fusionnez et rebasez beaucoup ou si vous maintenez une branche au long cours, la fonctionnalitĂ© appelĂ©e « rerere » peut s’avĂ©rer utile.

Rerere signifie « rĂ© utiliser les rĂ© solutions en re gistrĂ©es » (“ reuse recorded resolution ”) ‑ c’est un moyen de raccourcir les rĂ©solutions manuelles de conflit. Quand rerere est actif, Git va conserver un jeu de couples d’images prĂ© et post fusion des fichiers ayant prĂ©sentĂ© des conflits, puis s’il s’aperçoit qu’un conflit ressemble Ă  une de ces rĂ©solutions, il va utiliser la mĂȘme stratĂ©gie sans rien vous demander.

Cette fonctionnalitĂ© se traite en deux phases : une Ă©tape de configuration et une commande. L’étape de configuration est rerere.enabled qui active la fonction et qu’il est facile de placer en config globale :

$ git config --global rerere.enabled true

Ensuite, quand vous fusionnez en résolvant des conflits, la résolution sera enregistrée dans le cache pour un usage futur.

Si besoin, vous pouvez interagir avec le cache rerere au moyen de la commande git rerere. Quand elle est invoquĂ©e telle quelle, Git vĂ©rifie sa base de donnĂ©es de rĂ©solutions et essaie de trouver une correspondance avec les conflits en cours et les rĂ©sout (bien que ce soit automatique si rerere.enabled est Ă  true). Il existe aussi des sous-commandes permettant de voir ce qui sera enregistrĂ©, d’effacer du cache une rĂ©solution spĂ©cifique ou d’effacer entiĂšrement le cache. rerere est traitĂ© plus en dĂ©tail dans Rerere.

Étiquetage de vos publications

Quand vous dĂ©cidez de crĂ©er une publication de votre projet, vous souhaiterez probablement Ă©tiqueter le projet pour pouvoir recrĂ©er cette version dans le futur. Vous pouvez crĂ©er une nouvelle Ă©tiquette (tag) telle que dĂ©crite dans Les bases de Git. Si vous dĂ©cidez de signer l’étiquette en tant que mainteneur, la commande ressemblera Ă  ceci :

$ git tag -s v1.5 -m 'mon etiquette v1.5 signée'
Une phrase secrÚte est nécessaire pour déverrouiller la clef secrÚte de
l'utilisateur : "Scott Chacon <schacon@gmail.com>"
clé DSA de 1024 bits, identifiant F721C45A, créée le 2009-02-09

Si vous signez vos Ă©tiquettes, vous rencontrerez le problĂšme de la distribution de votre clĂ© publique PGP permettant de vĂ©rifier la signature. Le mainteneur du projet Git a rĂ©solu le problĂšme en incluant la clĂ© publique comme blob dans le dĂ©pĂŽt et en ajoutant une Ă©tiquette qui pointe directement sur ce contenu. Pour faire de mĂȘme, vous dĂ©terminez la clĂ© de votre trousseau que vous voulez publier en lançant gpg --list-keys :

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid                  Scott Chacon <schacon@gmail.com>
sub   2048g/45D02282 2009-02-09 [expires: 2010-02-09]

Ensuite, vous pouvez importer la clĂ© directement dans la base de donnĂ©es Git en l’exportant de votre trousseau et en la redirigeant dans git hash-object qui Ă©crit un nouveau blob avec son contenu dans Git et vous donne en sortie le SHA-1 du blob :

$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92

À prĂ©sent, vous avez le contenu de votre clĂ© dans Git et vous pouvez crĂ©er une Ă©tiquette qui pointe directement dessus en spĂ©cifiant la valeur SHA-1 que la commande hash-object vous a fournie :

$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92

Si vous lancez git push --tags, l’étiquette maintainer-pgp-pub sera partagĂ©e publiquement. Un tiers pourra vĂ©rifier une Ă©tiquette aprĂšs import direct de votre clĂ© publique PGP, en extrayant le blob de la base de donnĂ©e et en l’important dans GPG :

$ git show maintainer-pgp-pub | gpg --import

Il pourra alors utiliser cette clĂ© pour vĂ©rifier vos Ă©tiquettes signĂ©es. Si de plus, vous incluez des instructions d’utilisation pour la vĂ©rification de signature dans le message d’étiquetage, l’utilisateur aura accĂšs Ă  ces informations en lançant la commande git show <Ă©tiquette>.

GĂ©nĂ©ration d’un nom de rĂ©vision

Comme Git ne fournit pas par nature de nombres croissants tels que « r123 » Ă  chaque validation, la commande git describe permet de gĂ©nĂ©rer un nom humainement lisible pour chaque commit. Git concatĂšne le nom de l’étiquette la plus proche, le nombre de validations depuis cette Ă©tiquette et un code SHA-1 partiel du commit que l’on cherche Ă  dĂ©finir :

$ git describe master
v1.6.2-rc1-20-g8c5b85c

De cette maniĂšre, vous pouvez exporter un instantanĂ© ou le construire et le nommer de maniĂšre intelligible. En fait, si Git est construit Ă  partir du source clonĂ© depuis le dĂ©pĂŽt Git, git --version vous donne exactement cette valeur. Si vous demandez la description d’un instantanĂ© qui a Ă©tĂ© Ă©tiquetĂ©, le nom de l’étiquette est retournĂ©.

La commande git describe repose sur les Ă©tiquettes annotĂ©es (Ă©tiquettes crĂ©Ă©es avec les options -a ou -s). Les Ă©tiquettes de publication doivent donc ĂȘtre crĂ©Ă©es de cette maniĂšre si vous souhaitez utiliser git describe pour garantir que les commits seront dĂ©crits correctement. Vous pouvez aussi utiliser ces noms comme cible lors d’une extraction ou d’une commande show, bien qu’ils reposent sur le SHA-1 abrĂ©gĂ© et pourraient ne pas rester valides indĂ©finiment. Par exemple, le noyau Linux a sautĂ© derniĂšrement de 8 Ă  10 caractĂšres pour assurer l’unicitĂ© des objets SHA-1 et les anciens noms git describe sont par consĂ©quent devenus invalides.

PrĂ©paration d’une publication

Maintenant, vous voulez publier une version. Une des Ă©tapes consiste Ă  crĂ©er une archive du dernier instantanĂ© de votre code pour les malheureux qui n’utilisent pas Git. La commande dĂ©diĂ©e Ă  cette action est git archive :

$ git archive master --prefix='projet/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz

Lorsqu’on ouvre l’archive, on obtient le dernier instantanĂ© du projet sous un rĂ©pertoire projet. On peut aussi crĂ©er une archive au format zip de maniĂšre similaire en passant l’option --format=zip Ă  la commande git archive :

$ git archive master --prefix='project/' --format=zip > `git describe master`.zip

VoilĂ  deux belles archives tar.gz et zip de votre projet prĂȘtes Ă  ĂȘtre tĂ©lĂ©chargĂ©es sur un site web ou envoyĂ©es par courriel.

Shortlog

Il est temps d’envoyer une annonce Ă  la liste de diffusion des nouveautĂ©s de votre projet. Une maniĂšre simple d’obtenir rapidement une sorte de liste des modifications depuis votre derniĂšre version ou courriel est d’utiliser la commande git shortlog. Elle rĂ©sume toutes les validations dans l’intervalle que vous lui spĂ©cifiez. Par exemple, ce qui suit vous donne un rĂ©sumĂ© de toutes les validations depuis votre derniĂšre version si celle-ci se nomme v1.0.1 :

$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (8):
      Add support for annotated tags to Grit::Tag
      Add packed-refs annotated tag support.
      Add Grit::Commit#to_patch
      Update version and History.txt
      Remove stray `puts`
      Make ls_tree ignore nils

Tom Preston-Werner (4):
      fix dates in history
      dynamic version method
      Version bump to 1.0.2
      Regenerated gemspec for version 1.0.2

Vous obtenez ainsi un rĂ©sumĂ© clair de toutes les validations depuis v1.0.1, regroupĂ©es par auteur, prĂȘt Ă  ĂȘtre envoyĂ© sur la liste de diffusion.

scroll-to-top