hgbook

view fr/ch04-concepts.xml @ 1013:44946b10a4b3

merge with André Sintzoff
author Romain PELISSE <belaran@gmail.com>
date Tue Nov 24 11:44:49 2009 +0100 (2009-11-24)
parents 669ae1a09e46
children 77b4f62bed20
line source
1 <!-- vim: set filetype=docbkxml shiftwidth=2 autoindent expandtab tw=77 : -->
3 <chapter id="chap:concepts">
4 <?dbhtml filename="behind-the-scenes.html"?>
5 <title>Derrière le décor</title>
7 <para id="x_2e8">À la différence de beaucoup d'outils de gestion de révisions,
8 les concepts sur lesquels se base Mercurial sont assez simples pour
9 qu'il soit facile de comprendre comment le logiciel fonctionne.
10 Bien que leur connaissance ne soit pas indispensable, je trouve utile
11 d'avoir un <quote>modèle mental</quote> de ce qui se passe.</para>
13 <para id="x_2e9">En effet, cette compréhension m'apporte la confiance que
14 Mercurial a été développé avec soin pour être à la fois
15 <emphasis>sûr</emphasis> et <emphasis>efficace</emphasis>. De surcroît,
16 s'il m'est facile de garder en tête ce que le logiciel fait lorsque
17 j'accompli des tâches de révision, j'aurai moins de risques d'être
18 surpris par son comportement.</para>
20 <para id="x_2ea">Dans ce chapitre, nous décrirons tout d'abord les concepts
21 essentiels de l'architecture de Mercurial, pour ensuite discuter quelques
22 uns des détails intéressants de son implémentation.</para>
24 <sect1>
25 <title>Conservation de l'historique sous Mercurial</title>
26 <sect2>
27 <title>Suivi de l'historique pour un seul fichier</title>
29 <para id="x_2eb">Lorsque Mercurial effectue un suivi des modifications
30 faites à un fichier, il conserve l'historique pour ce fichier dans un
31 <emphasis>filelog</emphasis> sous forme de métadonnées. Chaque entrée
32 dans le <quote>filelog</quote> contient assez d'informations pour reconstituer une
33 révision du fichier correspondant. Les <quote>filelogs</quote> sont des fichiers
34 stockés dans le répertoire <filename role="special"
35 class="directory">.hg/store/data</filename>. Un <quote>filelog</quote> contient
36 des informations de deux types: les données de révision, et un index
37 pour permettre à Mercurial une recherche efficace d'une révision
38 donnée.</para>
40 <para id="x_2ec">Lorsqu'un fichier devient trop gros ou a un long
41 historique, son <quote>filelog</quote> se voit stocké dans un fichier de données
42 (avec un suffixe <quote><literal>.d</literal></quote>) et un fichier
43 index (avec un suffixe<quote><literal>.i</literal></quote>)
44 distincts. La relation entre un fichier dans le répertoire de travail
45 et le <quote>filelog</quote> couvrant le suivi de son historique dans le dépôt est
46 illustré à la figure <xref linkend="fig:concepts:filelog"/>.</para>
48 <figure id="fig:concepts:filelog">
49 <title>Relations entre les fichiers dans le répertoire de travail et
50 leurs <quote>filelogs</quote> dans le dépôt</title>
51 <mediaobject> <imageobject><imagedata
52 fileref="figs/filelog.png"/></imageobject>
53 <textobject><phrase>XXX add text</phrase></textobject>
54 </mediaobject> </figure>
56 </sect2>
57 <sect2>
58 <title>Gestion des fichiers suivis</title>
60 <para id="x_2ee">Mercurial a recours à une structure nommée
61 <emphasis>manifest</emphasis> pour rassembler les informations sur
62 les fichiers dont il gère le suivi. Chaque entrée dans ce <quote>manifest</quote>
63 contient des informations sur les fichiers présents dans une révision
64 donnée. Une entrée enregistre la liste des fichiers faisant partie de la
65 révision, la version de chaque fichier, et quelques autres
66 métadonnées sur ces fichiers.</para>
68 </sect2>
69 <sect2>
70 <title>Enregistrer les informations des <quote>changesets</quote></title>
72 <para id="x_2ef">Le <emphasis>changelog</emphasis> contient les
73 informations sur chaque <quote>changeset</quote>. Chaque révision enregistre qui a
74 <quote>committé</quote> un changement, le commentaire du <quote>changeset</quote>, d'autres
75 morceaux d'information relatives au <quote>changeset</quote> et la révision du
76 <quote>manifest</quote> à utiliser.</para>
78 </sect2>
79 <sect2>
80 <title>Relations entre les révisions</title>
82 <para id="x_2f0">A l'intérieur d'un <quote>changelog</quote>, d'un <quote>manifest</quote>, ou d'un
83 <quote>filelog</quote>, chaque révision enregistre un pointeur vers son parent
84 immédiat (ou à ses deux parents s'il s'agit d'une révision
85 correspondant à une fusion (merge)). Comme mentionné plus haut, il y
86 a aussi des relations entre les révisions <emphasis>à
87 travers</emphasis> ces structures, qui sont de nature
88 hiérarchique.</para>
90 <para id="x_2f1">Pour chaque <quote>changeset</quote> dans un dépôt, il y a exactement
91 une révision stockée dans le <quote>changelog</quote>. Chaque révision du <quote>changelog</quote>
92 contient un pointeur vers une unique révision du <quote>manifest</quote>. Une
93 révision du <quote>manifest</quote> garde un pointeur vers une unique révision pour
94 chaque <quote>filelog</quote> suivi lorsque le <quote>changeset</quote> est créé. Ces relations
95 sont illustrées dans <xref linkend="fig:concepts:metadata"/>.</para>
97 <figure id="fig:concepts:metadata">
98 <title>Metadata relationships</title>
99 <mediaobject> <imageobject><imagedata
100 fileref="figs/metadata.png"/></imageobject>
101 <textobject><phrase>XXX add text</phrase></textobject>
102 </mediaobject>
103 </figure>
105 <para id="x_2f3">Comme l'illustration le montre, il
106 <emphasis>n'</emphasis>y a <emphasis>pas</emphasis> de relation
107 <quote>un à un</quote> entre les révisions dans un <quote>changelog</quote>,
108 <quote>manifest</quote> ou <quote>filelog</quote>. Si un fichier que Mercurial suit n'a pas changé
109 entre deux <quote>changesets</quote>, l'entrée pour ce fichier dans les deux
110 révisions du <quote>manifest</quote> pointera vers la même révision de son <quote>filelog</quote>
111 <footnote> <para id="x_725">Il est possible (bien qu'inhabituel)
112 qu'un <quote>manifest</quote> reste le même entre deux <quote>changesets</quote>, auquel cas
113 l'entrée du <quote>changelog</quote> pour ces <quote>changesets</quote> pointera vers la même
114 révision du <quote>manifest</quote>.</para>
115 </footnote>.</para>
117 </sect2>
118 </sect1>
119 <sect1>
120 <title>Stockage sûr et efficace</title>
122 <para id="x_2f4">Les fondements des <quote>changelogs</quote>, des <quote>manifests</quote> et des
123 <quote>filelogs</quote> sont fournis par une unique structure appelée le
124 <emphasis>revlog</emphasis>.</para>
126 <sect2>
127 <title>stockage efficace</title>
129 <para id="x_2f5">Le <quote>revlog</quote> fournit un stockage efficace des révisions en
130 utilisant un mécanisme <emphasis>delta</emphasis>. A lieu de stocker
131 une copie complète d'un fichier à chaque révision, il stocke les
132 changements requis pour transformer une révision plus ancienne en une
133 nouvelle révision. Pour plusieurs type de données, ces deltas sont
134 typiquement une fraction de pourcentage de la taille de la copie
135 complète d'un fichier.</para>
137 <para id="x_2f6">Certains systèmes de gestion de révisions obsolètes
138 peuvent seulement travailler avec les deltas de fichiers texte. Il
139 doivent d'ailleurs stocker les fichiers binaires comme des images
140 complètes ou encodées avec une représentation texte, chacune de ces
141 approches étant gaspilleuse. Mercurial peut traiter les deltas de
142 fichiers avec du contenu binaire arbitraire ; il n'a pas besoin de
143 traiter spécialement du texte.</para>
145 </sect2>
146 <sect2 id="sec:concepts:txn">
147 <title>Opérations sûres</title>
149 <para id="x_2f7">Mercurial <emphasis>empile</emphasis> toujours les
150 données à la fin d'un fichier <quote>revlog</quote>. Il ne modifie jamais la section
151 d'un fichier après qu'il l'ait écrite. C'est à la fois plus robuste
152 et efficace que les schémas qui ont besoin de modifier ou réécrire
153 les données.</para>
155 <para id="x_2f8">De plus, Mercurial traite chaque écriture comme la
156 partie d'une <emphasis>transaction</emphasis> qui peut comprendre
157 plusieurs fichiers. Une transaction est <emphasis>atomique</emphasis>
158 : soit la transaction entière réussie ses effets sont tous
159 visibles aux lecteurs en une étape, soit la totalité est annulée.
160 Cette garantie de l'atomicité signifie que si vous exécutez deux
161 copies de Mercurial, où une lit les données et l'autre les écrit, le
162 lecteur ne verra jamais un résultat partiellement écrit qui pourrait
163 le perturber.</para>
165 <para id="x_2f9">Le fait que Mercurial ne fasse qu'ajouter aux fichiers
166 fait qu'il est facile de fournir cette garantie de transaction. Plus
167 les choses sont faites simplement comme ça, plus vous pouvez être
168 rassurés qu'elles sont bien faites.</para>
170 </sect2>
171 <sect2>
172 <title>Récupération rapide</title>
174 <para id="x_2fa">Mercurial évite habillement un piège commun à tous les
175 vieux systèmes de gestion de révisions : le problème de la
176 <emphasis>récupération inefficace</emphasis> La plupart des systèmes
177 de gestion de révisions stockent le contenu d'une révision comme une
178 série incrémentale de modifications faites à un
179 <quote>snapshot</quote>. (Certains basent le <quote>snapshot</quote> sur la plus
180 vieille révision, d'autres sur la plus récente.) Pour reconstruire
181 une révision spécifique, vous devez d'abord lire le <quote>snapshot</quote>, et
182 ensuite toutes les révisions entre le <quote>snapshot</quote> et votre révision
183 cible. Plus vous avez d'historique accumulé dans un fichier, plus de
184 révisions vous avez à lire, d'où la longueur que cela prend à
185 reconstruire une révision particulière.</para>
187 <figure id="fig:concepts:snapshot">
188 <title><quote>Snapshot</quote> d'un <quote>revlog</quote>, avec des deltas incrémentaux</title>
189 <mediaobject> <imageobject><imagedata
190 fileref="figs/snapshot.png"/></imageobject>
191 <textobject><phrase>XXX add text</phrase></textobject>
192 </mediaobject>
193 </figure>
195 <para id="x_2fc">L'inovation que Mercurial apporte à ce problème est
196 simple mais effective. Une fois que la quantité cumulée de deltas
197 d'informations stockées depuis le dernier snapshot excède un seuil
198 fixé, il stocke un nouveau <quote>snapshot</quote> (compressé bien sûr), plutôt qu'un
199 nouveau delta. Ceci rend possible la reconstruction de
200 <emphasis>toute</emphasis> révision d'un fichier rapidement. Cette
201 approche fonctionne si bien que depuis, elle a été copiée par
202 plusieurs autres systèmes de gestion de révisions.</para>
204 <para id="x_2fd"><xref linkend="fig:concepts:snapshot"/> illustre
205 l'idée. Dans une entrée d'un fichier d'index de <quote>revlog</quote>, Mercurial
206 stocke l'intervalle des entrées depuis le fichier de données qu'il doit
207 lire pour reconstruire une révision particulière.</para>
209 <sect3>
210 <title>En amont : l'influence de la compression vidéo</title>
212 <para id="x_2fe">Si vous êtes familiés de la compression vidéo ou
213 avez déjà regardé un programme TV par cable ou par un service
214 satellite, vous devez savoir que la plupart des schémas de
215 compression vidéo stockent chaque frame de vidéo comme un delta vis
216 à vis de la frame précédente.</para>
218 <para id="x_2ff">Mercurial emprunte cette idée pour rendre possible
219 la reconstruction d'une révision à partir d'un snapshot et d'un
220 petit nombre de deltas.</para>
222 </sect3>
223 </sect2>
224 <sect2>
225 <title>Identification et intégrité forte</title>
227 <para id="x_300">Avec les deltas ou l'information du snapshot, une
228 entrée d'un revlog contient un hash cryptographique des données qu'il
229 représente. Ceci fait qu'il est difficile de construire les données
230 d'une révision, mais facile de détecter une corruption
231 accidentelle.</para>
233 <para id="x_301">Les hash fournissent plus qu'un bon moyen de
234 vérification contre la corruption ; il sont aussi utilisés comme
235 identifiants pour les révisions. Les <quote>hashs</quote> d'identifications d'un
236 <quote>changeset</quote> que vous voyez comme utilisateur final proviennent des
237 révisions du <quote>changelog</quote>. Bien que les <quote>filelogs</quote> et le <quote>manifest</quote>
238 utilisent aussi des <quote>hashs</quote>, Mercurial ne les utilise qu'en arrière
239 plan.</para>
241 <para id="x_302">Mercurial vérifie que les <quote>hashs</quote> sont corrects lorsqu'il
242 récupère les révisions de fichiers et lorsqu'il récupère (pull) les
243 changements d'un autre dépôt. S'il rencontre un problème d'intégrité,
244 il se plaindra et arrêtera tout ce qu'il est en train de faire.</para>
246 <para id="x_303">En plus de l'effet qu'il a sur l'efficacité des
247 récupérations, l'utilisation par Mercurial de <quote>snapshots</quote> périodiques
248 fait qu'il est plus robuste contre la corruption partielle de
249 données. Si un <quote>revlog</quote> devient partiellement corrompu à cause d'une
250 erreur matérielle ou d'un bug système, il est souvent possible de
251 reconstruire certaines ou la plupart des révisions à partir des
252 sections non corrompues du <quote>revlog</quote>, avant et après la section
253 corrompue. Ceci ne serait pas possible à partir d'un modèle de
254 stockage de deltas seul.</para>
255 </sect2>
256 </sect1>
258 <sect1>
259 <title>Historique des révisions, branches et fusions (merge)</title>
261 <para id="x_304">Chaque entrée dans un <quote>revlog</quote> Mercurial connaît
262 l'identité de l'ancêtre immédiat de la révision, habituellement désignée
263 comme son <emphasis>parent</emphasis>. En fait, une révision contient
264 de la place pour non pas un parent, mais deux. Mercurial utilise un
265 <quote>hash</quote> spécial, appelé le <quote>null ID</quote> pour représenter l'idée
266 qu'<quote>il n'y a pas de parent ici</quote>. Ce <quote>hash</quote> est simplement
267 une chaîne de zéros.</para>
269 <para id="x_305">Dans <xref linkend="fig:concepts:revlog"/>, vous pouvez
270 voir un exemple de la structure conceptuelle d'un <quote>revlog</quote>. Les <quote>filelogs</quote>,
271 <quote>manifests</quote> et <quote>changelogs</quote> ont tous cette même structure ; ils diffèrent
272 simplement dans le type de donnée stockée dans chaque delta ou
273 <quote>snapshot</quote>.</para>
275 <para id="x_306">La première révision d'un <quote>revlog</quote> (au bas de l'image) a
276 le <quote>null ID</quote> dans chacune de ses cases parent. Pour une révision
277 <quote>normale</quote>, sa première case parent contient l'ID de sa
278 révision parent et la seconde contient le <quote>null ID</quote>, indiquant que cette
279 révision n'a qu'un seul vrai parent. Si deux révisions ont le même
280 parent, il s'agit de branches. Une révision qui représente une fusion
281 (merge) entre deux branches a deux identifiants de révision normaux
282 dans ses cases parents.</para>
284 <figure id="fig:concepts:revlog">
285 <title>Le concept de la structure d'un <quote>revlog</quote></title>
286 <mediaobject> <imageobject><imagedata
287 fileref="figs/revlog.png"/></imageobject> <textobject><phrase>XXX
288 add text</phrase></textobject>
289 </mediaobject>
290 </figure>
292 </sect1>
293 <sect1>
294 <title>Le répertoire de travail</title>
296 <para id="x_307">Dans un répertoire de travail, Mercurial stocke une image
297 des fichiers du dépôt à un <quote>changeset</quote> particulier.</para>
299 <para id="x_308">Le répertoire de travail <quote>sait</quote> quel
300 <quote>changeset</quote> il contient. Lorsque vous mettez à jour (update) le
301 répertoire de travail à un certain <quote>changeset</quote>, Mercurial regarde la
302 révision appropriée du <quote>manifest</quote> pour trouver quels fichiers il suivait
303 au moment où le <quote>changeset</quote> a été <quote>committé</quote>, et quelle révision de chaque
304 fichier était alors courante. Il recrée ensuite une copie de chacun de
305 ces fichiers, avec le même contenu qu'ils avaient lorsque le <quote>changeset</quote>
306 a été <quote>committé</quote>.</para>
308 <para id="x_309">La structure spéciale <emphasis>dirstate</emphasis>
309 contient la connaissance de Mercurial sur le répertoire de travail.
310 Elle est maintenue par un fichier appelé
311 <filename>.hg/dirstate</filename> dans un dépôt. Les détails du
312 dirstate sont le <quote>changeset</quote> vers lequel le répertoire de travail se met
313 à jour (update), et tous les fichiers que Mercurial suit dans le
314 répertoire de travail. Il permet aussi à Mercurial de connaître
315 rapidement les fichiers modifiés, en enregistrant l'heure de
316 dernière modification et la taille de chacun.</para>
318 <para id="x_30a">Puisqu'une révision de <quote>revlog</quote> a des emplacements pour
319 deux parents et peut représenter aussi bien une révision normale (avec
320 un parent) ou une fusion de deux révisions anciennes, le <quote>dirstate</quote> a des
321 emplacements pour deux parents. Lorsque vous utilisez la commande
322 <command role="hg-cmd">hg update</command>, le <quote>changeset</quote> que vous
323 mettez à jour est stocké dans l'emplacement du <quote>premier
324 parent</quote>, et le <quote>null ID</quote> l'est dans le second. Lorsque vous
325 utilisez la commande <command role="hg-cmd">hg merge</command> avec un
326 autre changeset, le premier parent reste inchangé, et le second est
327 rempli avec le <quote>changeset</quote> à partir duquel vous êtes en train de
328 fusionner. La commande <command role="hg-cmd">hg parents</command> vous
329 donne les parents du dirstate.</para>
331 <sect2>
332 <title>Que se passe-t'il lorsque vous <quote>committez</quote></title>
334 <para id="x_30b">Le <quote>dirstate</quote> stocke les informations sur les parents
335 pour plus qu'un simple livre de stockage. Mercurial utilise les
336 parents du <quote>distate</quote> comme <emphasis>les parents d'un nouveau
337 <quote>changeset</quote></emphasis> lorsque vous <quote>committez</quote>.</para>
339 <figure id="fig:concepts:wdir">
340 <title>Le répertoire de travail peut avoir deux parents</title>
341 <mediaobject>
342 <imageobject><imagedata fileref="figs/wdir.png"/></imageobject>
343 <textobject><phrase>XXX add text</phrase></textobject></mediaobject>
344 </figure>
346 <para id="x_30d"><xref linkend="fig:concepts:wdir"/> montre l'état
347 normal d'un répertoire de travail, où il n'y a qu'un seul <quote>changeset</quote>
348 comme parent. Ce <quote>changeset</quote> est le <emphasis>tip</emphasis>, le
349 <quote>changeset</quote> le plus récent dans le dépôt n'a pas d'enfant.</para>
351 <figure id="fig:concepts:wdir-after-commit">
352 <title>Le répertoire de travail gagne de nouveaux parents après un
353 <quote>commit</quote></title>
354 <mediaobject>
355 <imageobject><imagedata
356 fileref="figs/wdir-after-commit.png"/></imageobject>
357 <textobject><phrase>XXX add text</phrase></textobject>
358 </mediaobject>
359 </figure>
361 <para id="x_30f">On peut se représenter le répertoire de travail comme
362 <quote>le changeset que je vais committer</quote>. Chaque fichier
363 que vous demandez à Mercurial d'ajouter, de supprimer, de renommer ou de
364 copier va être intégré dans ce changeset, tout comme les
365 modifications de n'importe quel fichier que Mercurial est déjà en
366 train de suivre ; le nouveau <quote>changeset</quote> aura les mêmes parents que le
367 répertoire de travail.</para>
369 <para id="x_310">Après un commit, Mercurial va mettre à jour les
370 parents du répertoire de travail, ainsi, le premier parent est l'ID
371 du nouveau <quote>changeset</quote>, et le second, le <quote>null ID</quote>. Ceci est illustré dans
372 <xref linkend="fig:concepts:wdir-after-commit"/>. Mercurial ne touche
373 à aucun des fichiers du répertoire de travail lorsque vous <quote>committez</quote>
374 ; il modifie simplement le dirstate pour noter ses nouveaux
375 parents.</para>
377 </sect2>
378 <sect2>
379 <title>Création d'une nouvelle <quote>head</quote></title>
381 <para id="x_311">Il est parfaitement normal de faire un <quote>update</quote> du
382 répertoire de travail à un <quote>changeset</quote> autre que le <quote>tip</quote> courant. Par
383 exemple, vous pourriez vouloir savoir à quoi votre projet
384 ressemblait mardi dernier, ou regarder le <quote>changeset</quote> qui a
385 introduit un bug. Dans des cas comme ça, la chose naturelle à faire
386 est de faire un <quote>update</quote> du répertoire de travail au <quote>changeset</quote> qui vous
387 intéresse, et ensuite d'en examiner les fichiers pour regarder leurs
388 contenus comme ils l'étaient lorsque vous avez <quote>commité</quote> ce <quote>changeset</quote>.
389 L'effet de ceci est montré dans <xref
390 linkend="fig:concepts:wdir-pre-branch"/>.</para>
392 <figure id="fig:concepts:wdir-pre-branch">
393 <title>Le répertoire de travail, <quote>updaté</quote> pour un <quote>changeset</quote> plus
394 ancien</title>
395 <mediaobject> <imageobject><imagedata
396 fileref="figs/wdir-pre-branch.png"/></imageobject>
397 <textobject><phrase>XXX add text</phrase></textobject>
398 </mediaobject>
399 </figure>
401 <para id="x_313">En ayant fait un <quote>update</quote> du répertoire de travail vers
402 un <quote>changeset</quote> plus ancien, que se passe-t'il si vous faites des
403 changements et ensuite <quote>committez</quote> ? Mercurial se comporte comme je
404 l'ai fait remarqué plus haut. Les parents du répertoire de travail
405 deviennent les parents du nouveau <quote>changeset</quote>. Ce nouveau <quote>changeset</quote> n'a
406 pas d'enfant, donc il devient le nouveau <quote>tip</quote>. Le dépôt contient
407 maintenant deux <quote>changesets</quote> qui n'ont pas d'enfant ; on appelle ceci
408 des <emphasis>heads</emphasis>. Vous pouvez voir la structure que
409 cela crée dans <xref linkend="fig:concepts:wdir-branch"/>.</para>
411 <figure id="fig:concepts:wdir-branch">
412 <title>Après un <quote>commit</quote> fait pendant la synchronisation avec un ancien
413 <quote>changeset</quote></title>
414 <mediaobject> <imageobject><imagedata
415 fileref="figs/wdir-branch.png"/></imageobject>
416 <textobject><phrase>XXX add text</phrase></textobject>
417 </mediaobject>
418 </figure>
420 <note>
421 <para id="x_315">Si vous êtes nouveau à Mercurial, vous devez garder
422 à l'esprit une <quote>erreur</quote> commune, qui est d'utiliser la
423 commande <command role="hg-cmd">hg pull</command> sans aucune
424 option. Par défaut, la commande <command role="hg-cmd">hg
425 pull</command> <emphasis>ne fait pas</emphasis> d'<quote>update</quote> sur le
426 répertoire de travail, ainsi, vous allez récupérer les nouveaux
427 changesets dans votre dépôt, mais le répertoire de travail va
428 rester synchronisé au même <quote>changeset</quote> qu'il l'était avant le <quote>pull</quote>.
429 Si vous faites des changements et <quote>committez</quote> ensuite, vous allez
430 créer une nouvelle <quote>head</quote> puisque votre répertoire de travail n'est
431 pas synchronisé au <quote>tip</quote> actuel. Pour combiner les
432 opérations d'un <quote>pull</quote> suivi d'un <quote>update</quote>, exécutez <command>hg
433 pull -u</command>.</para>
435 <para id="x_316">Je place le mot <quote>erreur</quote> entre
436 guillemets parce que tous ce dont vous avez besoin de faire pour
437 rectifier la situation où vous avez créé une nouvelle <quote>head</quote> par
438 accident est un <command role="hg-cmd">hg merge</command> suivi
439 d'un <command role="hg-cmd">hg commit</command>. En d'autres mots,
440 ceci n'a presque jamais de conséquences négatives ; il s'agit juste
441 d'une surprise pour les nouveaux arrivants. Je discuterai d'autres
442 moyens d'éviter ce comportement, et pourquoi Mercurial agit de
443 cette façon surprenante plus tard.</para>
444 </note>
446 </sect2>
447 <sect2>
448 <title>Fusionner (merge) les changements</title>
450 <para id="x_317">Lorsque vous exécutez la commande <command
451 role="hg-cmd">hg merge</command>, Mercurial laisse le premier
452 parent du répertoire de travail inchangé et fixe le second au
453 <quote>changeset</quote> avec lequel vous fusionnez (merge), comme montré dans <xref
454 linkend="fig:concepts:wdir-merge"/>.</para>
456 <figure id="fig:concepts:wdir-merge">
457 <title>Fusionner (merge) deux <quote>heads</quote></title>
458 <mediaobject>
459 <imageobject> <imagedata fileref="figs/wdir-merge.png"/>
460 </imageobject> <textobject><phrase>XXX add text</phrase></textobject>
461 </mediaobject>
462 </figure>
464 <para id="x_319">Mercurial doit aussi modifier le répertoire de
465 travail pour fusionner les fichiers gérés dans les deux <quote>changesets</quote>.
466 Un peu simplifié, le processus de fusion fonctionne comme ça : pour
467 chaque fichier dans le <quote>manifest</quote> de chaque <quote>changeset</quote>.</para>
469 <itemizedlist>
470 <listitem><para id="x_31a">Si aucun <quote>changeset</quote> n'a modifié un fichier,
471 ne rien faire avec ce fichier.</para> </listitem>
472 <listitem><para id="x_31b">Si un <quote>changeset</quote> a modifié un fichier et
473 que l'autre ne l'a pas fait, créer une copie modifiée du fichier
474 dans le répertoire de travail.</para> </listitem>
475 <listitem><para id="x_31c">Si un <quote>changeset</quote> a modifié un fichier, et
476 que l'autre ne l'a pas fait (ou l'a supprimé), supprimer le
477 fichier du répertoire de travail.</para> </listitem>
478 <listitem><para id="x_31d">Si un <quote>changeset</quote> a supprimé un fichier,
479 mais que l'autre a modifié le fichier, demander à l'utilisateur
480 quoi faire : garder le fichier modifié ou le supprimer ?</para>
481 </listitem>
482 <listitem><para id="x_31e">Si chacun des <quote>changeset</quote> a modifié un
483 fichier, invoquer le programme externe de fusion pour choisir les
484 nouveaux contenus pour le fichier fusionné. Ceci peut demander
485 des entrées de l'utilisateur.</para></listitem>
486 <listitem><para id="x_31f">Si un <quote>changeset</quote> a modifié un fichier, et
487 que l'autre a renommé ou copié le fichier, être sûr que les
488 changements suivent le nouveau nom du fichier.</para></listitem>
489 </itemizedlist>
491 <para id="x_320">Il y a plus de détails&emdash;fusionner a beaucoup de
492 cas anguleux&emdash;mais ceux-ci sont des chois plus communs qui sont
493 invoqués pendant une fusion (merge). Comme vous pouvez le voir, la
494 plupart des cas sont entièrement automatiques, et effectivement, la
495 plupart des fusions (merge) se terminent automatiquement, sans avoir
496 besoin d'entrées pour résoudre un conflit.</para>
498 <para id="x_321">Lorsque vous pensez à ce qu'il se passe lorsque vous
499 <quote>committez</quote> après un <quote>merge</quote>, une fois encore, le répertoire de travail
500 est <quote>le changeset que je suis sur le point de
501 committer</quote>. Après que la commande <command role="hg-cmd">hg
502 merge</command> ait terminé, le répertoire de travail a deux
503 parents ; ceux ci vont devenir les parents du nouveau
504 <quote>changeset</quote>.</para>
506 <para id="x_322">Mercurial vous permet d'exécuter de multiples fusions,
507 mais vous devez <quote>committer</quote> le résultat de chaque fusion individuellement
508 au fur et à mesure. Ceci est nécessaire puisque Mercurial ne stocke
509 que deux parents pour chaque révision et le répertoire de travail.
510 Alors qu'il serait techniquement faisable de fusionner de multiples
511 <quote>changesets</quote> en même temps, Mercurial interdit cette simplicité. Avec
512 des fusions multiples, les risques de confusion pour l'utilisateur, de
513 conflits de résolutions, et de pagaille dans les fusions
514 augmenteraient de façon Intolérable.</para>
516 </sect2>
518 <sect2>
519 <title>Fusions et renommages</title>
521 <para id="x_69a">Un nombre surprenant de systèmes de gestion de
522 révisions fait peu ou pas attention à un <emphasis>nom</emphasis> au
523 cours du temps. Par exemple, il était habituel que si un fichier
524 était renommé d'un coté de la fusion, les changements à partir de
525 l'autre coté étaient supprimés silencieusement.</para>
527 <para id="x_69b">Mercurial enregistre les metadata lorsque vous lui
528 dite d'exécuter un renommage ou une copie. Il utilise ces metadatas
529 durant une fusion pour faire les bonnes choses dans le cas d'un
530 <quote>merge</quote>. Par exemple, si je renomme un fichier et que vous l'éditez
531 sans le renommer, lorsque l'on fusionne, le fichier sera renommé et
532 aura les changements appliqués.</para>
534 </sect2>
535 </sect1>
537 <sect1>
538 <title>D'autres fonctionnalités intéressantes</title>
540 <para id="x_323">Dans les sections au-dessus, j'ai tenté de mettre
541 l'accent sur certains aspects importants du design de Mercurial pour
542 illustrer l'attention particulière qui a été portée à la fiabilité et à
543 la performance. Cependant, l'attention aux détails ne s'arrête pas ici.
544 Il y a de nombreux aspects sur la construction de Mercurial que je
545 trouve personnellement intéressante. J'en détaillerai quelques-uns
546 ici, séparément des éléments du <quote>big ticket</quote> ci-dessus,
547 ainsi, si vous êtes intéressés, vous pourrez avoir une meilleure idée
548 de la quantité d'ingéniosité qu'il y a derrière un système bien
549 conçu.</para>
551 <sect2>
552 <title>Compression élégante</title>
554 <para id="x_324">Lorsque cela est approprié, Mercurial stocke les
555 <quote>snapshots</quote> et deltas sous une forme compressée. Il le fait en
556 <emphasis>essayant</emphasis> toujours de compresser un <quote>snapshot</quote> ou
557 un delta, mais en ne stockant la version compressée que si celle-ci
558 est plus petite que la version non compressée.</para>
560 <para id="x_325">Ceci signifie que Mercurial fait <quote>la bonne
561 chose</quote> lorsqu'il stocke un fichier dont la forme native est
562 compressée, comme une archive <literal>zip</literal> ou une image
563 JPEG. Lorsque ces types de fichiers sont compressés une seconde fois,
564 le fichier obtenu est habituellement plus gros que la forme
565 compressée une seule fois et Mercurial stockera alors le
566 <literal>zip</literal> ou JPEG.</para>
568 <para id="x_326">Les Deltas entre les révisions d'un fichier compressé
569 sont habituellement plus gros que les snapshots du fichier, et
570 Mercurial fait à nouveau <quote>la bonne chose</quote> dans ces cas.
571 Il trouve qu'un delta dépasse le seuil auquel il devrait stocker un
572 <quote>snapshot</quote> complet du fichier, alors il stocke le <quote>snapshot</quote>, en gagnant
573 encore de la place en comparaison d'une approche naïve avec un delta
574 seulement.</quote>
576 <sect3>
577 <title>Recompression réseau</title>
579 <para id="x_327">Lors du stockage des révisions sur le disque,
580 Mercurial utilise l'algorithme de compression
581 <quote>deflate</quote> (le même que celui utilisé pour le format
582 d'archive populaire <literal>zip</literal>), qui est un bon
583 compromis entre la vitesse et le taux de compression. Cependant,
584 lors de la transmission d'une révision de données par une connexion
585 réseau, Mercurial décompresse les données de révision
586 compressées.</para>
588 <para id="x_328">Si la connexion passe par HTTP, Mercurial
589 recompresse le flux entier de données en utilisant un algorithme de
590 compression qui donne un meilleur taux de compression (l'algorithme
591 Burrows-Wheeler utilisé principalement par le logiciel de
592 compression <literal>bzip2</literal>). Cette combinaison de
593 l'algorithme et de compression du flux entier (plutôt que pour une
594 révision à la fois) réduit substantiellement le nombre de bits qui
595 sont transférés, résultant en une performance réseau accrue sur
596 la plupart des supports.</para>
598 <para id="x_329">Si la connexion passe par
599 <command>ssh</command>, Mercurial <emphasis>ne</emphasis>
600 recompresse <emphasis>pas</emphasis> le flux puisque
601 <command>ssh</command> peut déjà le faire par lui même. Vous pouvez
602 demander à Mercurial de toujours utiliser la compression
603 <command>ssh</command> en éditant le fichier
604 <filename>.hgrc</filename> de votre répertoire personnel comme ci-dessous.
605 </para>
607 <programlisting>[ui]
608 ssh = ssh -C</programlisting>
610 </sect3>
611 </sect2>
612 <sect2>
613 <title>Ordres de Lecture/Écriture et atomicité</title>
615 <para id="x_32a">L'histoire ne se résume pas à ajouter à la fin des fichiers
616 lorsque l'on cherche à garantir que le lecteur ne verra
617 pas qu'une écriture partielle. Si vous relisez <xref
618 linkend="fig:concepts:metadata"/>, les révisions dans le <quote>changelog</quote>
619 pointent vers les révisions dans le <quote>manifest</quote>, et les révisions du
620 <quote>manifest</quote> pointent vers les révisions du <quote>filelog</quote>. Cette hiérarchie est
621 délibérée.</para>
623 <para id="x_32b">L'écriture commence par une transaction en écrivant dans
624 le <quote>filelog</quote> et dans les données du <quote>manifest</quote>, et n'écrit aucune donnée
625 du <quote>changelog</quote> tant que ce n'est pas terminé. La lecture commence en
626 lisant les données du <quote>changelog</quote>, puis les données du <quote>manifest</quote>, et
627 enfin les données du <quote>filelog</quote>.</para>
629 <para id="x_32c">Puisque que l'écriture ne finit pas d'écrire les
630 données du <quote>filelog</quote> et du <quote>manifest</quote> avant d'écrire dans le <quote>changelog</quote>,
631 la lecture ne verra jamais un pointeur vers une révision du <quote>manifest</quote>
632 partiellement écrite à partir du <quote>changelog</quote>, et ne lira jamais un
633 pointeur vers une révision du <quote>filelog</quote> partiellement écrite dans le
634 <quote>manifest</quote>.</para>
636 </sect2>
637 <sect2>
638 <title>Accès concurrent</title>
640 <para id="x_32d">La garantie de l'ordre de lecture/écriture et
641 de l'atomicité signifie que Mercurial n'a jamais besoin de poser de
642 <emphasis>lock</emphasis> sur un dépôt lorsqu'il lit des données,
643 même si le dépôt est en train d'être écrit au même moment que la
644 lecture a lieu. Ceci a un grand impact sur la fiabilité ; vous
645 pouvez avoir un nombre arbitraire de processus Mercurial qui lisent
646 sans risque les données d'un dépôt en même temps, peu importe s'il
647 est en train d'être lu ou non.</para>
649 <para id="x_32e">La nature sans <quote>lock</quote> de la lecture
650 signifie que si vous partagez un dépôt sur un système
651 multi-utilisateurs, vous n'avez pas besoin de donner aux autres
652 utilisateurs locaux la permission d'<emphasis>écrire</emphasis> sur
653 votre dépôt pour qu'ils soient capable de faire un clone ou un <quote>pull</quote>
654 des changements à partir de celui ci ; ils ont seulement besoin de la
655 permission en <emphasis>lecture</emphasis>. (Il
656 <emphasis>ne</emphasis> s'agit <emphasis>pas</emphasis> d'une
657 fonctionnalité commune à travers les systèmes de gestion de révisions,
658 donc ne prenez pas ça pour garantie ! La plupart ont besoin que les
659 lecteurs soient capables de mettre un lock sur le dépôt pour y
660 accéder en toute sécurité, et ceci demande des permissions en
661 écriture, sur au moins un répertoire, ce qui provoque bien sûr toutes
662 sortes de problèmes néfastes et ennuyants relatifs à la sécurité et à
663 l'administration.)</para>
665 <para id="x_32f">Mercurial utilise des <quote>locks</quote> pour assurer qu'un seul
666 processus peut écrire dans le dépôt à un moment donné (le mécanisme
667 de <quote>lock</quote> est sûr, même sur des systèmes de fichiers qui sont connus
668 pour être hostiles aux <quote>locks</quote>, comme NFS). Si un dépôt dispose d'un
669 <quote>lock</quote>, un processus qui cherche à écrire va attendre un peu avant de
670 retenter pour voir si le dépôt perd son <quote>lock</quote>, mais si le dépôt garde
671 trop longtemps son <quote>lock</quote>, le processus qui tente d'écrire va expirer
672 (time out) après un moment. Cela veut dire par exemple que vos
673 scripts lancés quotidiennement n'attendront pas toujours et boucleront
674 si un système plantait sans avertissement, par exemple. (Oui, le
675 timeout est configurable, de zéro à l'infini.)</para>
677 <sect3>
678 <title>Accès <quote>dirstate</quote> sûr</title>
680 <para id="x_330">Comme avec les données de révision, Mercurial n'utilise pas
681 de <quote>lock</quote> pour lire le fichier <quote>dirstate</quote> ; il n'acquiert pas un <quote>lock</quote> pour
682 y écrire. Pour empêcher la possibilité de lire une copie partiellement
683 écrite du fichier <quote>dirstate</quote>, Mercurial écrit sur un fichier avec un nom
684 unique dans le même répertoire que le fichier <quote>dirstate</quote>, ensuite renomme
685 le fichier temporaire automatiquement en <filename>dirstate</filename>.
686 Le fichier nommé <filename>dirstate</filename> est ainsi garanti d'être
687 écrit totalement, et non partiellement.</para>
689 </sect3>
690 </sect2>
691 <sect2>
692 <title>Empêcher les recherches</title>
694 <para id="x_331">L'absence de recherche sur les têtes de disques est
695 critique pour la performance de Mercurial, puisque toute recherche
696 est beaucoup plus coûteuse comparativement à une grosse opération de
697 lecture.</para>
699 <para id="x_332">C'est pour ça, par exemple, que le <quote>dirstate</quote> est stocké
700 dans un fichier unique. S'il y avait eu un <quote>dirstate</quote> par répertoire
701 que Mercurial suivrait, le disque aurait recherché une fois par
702 répertoire. Au lieu de ça, Mercurial lit entièrement un
703 fichier unique, en une étape.</para>
705 <para id="x_333">Mercurial utilise aussi un schéma <quote>copie à
706 l'écriture</quote> lorsqu'il clone un dépôt sur un stockage local.
707 Au lieu de copier chaque <quote>fichier</quote> revlog depuis l'ancien dépôt vers le
708 nouveau dépôt, il crée un <quote>lien physique</quote>, qui est le
709 plus court chemin pour dire <quote>Ces deux noms pointent vers le
710 même fichier</quote>. Lorsque Mercurial est sur le point d'écrire
711 sur l'un des revlogs de ces fichiers, il vérifie si le nombre de noms
712 pointant sur ce fichier est plus grand que un. Si c'est le cas, plus
713 d'un dépôt utilise le fichier, donc Mercurial crée une nouvelle copie
714 du fichier qui est privée à ce dépôt.</para>
716 <para id="x_334">Quelques développeurs de systèmes de gestion de
717 révisions ont montré que cette idée de faire une copie privée complète
718 d'un fichier n'est pas vraiment efficace au niveau du
719 stockage. Bien que ce soit vrai, le stockage est peu onéreux, et
720 cette méthode donne la plus grande performance lorsque l'on reporte
721 la plupart des journalisations au système d'exploitation. Un schéma
722 alternatif réduirait certainement la performance tout en augmentant
723 la complexité du logiciel, mais la vitesse et la simplicité sont les
724 clefs du <quote>confort</quote> de l'utilisation
725 quotidienne.</para>
727 </sect2>
728 <sect2>
729 <title>Autres contenus du <quote>dirstate</quote></title>
731 <para id="x_335">Puisque Mercurial ne vous force pas à signaler que
732 vous modifiez un fichier, il utilise le <quote>dirstate</quote> pour stocker
733 certaines informations supplémentaires pour déterminer efficacement
734 si vous avez ou non modifié un fichier. Pour chaque fichier du
735 répertoire de travail, il stocke l'heure à laquelle il a été modifié,
736 ainsi que la taille du fichier à cette heure.</para>
738 <para id="x_336">Lorsque vous faites explicitement un <command
739 role="hg-cmd">hg add</command>, <command role="hg-cmd">hg
740 remove</command>, <command role="hg-cmd">hg rename</command> ou
741 <command role="hg-cmd">hg copy</command> sur des fichiers, Mercurial
742 met à jour le <quote>dirstate</quote> afin de savoir quoi faire lorsque vous
743 effectuez un <quote>commit</quote>.</para>
745 <para id="x_337">Le <quote>dirstate</quote> aide Mercurial à vérifier efficacement le
746 statut des fichiers dans un dépôt.</para>
748 <itemizedlist>
749 <listitem> <para id="x_726"> Lorsque Mercurial vérifie l'état d'un
750 fichier du répertoire de travail, il compare d'abord la date de
751 dernière modification du fichier avec celle enregistrée dans le
752 <quote>dirstate</quote> qui correspond à celle que Mercurial a écrit en dernier sur ce
753 fichier. Si le temps de dernière modification correspond au temps
754 où Mercurial a écrit le fichier, celui ci n'a pas été modifié,
755 donc mercurial n'a pas besoin de revérifier.</para> </listitem>
756 <listitem> <para id="x_727"> Si la taille du fichier a changé, celui-ci
757 a été modifié. Si la date de modification a changé mais que la
758 taille est restée inchangée, seulement à ce moment là Mercurial
759 doit vérifier le contenu du fichier pour savoir s'il a été
760 modifié.</para> </listitem>
761 </itemizedlist>
763 <para id="x_728">Enregistrer la date de modification et la taille
764 réduit grandement le nombre d'opérations de lecture que Mercurial
765 doit effectuer lorsque l'on utilise une commande comme <command>hg
766 status</command>. Le résultat est un grand gain de
767 performance.</para>
768 </sect2>
769 </sect1>
770 </chapter>
772 <!--
773 local variables:
774 sgml-parent-document: ("00book.xml" "book" "chapter")
775 end:
776 -->