belaran@964: belaran@964: bos@559: bos@572: youshe@993: Derrière le décor youshe@993: youshe@993: À la différence de beaucoup d'outils de gestion de versions, youshe@993: les concepts sur lesquels se base Mercurial sont assez simples pour youshe@993: qu'il soit facile de comprendre comment le logiciel fonctionne. youshe@993: Bien que leur connaissance ne soit pas nécéssaire, je trouve utile youshe@993: d'avoir un modèle mental de ce qui se passe. youshe@993: youshe@993: En effet, cette compréhension m'apporte la confiance que youshe@993: Mercurial a été développé avec soin pour être à la fois youshe@993: sûr et efficace. De surcroît, youshe@993: si il m'est facile de garder en tête ce que le logiciel fait lorsque youshe@993: j'accompli des tâches de révision, j'aurai moins de risques d'être youshe@993: surpris par son comportement. youshe@993: youshe@993: Dans ce chapitre, nous décrirons tout d'abord les concepts youshe@993: essentiels de l'architecture de Mercurial, pour ensuite discuter quelques youshe@993: uns des détails intéressants de son implémentation. bos@559: bos@559: youshe@993: Conservation de l'historique sous Mercurial youshe@993: youshe@993: Suivi de l'historique pour un seul fichier youshe@993: youshe@993: Lorsque Mercurial effectue un suivi des modifications youshe@993: faites à un fichier, il conserve l'historique pour ce fichier dans un youshe@993: filelog sous forme de métadonnées. Chaque entrée youshe@993: dans le filelog contient assez d'informations pour reconstituer une youshe@993: révision du fichier correspondant. Les filelogs sont des fichiers youshe@993: stockés dans le répertoire .hg/store/data. Un filelog contient youshe@993: des informations de deux types: les données de révision, et un index youshe@993: pour permettre à Mercurial une recherche efficace d'une révision youshe@993: donnée. youshe@993: youshe@993: Lorsqu'un fichier devient trop gros ou a un long youshe@993: historique, son filelog se voit stocker dans un fichier de données youshe@993: (avec un suffixe .d) et un fichier youshe@993: index (avec un suffixe.i) youshe@993: distincts. La relation entre un fichier dans le répertoire de travail youshe@993: et le filelog couvrant le suivi de son historique dans le dépôt est youshe@993: illustré à la figure . bos@559: bos@591:
youshe@993: Relations entre les fichiers dans le répertoire de travail et youshe@993: leurs filelogs dans le dépôt youshe@993: youshe@993: XXX add text youshe@993:
youshe@993: youshe@993:
youshe@993: youshe@993: Gestion des fichiers suivis youshe@993: youshe@993: Mercurial a recours à une structure nommée youshe@993: manifest pour rassembler les informations sur youshe@993: les fichiers dont il gère le suivi. Chaque entrée dans ce manifest youshe@993: contient des informations sur les fichiers présents dans une révision youshe@1001: donnée. Une entrée enregistre la liste des fichiers faisant partie de la youshe@993: révision, la version de chaque fichier, et quelques autres youshe@993: métadonnées sur ces fichiers. bos@559: bos@559: bos@559: youshe@1001: Enregistrer les informations des changeset youshe@1001: youshe@1001: Le changelog contient les youshe@1001: informations sur chaque changeset. Chaque révision enregistre qui a youshe@1001: committé un changement, le commentaire du changeset, d'autres youshe@1001: morceaux d'information relatives au changeset et la révision du youshe@1001: manifest à utiliser. youshe@1001: youshe@1001: youshe@1001: youshe@1001: Relations entre les révisions youshe@1001: youshe@1001: A l'intérieur d'un changelog, d'un manifest, ou d'un youshe@1001: filelog, chaque révision enregistre un pointeur vers son parent youshe@1001: immédiat (ou à ses deux parents s'il s'agit d'une révision youshe@1001: correspondant à une fusion (merge)). Comme mentionné plus haut, il y youshe@1001: a aussi des relations entre les révisions à youshe@1001: travers ces structures, qui sont de nature youshe@1001: hiérarchique. youshe@1001: youshe@1001: Pour chaque changeset dans un dépôt, il y a exactement youshe@1001: une révision stockée dans le changelog. Chaque révision du changelog youshe@1001: contient un pointeur vers une unique révision du manifest. Une youshe@1001: révision du manifeste garde un pointeur vers une unique révision pour youshe@1001: chaque filelog suivi lorsque le changeset est créé. Ces relations youshe@1001: sont illustrées dans . bos@559: bos@591:
youshe@1001: Metadata relationships youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: youshe@1001: Comme l'illustration le monde, il youshe@1001: n'y a pas de relation youshe@1001: un à un entre les révisions dans un changelog, youshe@1001: manifest ou filelog. Si un fichier que Mercurial suit n'a pas changé youshe@1001: entre deux changesets, l'entrée pour ce fichier dans les deux youshe@1001: révisions du manifest pointera vers la même révision de son filelog youshe@1001: Il est possible (bien qu'inhabituel) youshe@1001: qu'un manifest reste le même entre deux changesets, auquel cas youshe@1001: l'entrée du changelog pour ces changesets pointera vers la même youshe@1001: révision du manifest. youshe@1001: . bos@559: bos@559:
bos@559:
bos@559: youshe@1001: Stockage sûr et efficace youshe@1001: youshe@1001: Les fondements des changelogs, des manifests et des youshe@1001: filelogs sont fournis par une unique structure appelée le bos@559: revlog. bos@559: bos@559: youshe@1001: stockage efficace youshe@1001: youshe@1001: Le revlog fournit un stockage efficace des révision en youshe@1001: utilisant un mécanisme delta. A lieu de stocker youshe@1001: une copie complète d'un fichier à chaque révision, il stocke les youshe@1001: changements requis pour transformer une révision plus ancienne en la youshe@1001: nouvelle révision. Pour plusieurs type de données, ces deltas sont youshe@1001: typiquement une fraction de pourcentage de la taille de la copie youshe@1001: complète d'un fichier. youshe@1001: youshe@1001: Certains systèmes de gestion de révisions obselètes youshe@1001: peuvent seulement travailler avec les deltas de fichiers texte. Il youshe@1001: doivent d'ailleurs stocker les fichiers binaires comme des images youshe@1001: complètes ou encodées avec une représentation texte, chacune de ces youshe@1001: approches étant gaspilleuse. Mercurial peut traiter les deltas de youshe@1001: fichiers avec du contenu binaire arbitraire ; il n'a pas besoin de youshe@1001: traiter spécialement du texte. bos@559: bos@559: bos@559: youshe@1001: Opérations sûres youshe@1001: youshe@1001: Mercurial empile toujours les youshe@1001: données à la fin d'un fichier revlog. Il ne modifie jamais la section youshe@1001: d'un fichier après qu'il l'ait écrite. C'est à la foit plus robuste youshe@1001: et efficace que les schémas qui ont besoin de modifier ou réécrire youshe@1001: les données. youshe@1001: youshe@1001: De plus, Mercurial traite chaque écriture comme une youshe@1001: partie d'une transaction qui peut comprendre youshe@1001: plusieurs fichiers. Une transaction est atomique youshe@1001: : spot la transaction entière réussit et ses effets sont tous youshe@1001: visibles aux lecteurs en une étape, soit la totalité est annulée. youshe@1001: Cette garantie de l'atomicité signifie que si vous exécutez deux youshe@1001: copies de Mercurial, où une lit les données et l'autre les écrit, le youshe@1001: lecteur ne verra jamais un résultat partiellement écrit qui pourrait youshe@1001: le perturber. youshe@1001: youshe@1001: Le fait que Mercurial ne fasse qu'ajouter aux fichiers youshe@1001: fait qu'il est facile de fournir cette garantie de transaction. Plus youshe@1001: les choses sont faites simplement comme ça, plus vous pouvez être youshe@1001: rassurés qu'elles sont bien faites. youshe@1001: youshe@1001: youshe@1001: youshe@1001: Récupération rapide youshe@1001: youshe@1001: Mercurial évite habillement un piège commun à tous les youshe@1001: vieux systèmes de gestion de révisions : le problème de la youshe@1001: récupération inefficace La plupart des systèmes youshe@1001: de gestion de révisions stockent le contenu d'une révision comme une youshe@1001: série incrémentale de modifications faites à un youshe@1001: snapshot. (Certains basent le snapshot sur la plus youshe@1001: vieille révision, d'autres sur la plus récente.) Pour reconstruire youshe@1001: une révision spécifique, vous devez d'abord lire le snapshot, et youshe@1001: ensuite toutes les révisions entre le snapshot et votre révision youshe@1001: cible. Plus vous avez d'historique accumulé dans un fichier, plus de youshe@1001: révisions vous avez à lire, d'où la longueur que cela prend à youshe@1001: reconstruire une révision particulière. bos@559: bos@591:
youshe@1001: Snapshot d'un revlog, avec des deltas incrémentaux youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: youshe@1001: L'inovation que Mercurial apporte à ce problème est youshe@1001: simple mais effective. Une fois que la quantité cumulée de deltas youshe@1001: d'informations stockées depuis le dernier snapshot excède un seuil youshe@1001: fixé, il stock un nouveau snapshot (compréssé biensûr), plutôt qu'un youshe@1001: nouveau delta. Ceci rend possible la reconstruction de youshe@1001: toute révision d'un fichier rapidement. Cette youshe@1001: approche fonctionne si bien que depuis, elle a été copiée par youshe@1001: plusieurs autres systèmes de gestion de révisions. youshe@1001: youshe@1001: illustre youshe@1001: l'idée. Dans une entrée d'un fichier d'index de revlog, Mercurial youshe@1001: stock l'intervale des entrées depuis le fichier de données qu'il doit youshe@1001: lire pour reconstruire une révision particulière. bos@559: bos@559: youshe@1001: En amont : l'influence de la compression vidéo youshe@1001: youshe@1001: Si vous êtes familiés de la compression vidéo ou youshe@1001: avez déjà regardé un programme TV par cable ou par un service youshe@1001: satellite, vous devez savoir que la plupart des schémas de youshe@1001: compression vidéo stockent chaque frame de vidéo comme un delta vis youshe@1001: à vis de la frame précédente. youshe@1001: youshe@1001: Mercurial emprunte cette idée pour rendre possible youshe@1001: la reconstruction d'une révision à partir d'un snapshot et d'un youshe@1001: petit nombre de deltas. bos@559: bos@559: bos@559:
bos@559: youshe@1001: Identification et intégrité forte youshe@1001: youshe@1001: Avec les deltas ou l'information du snapshot, une youshe@1001: entrée d'un revlog contient un hash cryptographique des données qu'il youshe@1001: représente. Ceci fait qu'il est difficile de construire les données youshe@1001: d'une révision, mais facile de détecter une corruption youshe@1001: accidentelle. youshe@1001: youshe@1001: Les hash fournissent plus qu'un bon moyen de youshe@1001: vérification contre la corruption ; il sont aussi utilisés comme youshe@1001: identifiants pour les révisions. Le hash d'identification d'un youshe@1001: changeset que vous voyez comme utilisateur final proviennent des youshe@1001: révisions du changelog. Bien que les filelogs et le manifest youshe@1001: utilisent aussi des hash, Mercurial ne les utilise qu'en arrière youshe@1001: plan. youshe@1001: youshe@1001: Mercurial vérifie que les hash sont corrects lorsqu'il youshe@1001: récupère les révisions de fichiers et lorsqu'il récupère (pull) les youshe@1001: changements d'un autre dépôt. S'il rencontre un problème d'intégrité, youshe@1001: il se pleindra et arrêtera tout ce qu'il est en train de faire. youshe@1001: youshe@1001: En plus de l'effet qu'il a sur l'efficacité des youshe@1001: récupérations, l'utilisation de Mercurial de snapshots périodiques youshe@1001: fait qu'il est plus robuste contre la corruption partielle de youshe@1001: données. Si un revlog devient partiellement corrompu à cause d'une youshe@1001: erreur matérielle ou d'un bug système, il est souvent possible de youshe@1001: reconstruire certaines ou la plupart des révisions à partir des youshe@1001: sections non corrompues du revlog, avant et après la section youshe@1001: corrompue. Ceci ne serait pas possible à partir d'un modèle de youshe@1001: stockage delta seul. bos@559: bos@559:
bos@701: bos@559: youshe@1001: Historique des révisions, branches et fusions (merge) youshe@1001: youshe@1001: Chaque entrée dans un revlog Mercurial connaît youshe@1001: l'identité de l'ancètre immédiat de la révision, habituellement référé youshe@1001: comme son parent. En fait, une révision contient youshe@1001: de la place pour non pas un parent, mais deux. Mercurial utilise un youshe@1001: hash spécial, appelé le null ID pour représenter l'idée youshe@1001: qu'il n'y a pas de parent ici. Ce hash est simplement youshe@1001: une chaîne de zéros. youshe@1001: youshe@1001: Dans , vous pouvez youshe@1001: voir un exemple de la structure conceptuelle d'un revlog. Les filelogs, youshe@1001: manifests et changelogs ont tous cette même structure ; ils difèrent youshe@1001: simplement dans le type de donnée stockée dans chaque delta ou bos@559: snapshot. bos@559: youshe@1001: La première révision d'un revlog (au bas de l'image) a youshe@1001: le null ID dans chacune de ses cases parent. Pour une révision youshe@1001: normale, sa première case parent contient l'ID de sa youshe@1001: révision parent et la seconde contient le null ID, indiquant que cette youshe@1001: révision n'a qu'un seul vrai parent. Si deux révisions ont le même youshe@1001: parent, il s'agit de branches. Une révision qui représente une fusion youshe@1001: (merge) entre deux branches a deux identifiants de révision normaux youshe@1001: dans ses cases parents. bos@559: bos@591:
bos@591: The conceptual structure of a revlog youshe@1001: XXX youshe@1001: add text bos@591: bos@591:
bos@559: bos@559:
bos@559: youshe@1001: Le répertoire de travail youshe@1001: youshe@1001: Dans un répertoire de travail, Mercurial stock une image youshe@1001: des fichiers du dépôt à un changeset particulier. youshe@1001: youshe@1001: Le répertoire de travail sait quel youshe@1001: changeset il contient. Lorsque vous mettez à jour (update) le youshe@1001: répertoire de travail à un certain changeset, Mercurial regarde la youshe@1001: révision appropriée du manifest pour trouver quels fichier il suivait youshe@1001: au moment où le changeset a été committé, et quelle révision de chaque youshe@1001: fichier était alors courante. Il recrée ensuite une copie de chacun de youshe@1001: ces fichiers, avec le même contenu qu'ils avaient lorsque le changeset youshe@1001: a été committé. youshe@1001: youshe@1001: La structure spéciale dirstate youshe@1001: contient la connaissance de Mercurial sur le répertoire de travail. youshe@1001: Elle est maintenue par un fichier appelé youshe@1001: .hg/dirstate dans un dépôt. Les détails du youshe@1001: dirstate sont le changeset vers lequel le répertoire de travail se met youshe@1001: à jour (update), et tous les fichiers que Mercurial suit dans le youshe@1001: répertoire de travail. Il permet aussi à Mercurial se connaître youshe@1001: rapidement les fichiers modifiés, en enregistrant leurs heures de youshe@1001: dernière modification et leur taille. youshe@1001: youshe@1001: Puisqu'une révision de revlog a des emplacements pour youshe@1001: deux parents et peut représenter aussi bien une révision normale (avec youshe@1001: un parent) ou une fusion de deux révisions anciennes, le dirstate a des youshe@1001: emplacements pour deux parents. Lorsque vous utilisez la commande youshe@1001: hg update, le changeset que vous youshe@1001: mettez à jour est stocké dans l'emplacement du premier youshe@1001: parent, et le null ID l'est dans le second. Lorsque vous youshe@1001: utilisez la commande hg merge avec un youshe@1001: autre changeset, le premier parent reste inchangé, et le second est youshe@1001: rempli avec le changeset à partir duquel vous êtes en train de youshe@1001: fusionner. La commande hg parents vous youshe@1001: donne les parents du dirstate. youshe@1001: youshe@1001: youshe@1001: Que se passe-t-il lorsque vous committez youshe@1001: youshe@1001: Le dirstate stock les informations sur les parents youshe@1001: pour plusqu'un simple livre de stockage. Mercurial utilise les youshe@1001: parents du distate comme les parents d'un nouveau youshe@1001: changeset lorsque vous committez. youshe@1001: youshe@1001:
youshe@1001: Le répertoire de travail peut avoir deux parents youshe@1001: youshe@1001: youshe@1001: XXX add text bos@591:
bos@559: youshe@1001: montre l'état youshe@1001: normal d'un répertoire de travail, où il n'y a qu'un seul changeset youshe@1001: comme parent. Ce changeset est le tip, le youshe@1001: changeset le plus récent dans le dépôt n'a pas d'enfant. bos@559: bos@591:
youshe@1001: Le répertoire de travail gagne de nouveaux parents après un youshe@1001: commit youshe@1001: youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: youshe@1001: Il est utile de penser du répertoire de travail qu'il youshe@1001: est le changeset que je vais committer. Chaque fichier youshe@1001: que vous dites à mercurial d'ajouter, de supprimer, de renommer ou de youshe@1001: copier va être reflété dasn ce changeset, tout comme les youshe@1001: modifications de n'importe quel fichier que Mercurial est déjà en youshe@1001: train de suite ; le nouveau changeset aura les mêmes parents que le youshe@1001: répertoire de travail. youshe@1001: youshe@1001: Après un commit, Mercurial va mettre à jour les youshe@1001: parents du répertoire de travail, ainsi, le premier parents est l'ID youshe@1001: du nouveau changeset, et le second, le nullID. Ceci est illustré dans youshe@1001: . Mercurial ne touche youshe@1001: à aucun des fichiers du répertoire de travail lorsque vous committez youshe@1001: ; il modifie simplement le dirstate pour noter ses nouveaux youshe@1001: parents. youshe@1001: youshe@1001:
youshe@1001: youshe@1001: Création d'une nouvelle <quote>head</quote> youshe@1001: youshe@1001: Il est parfaitement normal de faire un update du youshe@1001: répertoire de travail à un changeset autre que le tip courant. Par youshe@1001: exemple, vous pourriez vouloir savoir ce à quoi votre projet youshe@1001: ressemblait le dernier Mardi, ou regarder le changeset qui a youshe@1001: introduit un bug. Dans des cas comme ça, la chose naturelle à faire youshe@1001: est de faire un update du répertoire de travail au changeset qui vous youshe@1001: intéresse, et ensuite d'en examiner les fichiers pour regarder leurs youshe@1001: contenus comme ils l'étaient lorsque vous avez commité ce changeset. youshe@1001: L'effet de ceci est montré dans . bos@559: bos@591:
youshe@1001: Le répertoire de travail, "updaté" pour un changeset plus youshe@1001: ancien youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: youshe@1001: En ayant fait un update du répertoire de travail vers youshe@1001: un changeset plus ancien, qu'est-ce qu'il se passe si vous faites des youshe@1001: changements et ensuite committez ? Mercurial se comporte comme je youshe@1001: l'ai fait remarqué plus haut. Les parents du répertoire de travail youshe@1001: deviennent les parents du nouveau changeset. Ce nouveau changeset n'a youshe@1001: pas d'enfant, donc il devient le nouveau tip. Le dépôt contient youshe@1001: maintenant deux changesets qui n'ont pas d'enfant ; on appelle ceci youshe@1001: des heads. Vous pouvez voir la structire que youshe@1001: cela crée dans . bos@559: bos@591:
youshe@1001: Après un commit fait pendant la synchronisation avec un ancien youshe@1001: changeset youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: bos@559: youshe@1001: Si vous êtes nouveau à Mercurial, vous devez garder youshe@1001: à l'esprit une erreur commune, qui est d'utiliser la youshe@1001: commande hg pull sans aucune youshe@1001: option. Par défaut, la commande hg youshe@1001: pull ne fait pas d'update sur le youshe@1001: répertoire de travail, ainsi, vous allez récupérer les nouveaux youshe@1001: changesets dans votre dépôt, mais le répertoire de travail va youshe@1001: rester synchroniser au même changeset qu'il l'était avant le pull. youshe@1001: Si vous faites des changements et committez ensuite, vous allez youshe@1001: créer une nouvelle head puisque votre répertoire de travail n'est youshe@1001: pas synchronisé à ce que le tip actuel est. Pour combiner les youshe@1001: opérations d'un pull suivi d'un update, exécutez run hg youshe@1001: pull -u. youshe@1001: youshe@1001: Je place le mot erreur entre youshe@1001: guillemets parce que tous ce dont vous avez besoin de faire pour youshe@1001: rectifier la situation où vous avez créé une nouvelle head par youshe@1001: accident est un hg merge suivi youshe@1001: d'un hg commit. En d'autres mots, youshe@1001: ceci n'a presque jamais de conséquences négatives ; il s'agit juste youshe@1001: d'une surprise pour les nouveaux arrivants. Je discuterai d'autres youshe@1001: moyens d'éviter ce comportement, et pourquoi Mercurial agit de youshe@1001: cette façon surprenante plus tard. bos@559: bos@559: bos@559:
bos@559: youshe@1001: Fusionner (merge) les changements youshe@1001: youshe@1001: Lorsque vous exécutez la commande hg merge, Mercurial laisse le premier youshe@1001: parent du répertoire de travail inchangé et fixe le second au youshe@1001: changeset avec lequel vous fusionnez (merge), comme montré dans . bos@559: bos@591:
youshe@1001: Fusionner (merge) deux heads youshe@1001: youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: youshe@1001: Mercurial doit aussi modifier le répertoire de youshe@1001: travail pour fusionner les fichiers gérés dans les deux changesets. youshe@1001: Un peu simplifié, le processus de fusion fonctionne comme ça : pour youshe@1001: chaque fichier dans le manifest de chaque changeset. youshe@1001: bos@559: youshe@1001: Si aucun changeset n'a modifié un fichier, youshe@1001: ne rien faire avec ce fichier. youshe@1001: Si un changeset a modifié un fichier et youshe@1001: que l'autre ne l'a pas fait, créer une copie modifiée du fichier youshe@1001: dans le répertoire de travail. youshe@1001: Si un changeset a modifié un fichier, et youshe@1001: que l'autre ne l'a pas fait (ou l'a supprimé), supprimer le youshe@1001: fichier du répertoire de travail. youshe@1001: Si un changeset a supprimé un fichier, youshe@1001: mais que l'autre a modifié le fichier, demander à l'utilisateur youshe@1001: quoi faire : garder le fichier modifié ou le supprimer ? youshe@1001: youshe@1001: Si chacun des chengeset a modifié un youshe@1001: fichier, invoquer le programme externe de fusion pour choisir les youshe@1001: nouveaux contenus pour le fichier fusionné. Ceci peut demander youshe@1001: des entrées de l'utilisateur. youshe@1001: Si un changeset a modifié un fichier, et youshe@1001: que l'autre a renommé ou copié le fichier, être sûr que les youshe@1001: changements suivent le nouveau nom du fichier. youshe@1001: youshe@1001: youshe@1001: Il y a plus de détails&emdash;fusionner a beaucoup de youshe@1001: cas anguleux&emdash;mais ceux-ci sont des chois plus communs qui sont youshe@1001: invoqués pendant une fusion (merge). Comme vous pouvez le voir, la youshe@1001: plupart des cas sont entièrement automatiques, et effectivement, la youshe@1001: plupart des fusions (merge) se terminent automatiquement, sans avoir youshe@1001: besoin d'entrées pour résoudre un conflit. youshe@1001: youshe@1001: Lorsque vous pensez à ce qu'il se passe lorsque vous youshe@1001: committez après un merge, une fois encore, le répertoire de travail youshe@1001: est le changeset que je suis sur le point de youshe@1001: committer. Après que la commande hg youshe@1001: merge ait terminé, le répertoire de travail a deux youshe@1001: parents ; ceux ci vont devenir les parents du nouveau youshe@1001: changeset. youshe@1001: youshe@1001: Mercurial vous permet d'exécuter de multiples fusions, youshe@1001: mais vous devez committer le résultat de chaque fusion individuelle youshe@1001: comme vous avancez. Ceci est nécessaire puisque Mercurial ne stock youshe@1001: que deux parents pour chaque révision et le répertoire de travail. youshe@1001: Alors qu'il serait techniquement faisble de fusionner de multiples youshe@1001: changesets en même temps, Mercurial interdit cette simplicité. Avec youshe@1001: des fusions multplus, les risques de confision utilisateur, de youshe@1001: conflits néfastes de résolutions, et faire une pagaille d'une fusion youshe@1001: grossiraient intollérablement. youshe@1001: youshe@1001:
youshe@1001: youshe@1001: youshe@1001: Fusions et renommages youshe@1001: youshe@1001: Un nombre surprenant de systèmes de gestion de youshe@1001: révision fait peu ou pas attention à un nom au youshe@1001: cours du temps. Par exemple, il était habituel que si un fichier youshe@1001: était renommé d'un coté de la fusion, les changements à partir de youshe@1001: l'autre coté étaient supprimés silencieusement. youshe@1001: youshe@1001: Mercurial enregistre les metadata lorsque vous lui youshe@1001: dite d'exécuter un renommage ou une copie. Il utilise ces metadata youshe@1001: durant une fusion pour faire les bonnes choses dans le cas d'un youshe@1001: merge. Par exemple, si je renomme un fichier et que vous l'éditez youshe@1001: sans le renommer, lorsque l'on fusionne, le fichier sera renommé et youshe@1001: aura les éditions appliquées. youshe@1001: bos@620: bos@559:
bos@620: bos@559: youshe@1001: D'autres fonctionnalités intéressantes youshe@1001: youshe@1001: Dans les sections au dessus, j'ai tenté de mettre youshe@1001: l'accent sur certains aspects importants du design de Mercurial pour youshe@1001: illustrer l'attention particulière qui a été portée à la fiabilité et à youshe@1001: la performance.Cependant, l'attention aux détails ne s'arrête pas ici. youshe@1001: Il y a de nombreux aspects sur la construction de Mercurial que je youshe@1001: trouve personnellement intéressante. Je détaillerai quelques un d'eux youshe@1001: ici, séparément des éléments du big ticket ci dessus, youshe@1001: ainsi, si vous êtes intéressés, vous pourrez avoir une meilleure idée youshe@1001: de la quantité de pensées qu'il y a derrière un système bien youshe@1001: défini. youshe@1001: youshe@1001: youshe@1001: Compression élégante youshe@1001: youshe@1001: Lorsque cela est approprié, Mercurial stocke les youshe@1001: snapshots et deltas sous une forme compressée. Il le fait en youshe@1001: essayant toujours de compression un snapshot ou youshe@1001: un delta, mais en ne stockant la version compression que si celle ci youshe@1001: est plus petite que la version non compressée. youshe@1001: youshe@1001: Ceci signifie que Mercurial fait la bonne youshe@1001: chose lorsqu'il stocke un fichier dont la forme native est youshe@1001: compressée, comme une archive zip ou une image youshe@1001: JPEG. Lorsque ces types de fichiers sont compressés une seconde fois, youshe@1001: le fichier obtenu est habituellement plus gros que la forme youshe@1001: compressée une seule fois et Mercurial stockera alors le youshe@1001: zip ou JPEG. youshe@1001: youshe@1001: Les Deltas entre les révisions d'un fichier compressé youshe@1001: sont habituellement plus gros que les snapshots du fichier, et youshe@1001: Mercurial fait à nouveau la bonne chose dans ces cas. youshe@1001: Il trouve qu'un delta dépasse le seuil auquel il devrait stocker un youshe@1001: snapshot complet du ficheir, alors il stocke le snapshot, en gagnant youshe@1001: encore de la place en comparaison à une approche naïve delta youshe@1001: seulement. bos@559: bos@559: youshe@1001: Recompression réseau youshe@1001: youshe@1001: Lors du stockage des révisions sur le disque, youshe@1001: Mercurial utilise l'algorithme de compression youshe@1001: deflate (le même que celui utilisé pour le format youshe@1001: d'archive populaire zip), qui est un bon youshe@1001: comprimis entre la vitesse et le taux de compression. Cependant, youshe@1001: lors de la transmission d'une révision de données par une connexion youshe@1001: réseau, Mercurial décompresse les données de révision youshe@1001: compressées. youshe@1001: youshe@1001: Si la connexion est au dessus de HTTP, mercurial youshe@1001: recompresse le flux entier de données en utilisant un algorithme de youshe@1001: compression qui donne un meilleur taux de compression (l'algorithme youshe@1001: Burrows-Wheeler utilisé principalement par le package de youshe@1001: compression bzip2). Cette combinaison de youshe@1001: l'algorithme et de compression du flux entier (plutôt que pour une youshe@1001: révision à la fois) réduit substanciellement le nombre de bits qui youshe@1001: sont transférés, résultant dans une performance réseau accrue sur youshe@1001: la plupart des supports. youshe@1001: youshe@1001: Si la connexion est au dessus de youshe@1001: ssh, Mercurial ne youshe@1001: recompresse pas le flux puisque youshe@1001: ssh peut déjà le faire par lui même. Vous pouvez youshe@1001: demander à Mercurial de toujours utiliser la compression youshe@1001: ssh en éditant le fichier youshe@1001: .hgrc de votre répertoire personnale comme ci youshe@1001: dessous. youshe@1001: youshe@1001: [ui] bos@701: ssh = ssh -C bos@559: bos@559: bos@559: bos@559: youshe@1001: Ordres de Lecture/Écriture et atomicité youshe@1001: youshe@1001: Ajouter à la fin des fichiers n'est pas toute youshe@1001: l'histoire lorsque l'on cherche à garantir que le lecteur ne verra youshe@1001: pas qu'une écriture partielle. Si vous relisez , les révisions dans le changelog youshe@1001: pointent vers les révisions dans le manifest, et les révisions du youshe@1001: manifest pointent vers les révisions du filelog. Cette hiérarchie est youshe@1001: délibérée. youshe@1001: youshe@1001: L'écriture commence une transaction en écrivant dans youshe@1001: le filelog et dans les données du manifest, et n'écrit aucune donnée youshe@1001: changelog tant que ce n'est pas terminé. La lecture commence en youshe@1001: lisant les données du changelog, puis les données du manifest, et youshe@1001: enfin les données du filelog. youshe@1001: youshe@1001: Puisque que l'écriture ne finit pas d'écrire les youshe@1001: données du filelog et du manifest avant d'écrire dans le changelog, youshe@1001: la lecture ne verra jamais un pointeur vers une révision du manifest youshe@1001: partiellement écrite à partir du changelog, et ne lira jamais un youshe@1001: pointeur vers une révision du filelog partiellement écrite dans le youshe@1001: manifest. youshe@1001: youshe@1001: youshe@1001: youshe@1001: Accès concurrent youshe@1001: youshe@1001: La garantie de l'ordre de lecture/écriture et youshe@1001: de l'atomicite signifie que Mercurial n'a jamais besoin de poser de youshe@1001: lock sur un dépôt lorsqu'il lit des données, youshe@1001: même si le dépôt est en train d'être écrit au même moment que la youshe@1001: lecture a lieue. Ceci a un grand impact sur la fiabilité ; vous youshe@1001: pouvez avoir un nombre arbitraire de processus Mercurial qui lisent youshe@1001: dans risque en même temps les données d'un dépôt, peu importe s'il youshe@1001: est en train d'être lu ou non. youshe@1001: youshe@1001: La nature sans lock de la lecture youshe@1001: signifie que si vous partagez un dépôt sur un système youshe@1001: multi-utilisateurs, vous n'avez pas besoin de donner aux autres youshe@1001: utilisateurs locaux la permission d'écrire sur youshe@1001: votre dépôt pour qu'ils soient capable de faire un clone ou un pull youshe@1001: des changements à partir de celui ci ; ils ont seulement besoin de la youshe@1001: permission en lecture. (Il youshe@1001: ne s'agit pas d'une youshe@1001: fonctionnalité commune à travers les systèmes de gestion de révision, youshe@1001: donc ne prenez pas ça pour garanti ! La plupart ont besoin que les youshe@1001: lecteurs soient capables de mettre un lock sur le dépôt pour y youshe@1001: accéder en toute sécurité, et ceci demande des permissions en youshe@1001: écriture, sur au moins un dépertoire, ce qui provoque biensûr toutes youshe@1001: sortes de problèmes néfastes et ennuyants relatifs à la sécurité et à youshe@1001: l'administration.) youshe@1001: youshe@1001: Mercurial utilise des locs pour assurer qu'un seul youshe@1001: processus peut écrire dans le dépôt à un moment donné (le mécanisme youshe@1001: de lock est sûr, même sur des systèmes de fichiers qui sont connus youshe@1001: pour être hostiles aux locks, comme NFS). Si un dépôt dispose d'un youshe@1001: lock, un processus qui cherche à écrire va attendre un peu avant de youshe@1001: retenter pour voir si le dépôt perd son lock, mais le dépôt garde youshe@1001: trop longtemps son lock, le processus qui tente d'écrire va expirer youshe@1001: (time out) après un moment. Celà veut dire par exemple que vous youshe@1001: scripts lancés quotidiennement n'attendront pas toujours et boucler youshe@1001: si un système crashait sans avertissement, par exemple. (Oui, le youshe@1001: timeout est configurable, de zéro à l'infini.) bos@559: bos@559: youshe@1001: Accès dirstate sûr youshe@1001: youshe@1001: Comme avec les données de révision, Mercurial ne prend pas youshe@1001: de lock pour lire le fichier dirstate ; il n'acquier pas un lock pour youshe@1001: y écrire. Pour empécher la possibilité de lire une copie partiellement youshe@1001: écrite du fichier dirstate, Mercurial écrit à un fichier avec un nom youshe@1001: unique dans le même répertoire que le fichier dirstate, ensuite renomme youshe@1001: le fichier temporaire automatiquement en dirstate. youshe@1001: Le fichier nommé dirstate est ainsi garanti d'être youshe@1001: écrit totalement, et non partiellement. bos@559: bos@559: bos@559: bos@559: youshe@1001: Empécher les recherches youshe@1001: youshe@1001: L'absence de recherche sur les têtes de disques est youshe@1001: critique pour la performance de Mercurial, puisque toute recherche youshe@1001: est beaucoup plus coûteuse comparativement à une grosse opération de youshe@1001: lecture. youshe@1001: youshe@1001: C'est pour ça, par exemple, que le dirstate est stocké youshe@1001: dans un unique fichier. S'il y avait eu un dirstate par répertoire youshe@1001: que Mercurial suivait, le disque aurait recherché une fois par youshe@1001: répertoire. Au lieu de ça, Mercurial lit entièrement un unique youshe@1001: fichier, en une étape. youshe@1001: youshe@1001: Mercurial utilise aussi un schéma copie à youshe@1001: l'écriture lorsqu'il clone un dépôt sur un stockage local. youshe@1001: Au lieu de copier chaque fichier revlog depuis l'ancien dépôt vers le youshe@1001: nouveau dépôt, il crée un lien physique, qui est le youshe@1001: plus court chemin pour dire Ces deux noms pointent vers le youshe@1001: même fichier. Lorsque Mercurial est sur le point d'écrire youshe@1001: sur l'un des revlogs de ces fichiers, il vérifie si le nombre de noms youshe@1001: pointant sur ce fichier est plus grand que un. Si c'est le cas, plus youshe@1001: d'un dépôt utilise le fichier, donc Mercurial crée une nouvelle copie youshe@1001: du fichier qui est privée à ce dépôt. youshe@1001: youshe@1001: Quelques développeurs de systèmes de gestion de youshe@1001: révision ont montré que cette idée de faire une copie privée complète youshe@1001: d'un fichier n'est pas vraiment efficace dans son utilisation du youshe@1001: stockage. Bien que ce soit vrai, le stockage est peu onéreux, et youshe@1001: cette méthode donne la plus grande performance lorsque l'on reporte youshe@1001: la plupart des journalisations au système d'exploitation. Un schéma youshe@1001: alternatif réduirait certainement la performance tout en augmentant youshe@1001: la complexité du logiciel, mais la vitesse et la simplicité sont els youshe@1001: clefs du sentiment de l'utilisation youshe@1001: quotidienne. youshe@1001: youshe@1001: youshe@1001: youshe@1001: Autres contenus du dirstate youshe@1001: youshe@1001: Puisque Mercurial ne vous force pas à dire lorsque youshe@1001: vous modifiez un fichier, il utilise le dirstate pour stocker youshe@1001: certaines informations supplémentaires pour déterminer efficacement youshe@1001: si vous avez ou non modifié un fichier. Pour chaque fichier du youshe@1001: répertoire de travail, il stocke l'heure à laquelle il a été modifié, youshe@1001: ainsi que la taille du fichier à cette heure. youshe@1001: youshe@1001: Lorsque vous faites explicitement un hg add, hg youshe@1001: remove, hg rename ou youshe@1001: hg copy sur des fichiers, Mercurial youshe@1001: met à jour le dirstate afin de savoir quoi faire lorsque vous youshe@1001: effectuez un commit. youshe@1001: youshe@1001: Le dirstate aide Mercurial à vérifier efficacement le youshe@1001: status des fichiers dans un dépôt. bos@701: bos@701: youshe@1001: Lorsque Mercurial vérifie l'état d'un youshe@1001: fichier du répertoire de travail, il compare d'abord la date de youshe@1001: dernière modification du fichier avec celle enregistrée dans le youshe@1001: dirstate qui correspond à Mercurial a écrit en dernier sur ce youshe@1001: fichier. Si le temps de dernière modification correspond au temps youshe@1001: où Mercurial a écrit le fichier, celui ci n'a pas été modifié, youshe@1001: donc mercurial n'a pas besoin de revérifier. youshe@1001: Si la taille du fichier a changé, celui youshe@1001: ci a été modifié. Si la date de modification a changé mais que la youshe@1001: taille est restée inchangée, seulement à ce moment là Mercurial youshe@1001: doit vérifier le contenu du fichier pour savoir s'il a été youshe@1001: modifié. bos@701: bos@701: youshe@1001: Enregistrer la date de modification et la taille youshe@1001: réduit grandement le nombre d'opérations de lecture que Mercurial youshe@1001: doit effectuer lorsque l'on utilise une commande comme hg youshe@1001: status. Le résultat est un grand gain de youshe@1001: performance. bos@559: bos@559: belaran@964:
belaran@964: belaran@964: