hgbook

view fr/ch03-tour-merge.xml @ 979:64475a75365b

Merged from rpelisse
author Jean-Marie Clément <JeanMarieClement@web.de>
date Fri Sep 04 18:24:06 2009 +0200 (2009-09-04)
parents
children 713f0f69029a
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <chapter>
4 <title>Un rapide tour de Mercurial: fusionner les travaux</title>
5 <para>\label{chap:tour-merge}</para>
7 <para>Nous avons maintenant étudié comment cloner un dépôt, effectuer
8 des changements dedans, et récupérer ou transférer depuis un
9 autre dépôt. La prochaine étape est donc de <emphasis>fusionner</emphasis> les
10 modifications de différents dépôts.</para>
12 <sect1>
13 <title>Fusionner différents travaux</title>
14 <para> %%% for 'Merging streams of work' ?
15 La fusion\footnote{NdT: Je garde fusion mais le jargon professionnel
16 emploiera généralement le terme \textit{merge}.} est un aspect
17 fondamental lorsqu'on travaille avec un gestionnaire de source
18 distribué.</para>
19 <itemizedlist>
20 <listitem><para>Alice et Bob ont chacun une copie personnelle du dépôt d'un
21 projet sur lequel ils collaborent. Alice corrige un \textit{bug}
22 dans son dépôt, et Bob ajoute une nouvelle fonctionnalité dans le
23 sien. Ils veulent un dépôt partagé avec à la fois le correctif du
24 \textit{bug} et la nouvelle fonctionnalité.</para>
25 </listitem>
26 <listitem><para>Je travaille régulièrement sur plusieurs tâches différentes sur
27 un seul projet en même temps, chacun isolé dans son propre dépôt.
28 Travailler ainsi signifie que je dois régulièrement fusionner une
29 partie de mon code avec celui des autres.</para>
30 </listitem></itemizedlist>
32 <para>Parce que la fusion est une opération si commune à réaliser,
33 Mercurial la rend facile. Étudions ensemble le déroulement des opérations.
34 Nous commencerons encore par faire un clone d'un autre dépôt (vous voyez
35 que l'on fait ça tout le temps ?) puis nous ferons quelques modifications
36 dessus.
37 <!-- &interaction.tour.merge.clone; -->
38 Nous devrions avoir maintenant deux copies de <filename>hello.c</filename> avec
39 des contenus différents. Les historiques de ces deux dépôts ont aussi
40 divergés, comme illustré dans la figure <xref linkend="fig:tour-merge:sep-repos"/>.</para>
42 <para><!-- &interaction.tour.merge.cat; --></para>
44 <informalfigure>
46 <para> <mediaobject><imageobject><imagedata fileref="tour-merge-sep-repos"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
47 <caption><para>Historiques récent divergents des dépôts \dirname{my-hello</para></caption>
48 et <filename class="directory">my-new-hello</filename>}
49 \label{fig:tour-merge:sep-repos}</para>
50 </informalfigure>
52 <para>Nous savons déjà que récupérer les modifications depuis notre dépôt
53 <filename class="directory">my-hello</filename> n'aura aucun effet sur l'espace de travail.
54 </para>
56 <para><!-- &interaction.tour.merge.pull; -->
57 </para>
59 <para>Néanmoins, la commande <command role="hg-cmd">hg pull</command> nous indique quelque chose au
60 sujet des <quote>heads</quote>.
61 </para>
63 <sect2>
64 <title>\textit{Head changesets}</title>
66 <para>Une \textit{head}\footnote{NdT: Je garde \textit{head} que j'accorde
67 au féminin comme la coutume orale l'a imposé.} est un \textit{changeset}
68 sans descendants, ou enfants, comme on les désigne parfois. La révision
69 \textit{tip} est une \textit{head}, car la dernière révision dans un dépôt
70 n'a aucun enfant, mais il est important de noter qu'un dépôt peut contenir
71 plus d'une \textit{head}.
72 </para>
74 <informalfigure>
76 <para> <mediaobject><imageobject><imagedata fileref="tour-merge-pull"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
77 \caption{Contenu d'un dépôt après avoir transféré le contenu du dépôt
78 <filename class="directory">my-hello</filename> dans le dépôt <filename class="directory">my-new-hello</filename>}
79 \label{fig:tour-merge:pull}
80 </para>
81 </informalfigure>
83 <para>Dans la figure <xref linkend="fig:tour-merge:pull"/>, vous pouvez constater l'effet
84 d'un \textit{pull} depuis le dépôt <filename class="directory">my-hello</filename> dans le dépôt
85 <filename class="directory">my-new-hello</filename>. L'historique qui était déjà présent dans le dépôt
86 <filename class="directory">my-new-hello</filename> reste intact, mais une nouvelle révision a été
87 ajoutée. En vous reportant à la figure <xref linkend="fig:tour-merge:sep-repos"/>,
88 vous pouvez voir que le \textit{<emphasis>changeset ID</emphasis>} reste le même dans
89 le nouveau dépôt, mais que le <emphasis>numéro de révision</emphasis> reste le même.
90 (Ceci est un parfait exemple de pourquoi il n'est fiable d'utiliser les
91 numéros de révision lorsque l'on discute d'un \textit{changeset}.) Vous
92 pouvez voir les \texit{heads} présentes dans le dépôt en utilisant la
93 commande <command role="hg-cmd">hg heads</command>.
94 <!-- &interaction.tour.merge.heads; -->
95 </para>
97 </sect2>
98 <sect2>
99 <title>Effectuer la fusion</title>
101 <para>Que se passe-t-il quand vous essayez d'utiliser la commande <command role="hg-cmd">hg update</command>
102 pour mettre à jour votre espace de travail au nouveau \textit{tip}.
103 <!-- &interaction.tour.merge.update; -->
104 Mercurial nous prévient que la commande <command role="hg-cmd">hg update</command> n'effectuera pas
105 la fusion, il ne veut pas mettre à jour l'espace de travail quand il
106 estime que nous pourrions avoir besoin d'une fusion, à moins de lui
107 forcer la main. À la place, il faut utiliser la commande <command role="hg-cmd">hg merge</command>
108 pour fusionner les deux \textit{heads}.
109 <!-- &interaction.tour.merge.merge; -->
110 </para>
112 <informalfigure>
114 <para> <mediaobject><imageobject><imagedata fileref="tour-merge-merge"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
115 \caption{Espace de travail et dépôt lors d'une fusion, et dans le
116 \textit{commit} qui suit.}
117 \label{fig:tour-merge:merge}
118 </para>
119 </informalfigure>
121 <para>Ceci met à jour l'espace de travail de manière à ce qu'il contienne
122 les modifications des <emphasis>deux</emphasis> \textit{heads}, ce qui apparaît dans
123 les sorties de la commande <command role="hg-cmd">hg parents</command> et le contenu de
124 <filename>hello.c</filename>.
125 <!-- &interaction.tour.merge.parents; -->
126 </para>
128 </sect2>
129 <sect2>
130 <title>Effectuer le \textit{commit} du résultat de la fusion</title>
132 <para>Dès l'instant où vous avez effectué une fusion, <command role="hg-cmd">hg parents</command> vous
133 affichera deux parents, avant que vous n'exécutiez la commande
134 <command role="hg-cmd">hg commit</command> sur le résultat de la fusion.
135 <!-- &interaction.tour.merge.commit; -->
136 Nous avons maintenant un nouveau \textit{tip}, remarquer qu'il contient
137 <emphasis>à la fois</emphasis> nos anciennes \textit{heads} et leurs parents. Ce sont
138 les mêmes révisions que nous avions affichées avec la commande
139 <command role="hg-cmd">hg parents</command>.
140 </para>
142 <para><!-- &interaction.tour.merge.tip; -->
143 Dans la figure <xref linkend="fig:tour-merge:merge"/>, vous pouvez voir une représentation
144 de ce qui se passe dans l'espace de travail pendant la fusion, et comment ceci
145 affecte le dépôt lors du \textit{commit}. Pendant la fusion, l'espace de travail,
146 qui a deux \texit{changesets} comme parents, voit ces derniers devenir le parent
147 %%% TODO: le parent ou "les parents" : plus logique mais si il reste seulement
148 %%% un changeset, alors c'est effectivement un parent (le changeset est hermaphrodite)
149 d'un nouveau \textit{changeset}.
150 </para>
152 </sect2>
153 </sect1>
154 <sect1>
155 <title>Fusionner les modifications en conflit</title>
157 <para>La plupart des fusions sont assez simple à réaliser, mais parfois
158 vous vous retrouverez à fusionner des fichiers où la modification touche
159 la même portion de code, au sein d'un même fichier. À moins que ces
160 modification ne soient identiques, ceci aboutira à un <emphasis>conflit</emphasis>,
161 et vous devrez décider comment réconcilier les différentes modifications
162 dans un tout cohérent.
163 </para>
165 <informalfigure>
167 <para> <mediaobject><imageobject><imagedata fileref="tour-merge-conflict"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
168 <caption><para>Modifications conflictuelles dans un document</para></caption>
169 \label{fig:tour-merge:conflict}
170 </para>
171 </informalfigure>
173 <para>La figure <xref linkend="fig:tour-merge:conflict"/> illustre un cas de modifications
174 conflictuelles dans un document. Nous avons commencé avec une version simple
175 de ce fichier, puis nous avons ajouté des modifications, pendant que
176 quelqu'un d'autre modifiait le même texte. Notre tâche dans la résolution
177 du conflit est de décider à quoi le fichier devrait ressembler.
178 </para>
180 <para>Mercurial n'a pas de mécanisme interne pour gérer les conflits.
181 À la place, il exécute un programme externe appelé <command>hgmerge</command>.
182 Il s'agit d'un script shell qui est embarqué par Mercurial, vous
183 pouvez le modifier si vous le voulez. Ce qu'il fait par défaut est
184 d'essayer de trouver un des différents outils de fusion qui seront
185 probablement installés sur le système. Il commence par les outils
186 totalement automatiques, et si ils échouent (parce que la résolution
187 du conflit nécessite une intervention humaine) ou si ils sont absents,
188 le script tente d'exécuter certains outils graphiques de fusion.
189 </para>
191 <para>Il est aussi possible de demander à Mercurial d'exécuter un autre
192 programme ou un autre script au lieu de la commande <command>hgmerge</command>,
193 en définissant la variable d'environnement <envar>HGMERGE</envar> avec le nom
194 du programme de votre choix.
195 </para>
197 <sect2>
198 <title>Utiliser un outil graphique de fusion</title>
200 <para>Mon outil de fusion préféré est <command>kdiff3</command>, que j'utilise ici
201 pour illustrer les fonctionnalités classiques des outils graphiques
202 de fusion. Vous pouvez voir une capture d'écran de l'utilisation de
203 <command>kdiff3</command> dans la figure <xref linkend="fig:tour-merge:kdiff3"/>. Cet outil
204 effectue une <emphasis>fusion \textit{three-way</emphasis>}, car il y a trois différentes
205 versions du fichier qui nous intéresse. Le fichier découpe la partie
206 supérieure de la fenêtre en trois panneaux:
207 </para>
209 <itemizedlist>
210 <listitem><para>A gauche on la version de <emphasis>base</emphasis> du fichier, soit la plus
211 récente version des deux versions qu'on souhaite fusionner.
212 </para>
213 </listitem>
214 <listitem><para>Au centre, il y a <quote>notre</quote> version du fichier, avec le contenu
215 que nous avons modifié.
216 </para>
217 </listitem>
218 <listitem><para>Sur la droite, on trouve <quote>leur</quote> version du fichier, celui qui
219 contient le \textit{changeset} que nous souhaitons intégré.
220 </para>
221 </listitem></itemizedlist>
223 <para>Dans le panneau en dessous, on trouve le <emphasis>résultat</emphasis> actuel de notre
224 fusion. Notre tâche consiste donc à remplacement tous les textes en rouges,
225 qui indiquent des conflits non résolus, avec une fusion manuelle et pertinente
226 de <quote>notre</quote> version et de la <quote>leur</quote>.
227 </para>
229 <para>Tous les quatre panneaux sont <emphasis>accrochés ensemble</emphasis>, si nous déroulons
230 les ascenseurs verticalement ou horizontalement dans chacun d'entre eux, les
231 autres sont mis à jour avec la section correspondante dans leurs fichiers
232 respectifs.
233 </para>
235 <informalfigure>
237 <para> <mediaobject><imageobject><imagedata fileref="kdiff3"/></imageobject><textobject><phrase>XXX add text</phrase></textobject></mediaobject>
238 <caption><para>Utilisation de \command{kdiff3</para></caption> pour fusionner différentes versions
239 d'un fichier.}
240 \label{fig:tour-merge:kdiff3}
241 </para>
242 </informalfigure>
244 <para>Pour chaque portion de fichier posant problème, nous pouvons choisir
245 de résoudre le conflit en utilisant une combinaison
246 de texte depuis la version de base, la notre, ou la leur. Nous pouvons
247 aussi éditer manuellement les fichiers à tout moment, si c'est
248 nécessaire.
249 </para>
251 <para>Il y a <emphasis>beaucoup</emphasis> d'outils de fusion disponibles, bien trop pour
252 en parler de tous ici. Leurs disponibilités varient selon les plate formes
253 ainsi que leurs avantages et inconvénients. La plupart sont optimisé pour
254 la fusion de fichier contenant un texte plat, certains sont spécialisé
255 dans un format de fichier précis (généralement XML).
256 </para>
258 </sect2>
259 <sect2>
260 <title>Un exemple concret</title>
262 <para>Dans cet exemple, nous allons reproduire la modification de l'historique
263 du fichier de la figure <xref linkend="fig:tour-merge:conflict"/> ci dessus. Commençons
264 par créer un dépôt avec une version de base de notre document.
265 </para>
267 <para><!-- &interaction.tour-merge-conflict.wife; -->
268 Créons un clone de ce dépôt et faisons une modification dans le fichier.
269 <!-- &interaction.tour-merge-conflict.cousin; -->
270 Et un autre clone, pour simuler que quelqu'un d'autre effectue une
271 modification sur le fichier. (Ceci pour suggérer qu'il n'est pas rare
272 de devoir effectuer des \textit{merge} avec vos propres travaux quand
273 vous isolez les tâches dans des dépôts distincts. En effet, vous
274 aurez alors à trouver et résoudre certains conflits).
275 <!-- &interaction.tour-merge-conflict.son; -->
276 Maintenant que ces deux versions différentes du même fichier sont
277 créées, nous allons configurer l'environnement de manière appropriée pour
278 exécuter notre \textit{merge}.
279 <!-- &interaction.tour-merge-conflict.pull; -->
280 </para>
282 <para>Dans cette exemple, je n'utiliserais pas la commande Mercurial
283 habituelle <command>hgmerge</command> pour effectuer le \textit{merge},
284 car il me faudrait abandonner ce joli petit exemple automatisé
285 pour utiliser un outil graphique. À la place, je vais définir
286 la variable d'environnement <envar>HGMERGE</envar> pour indiquer à
287 Mercurial d'utiliser la commande non-interactive <command>merge</command>.
288 Cette dernière est embarquée par de nombreux systèmes <quote>à la Unix</quote>.
289 Si vous exécutez cet exemple depuis votre ordinateur, ne vous
290 occupez pas de définir <envar>HGMERGE</envar>.
291 <!-- &interaction.tour-merge-conflict.merge; -->
292 Parce que <command>merge</command> ne peut pas résoudre les modifications
293 conflictuelles, il laisse des <emphasis>marqueurs de différences</emphasis>
294 \footnote{NdT: Oui, je traduis \textit{merge markers} par un sens
295 inverse en Français, mais je pense vraiment que c'est plus clair
296 comme ça...} à l'intérieur du fichier qui a des conflits, indiquant
297 clairement quelles lignes sont en conflits, et si elles viennent de
298 notre fichier ou du fichier externe.
299 </para>
301 <para>Mercurial peut distinguer, à la manière dont la commande <command>merge</command>
302 se termine, qu'elle n'a pas été capable d'effectuer le \textit{merge},
303 alors il nous indique que nous devons effectuer de nouveau cette
304 opération. Ceci peut être très utile si, par exemple, nous exécutons un
305 outil graphique de fusion et que nous le quittons sans nous rendre compte
306 qu'il reste des conflits ou simplement par erreur.
307 </para>
309 <para>Si le \textit{merge} automatique ou manuel échoue, il n'y a rien pour
310 nous empêcher de <quote>corriger le tir</quote> en modifiant nous même les fichiers,
311 et enfin effectuer le \textit{commit} du fichier:
312 <!-- &interaction.tour-merge-conflict.commit; -->
313 </para>
315 </sect2>
316 </sect1>
317 <sect1>
318 <title>Simplification de la séquence pull-merge-commit</title>
319 <para>\label{sec:tour-merge:fetch}
320 </para>
322 <para>La procédure pour effectuer la fusion indiquée ci-dessus est simple,
323 mais requiert le lancement de trois commandes à la suite.
324 </para>
325 <programlisting>
326 <para> hg pull
327 hg merge
328 hg commit -m 'Merged remote changes'
329 </para>
330 </programlisting>
332 <para>Lors du \textit{commit} final, vous devez également saisir un message,
333 qui aura vraisemblablement assez peu d'intérêt.
334 </para>
336 <para>Il serait assez sympathique de pouvoir réduire le nombre d'opérations
337 nécessaire, si possible. De fait Mercurial est fourni avec une
338 extension appelé <literal role="hg-ext">fetch</literal> qui fait justement cela.
339 </para>
341 <para>Mercurial fourni un mécanisme d'extension flexible qui permet à chacun
342 d'étendre ces fonctionnalités, tout en conservant le cœur de Mercurial
343 léger et facile à utiliser. Certains extensions ajoutent de nouvelles
344 commandes que vous pouvez utiliser en ligne de commande, alors que
345 d'autres travaillent <quote>en coulisse,</quote> par exemple en ajoutant des
346 possibilités au serveur.
347 </para>
349 <para>L'extension <literal role="hg-ext">fetch</literal> ajoute une nouvelle commande nommée, sans
350 surprise, <command role="hg-cmd">hg fetch</command>. Cette extension résulte en une combinaison
351 de <command role="hg-cmd">hg pull</command>, <command role="hg-cmd">hg update</command> and <command role="hg-cmd">hg merge</command>. Elle commence par
352 récupérer les modifications d'un autre dépôt dans le dépôt courant.
353 Si elle trouve que les modifications ajoutent une nouvelle \textit{head},
354 elle effectue un \textit{merge}, et ensuite \texit{commit} le résultat
355 du \textit{merge} avec un message généré automatiquement. Si aucune
356 \textit{head} n'ont été ajouté, elle met à jour le répertoire de travail
357 au niveau du nouveau \textit{changeset} \textit{tip}.
358 </para>
361 <para>Activer l'extension <literal role="hg-ext">fetch</literal> est facile. Modifiez votre <filename role="special">.hgrc</filename>,
362 et soit allez à la section <literal role="rc-extensions">extensions</literal> soit créer une
363 section <literal role="rc-extensions">extensions</literal>. Ensuite ajoutez une ligne qui consiste
364 simplement en <quote>\Verb+fetch =</quote>.
365 </para>
367 <programlisting>
368 <para> [extensions]
369 fetch =
370 </para>
371 </programlisting>
372 <para>(Normalement, sur la partie droite de <quote><literal>=</literal></quote> devrait apparaître
373 le chemin de l'extension, mais étant donné que l'extension <literal role="hg-ext">fetch</literal>
374 fait partie de la distribution standard, Mercurial sait où la trouver.)
375 </para>
377 </sect1>
378 </chapter>
380 <!--
381 local variables:
382 sgml-parent-document: ("00book.xml" "book" "chapter")
383 end:
384 -->