belaran@964: belaran@964: bos@559: bos@572: youshe@993: Derrière le décor youshe@993: wilk@1008: À la différence de beaucoup d'outils de gestion de révisions, 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. wilk@1008: Bien que leur connaissance ne soit pas indispensable, 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, wilk@1008: s'il m'est facile de garder en tête ce que le logiciel fait lorsque andre@1017: j'accomplis 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 andre@1017: 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 wilk@1008: dans le filelog contient assez d'informations pour reconstituer une wilk@1008: révision du fichier correspondant. Les filelogs sont des fichiers youshe@993: stockés dans le répertoire .hg/store/data. Un filelog contient andre@1017: 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 wilk@1008: historique, son filelog se voit stocké 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 wilk@1008: 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 wilk@1008: leurs <quote>filelogs</quote> 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 wilk@1008: 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: wilk@1008: Enregistrer les informations des <quote>changesets</quote> youshe@1001: youshe@1001: Le changelog contient les wilk@1008: informations sur chaque changeset. Chaque révision enregistre qui a wilk@1008: committé un changement, le commentaire du changeset, d'autres wilk@1008: morceaux d'information relatives au changeset et la révision du wilk@1008: manifest à utiliser. youshe@1001: youshe@1001: youshe@1001: youshe@1001: Relations entre les révisions youshe@1001: andre@1017: À l'intérieur d'un changelog, d'un manifest, ou d'un wilk@1008: 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: wilk@1008: Pour chaque changeset dans un dépôt, il y a exactement wilk@1008: une révision stockée dans le changelog. Chaque révision du changelog wilk@1008: contient un pointeur vers une unique révision du manifest. Une wilk@1008: révision du manifest garde un pointeur vers une unique révision pour wilk@1008: 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: wilk@1008: Comme l'illustration le montre, il youshe@1001: n'y a pas de relation wilk@1008: un à un entre les révisions dans un changelog, wilk@1008: manifest ou filelog. Si un fichier que Mercurial suit n'a pas changé wilk@1008: entre deux changesets, l'entrée pour ce fichier dans les deux wilk@1008: révisions du manifest pointera vers la même révision de son filelog youshe@1001: Il est possible (bien qu'inhabituel) wilk@1008: qu'un manifest reste le même entre deux changesets, auquel cas wilk@1008: l'entrée du changelog pour ces changesets pointera vers la même wilk@1008: révision du manifest. youshe@1001: . bos@559: bos@559:
bos@559:
bos@559: youshe@1001: Stockage sûr et efficace youshe@1001: wilk@1008: Les fondements des changelogs, des manifests et des wilk@1008: filelogs sont fournis par une unique structure appelée le bos@559: revlog. bos@559: bos@559: andre@1017: Stockage efficace youshe@1001: wilk@1008: Le revlog fournit un stockage efficace des révisions en andre@1017: utilisant un mécanisme delta. Au lieu de stocker youshe@1001: une copie complète d'un fichier à chaque révision, il stocke les wilk@1008: changements requis pour transformer une révision plus ancienne en une andre@1017: nouvelle révision. Pour plusieurs types 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: wilk@1008: Certains systèmes de gestion de révisions obsolè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 wilk@1008: données à la fin d'un fichier revlog. Il ne modifie jamais la section wilk@1008: d'un fichier après qu'il l'ait écrite. C'est à la fois 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: wilk@1008: De plus, Mercurial traite chaque écriture comme la youshe@1001: partie d'une transaction qui peut comprendre youshe@1001: plusieurs fichiers. Une transaction est atomique andre@1017: : soit 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 andre@1017: 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 wilk@1008: snapshot. (Certains basent le snapshot sur la plus youshe@1001: vieille révision, d'autres sur la plus récente.) Pour reconstruire wilk@1008: une révision spécifique, vous devez d'abord lire le snapshot, et wilk@1008: 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:
wilk@1008: <quote>Snapshot</quote> d'un <quote>revlog</quote>, avec des deltas incrémentaux youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: andre@1017: L'innovation que Mercurial apporte à ce problème est andre@1017: simple mais efficace. Une fois que la quantité cumulée de deltas youshe@1001: d'informations stockées depuis le dernier snapshot excède un seuil wilk@1008: fixé, il stocke un nouveau snapshot (compressé bien sû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 wilk@1008: l'idée. Dans une entrée d'un fichier d'index de revlog, Mercurial wilk@1008: stocke l'intervalle 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: andre@1017: Aparté : l'influence de la compression vidéo youshe@1001: youshe@1001: Si vous êtes familiés de la compression vidéo ou andre@1017: avez déjà regardé un programme TV par câble ou par un service youshe@1001: satellite, vous devez savoir que la plupart des schémas de andre@1017: compression vidéo stockent chaque trame de vidéo comme un delta andre@1017: vis-à-vis de la trame 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 wilk@1008: identifiants pour les révisions. Les hashs d'identifications d'un wilk@1008: changeset que vous voyez comme utilisateur final proviennent des wilk@1008: révisions du changelog. Bien que les filelogs et le manifest andre@1017: utilisent aussi des hashs, Mercurial ne les utilise qu'en andre@1017: arrière-plan. youshe@1001: wilk@1008: Mercurial vérifie que les hashs 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é, wilk@1008: il se plaindra 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 wilk@1008: récupérations, l'utilisation par Mercurial de snapshots périodiques youshe@1001: fait qu'il est plus robuste contre la corruption partielle de wilk@1008: 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 wilk@1008: 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 wilk@1008: stockage de deltas seul. bos@559: bos@559:
bos@701: bos@559: youshe@1001: Historique des révisions, branches et fusions (merge) youshe@1001: wilk@1008: Chaque entrée dans un revlog Mercurial connaît wilk@1008: l'identité de l'ancêtre immédiat de la révision, habituellement désignée 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 wilk@1008: hash spécial, appelé le null ID pour représenter l'idée wilk@1008: 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 wilk@1008: voir un exemple de la structure conceptuelle d'un revlog. Les filelogs, wilk@1008: manifests et changelogs ont tous cette même structure ; ils diffèrent youshe@1001: simplement dans le type de donnée stockée dans chaque delta ou wilk@1008: snapshot. wilk@1008: wilk@1008: La première révision d'un revlog (au bas de l'image) a wilk@1008: 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 wilk@1008: 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:
wilk@1008: Le concept de la structure d'un <quote>revlog</quote> 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: wilk@1008: Dans un répertoire de travail, Mercurial stocke une image wilk@1008: des fichiers du dépôt à un changeset particulier. youshe@1001: youshe@1001: Le répertoire de travail sait quel wilk@1008: changeset il contient. Lorsque vous mettez à jour (update) le wilk@1008: répertoire de travail à un certain changeset, Mercurial regarde la wilk@1008: révision appropriée du manifest pour trouver quels fichiers il suivait wilk@1008: 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 wilk@1008: ces fichiers, avec le même contenu qu'ils avaient lorsque le changeset wilk@1008: 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 wilk@1008: 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 wilk@1008: répertoire de travail. Il permet aussi à Mercurial de connaître wilk@1008: rapidement les fichiers modifiés, en enregistrant l'heure de wilk@1008: dernière modification et la taille de chacun. wilk@1008: wilk@1008: 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 wilk@1008: 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 wilk@1008: hg update, le changeset que vous youshe@1001: mettez à jour est stocké dans l'emplacement du premier wilk@1008: 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 wilk@1008: 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: andre@1017: Que se passe-t-il lorsque vous <quote>committez</quote> wilk@1008: wilk@1008: Le dirstate stocke les informations sur les parents andre@1017: pour plus qu'une simple comptabilité. Mercurial utilise les andre@1017: parents du dirstate comme les parents d'un nouveau wilk@1008: 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 wilk@1008: normal d'un répertoire de travail, où il n'y a qu'un seul changeset wilk@1008: comme parent. Ce changeset est le tip, le wilk@1008: 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 wilk@1008: <quote>commit</quote> youshe@1001: youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: wilk@1008: On peut se représenter le répertoire de travail comme wilk@1008: le changeset que je vais committer. Chaque fichier wilk@1008: que vous demandez à Mercurial d'ajouter, de supprimer, de renommer ou de wilk@1008: copier va être intégré dans ce changeset, tout comme les youshe@1001: modifications de n'importe quel fichier que Mercurial est déjà en wilk@1008: train de suivre ; 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 wilk@1008: parents du répertoire de travail, ainsi, le premier parent est l'ID wilk@1008: du nouveau changeset, et le second, le null ID. Ceci est illustré dans youshe@1001: . Mercurial ne touche wilk@1008: à 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: wilk@1008: Il est parfaitement normal de faire un update du wilk@1008: répertoire de travail à un changeset autre que le tip courant. Par wilk@1008: exemple, vous pourriez vouloir savoir à quoi votre projet wilk@1008: ressemblait mardi dernier, ou regarder le changeset qui a youshe@1001: introduit un bug. Dans des cas comme ça, la chose naturelle à faire wilk@1008: 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 andre@1017: contenus comme ils l'étaient lorsque vous avez committé ce changeset. youshe@1001: L'effet de ceci est montré dans . bos@559: bos@591:
wilk@1008: Le répertoire de travail, <quote>updaté</quote> pour un <quote>changeset</quote> plus youshe@1001: ancien youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: wilk@1008: En ayant fait un update du répertoire de travail vers andre@1017: un changeset plus ancien, que se passe-t-il si vous faites des wilk@1008: changements et ensuite committez ? Mercurial se comporte comme je youshe@1001: l'ai fait remarqué plus haut. Les parents du répertoire de travail wilk@1008: deviennent les parents du nouveau changeset. Ce nouveau changeset n'a wilk@1008: pas d'enfant, donc il devient le nouveau tip. Le dépôt contient wilk@1008: maintenant deux changesets qui n'ont pas d'enfant ; on appelle ceci wilk@1008: des heads. Vous pouvez voir la structure que youshe@1001: cela crée dans . bos@559: bos@591:
wilk@1008: Après un <quote>commit</quote> fait pendant la synchronisation avec un ancien wilk@1008: <quote>changeset</quote> youshe@1001: youshe@1001: XXX add text youshe@1001: bos@591:
bos@559: bos@559: andre@1017: Si vous êtes un nouvel utilisateur de 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 wilk@1008: 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 wilk@1008: rester synchronisé au même changeset qu'il l'était avant le pull. wilk@1008: Si vous faites des changements et committez ensuite, vous allez wilk@1008: créer une nouvelle head puisque votre répertoire de travail n'est wilk@1008: pas synchronisé au tip actuel. Pour combiner les wilk@1008: opérations d'un pull suivi d'un update, exécutez hg youshe@1001: pull -u. youshe@1001: youshe@1001: Je place le mot erreur entre andre@1017: guillemets parce que tout ce dont vous avez besoin de faire pour wilk@1008: 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 wilk@1008: changeset avec lequel vous fusionnez (merge), comme montré dans . bos@559: bos@591:
wilk@1008: Fusionner (merge) deux <quote>heads</quote> 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 wilk@1008: 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 wilk@1008: chaque fichier dans le manifest de chaque changeset. youshe@1001: bos@559: wilk@1008: Si aucun changeset n'a modifié un fichier, youshe@1001: ne rien faire avec ce fichier. wilk@1008: 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. wilk@1008: 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. wilk@1008: 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: andre@1017: Si chacun des changesets 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 andre@1017: une intervention de l'utilisateur. wilk@1008: 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 andre@1017: corner cases&emdash;mais ceux-ci sont des choix plus communs qui sont andre@1017: liés à une fusion (merge). Comme vous pouvez le voir, la youshe@1001: plupart des cas sont entièrement automatiques, et effectivement, la andre@1017: plupart des fusions (merge) se terminent automatiquement, sans nécessiter andre@1017: votre intervention pour résoudre un conflit. youshe@1001: youshe@1001: Lorsque vous pensez à ce qu'il se passe lorsque vous wilk@1008: 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 andre@1017: merge soit terminée, le répertoire de travail a deux youshe@1001: parents ; ceux ci vont devenir les parents du nouveau wilk@1008: changeset. youshe@1001: youshe@1001: Mercurial vous permet d'exécuter de multiples fusions, wilk@1008: mais vous devez committer le résultat de chaque fusion individuellement wilk@1008: au fur et à mesure. Ceci est nécessaire puisque Mercurial ne stocke youshe@1001: que deux parents pour chaque révision et le répertoire de travail. wilk@1008: Alors qu'il serait techniquement faisable de fusionner de multiples andre@1017: changesets en même temps, Mercurial interdit cela pour être plus simple. Avec wilk@1008: des fusions multiples, les risques de confusion pour l'utilisateur, de andre@1017: mauvaie résolution de conflits, et de pagaille dans les fusions andre@1017: augmenteraient de façon intolérable. 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 andre@1017: révisions fait peu ou pas attention à un nom de fichier 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 andre@1017: dites d'exécuter un renommage ou une copie. Il utilise ces metadatas youshe@1001: durant une fusion pour faire les bonnes choses dans le cas d'un wilk@1008: 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 wilk@1008: aura les changements appliqués. youshe@1001: bos@620: bos@559:
bos@620: bos@559: youshe@1001: D'autres fonctionnalités intéressantes youshe@1001: wilk@1008: 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 à wilk@1008: 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 andre@1017: trouve personnellement intéressants. J'en détaillerai quelques-uns wilk@1008: 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 wilk@1008: de la quantité d'ingéniosité qu'il y a derrière un système bien wilk@1008: conçu. youshe@1001: youshe@1001: andre@1017: Compression astucieuse youshe@1001: youshe@1001: Lorsque cela est approprié, Mercurial stocke les wilk@1008: snapshots et deltas sous une forme compressée. Il le fait en wilk@1008: essayant toujours de compresser un snapshot ou wilk@1008: un delta, mais en ne stockant la version compressée 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: andre@1017: 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 wilk@1008: snapshot complet du fichier, alors il stocke le snapshot, en gagnant wilk@1008: encore de la place en comparaison d'une approche naïve avec un delta youshe@1001: seulement. bos@559: bos@559: andre@1017: Recompression sur le réseau youshe@1001: youshe@1001: Lors du stockage des révisions sur le disque, youshe@1001: Mercurial utilise l'algorithme de compression andre@1017: deflate (le même que celui utilisé pour le format populaire andre@1017: d'archive zip), qui est un bon wilk@1008: compromis 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: wilk@1008: Si la connexion passe par 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 wilk@1008: Burrows-Wheeler utilisé principalement par le logiciel de youshe@1001: compression bzip2). Cette combinaison de andre@1017: l'algorithme et de la compression du flux entier (plutôt que pour une wilk@1008: révision à la fois) réduit substantiellement le nombre de bits qui wilk@1008: sont transférés, résultant en une performance réseau accrue sur youshe@1001: la plupart des supports. youshe@1001: wilk@1008: Si la connexion passe par youshe@1001: ssh, Mercurial ne youshe@1001: recompresse pas le flux puisque andre@1017: 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 wilk@1008: .hgrc de votre répertoire personnel comme ci-dessous. wilk@1008: youshe@1001: youshe@1001: [ui] bos@701: ssh = ssh -C bos@559: bos@559: bos@559: bos@559: andre@1017: Ordre de lecture/écriture et atomicité youshe@1001: wilk@1008: L'histoire ne se résume pas à ajouter à la fin des fichiers wilk@1008: 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 wilk@1008: pointent vers les révisions dans le manifest, et les révisions du wilk@1008: manifest pointent vers les révisions du filelog. Cette hiérarchie est youshe@1001: délibérée. youshe@1001: wilk@1008: L'écriture commence par une transaction en écrivant dans wilk@1008: le filelog et dans les données du manifest, et n'écrit aucune donnée wilk@1008: du changelog tant que ce n'est pas terminé. La lecture commence en wilk@1008: lisant les données du changelog, puis les données du manifest, et wilk@1008: enfin les données du filelog. youshe@1001: youshe@1001: Puisque que l'écriture ne finit pas d'écrire les wilk@1008: données du filelog et du manifest avant d'écrire dans le changelog, wilk@1008: la lecture ne verra jamais un pointeur vers une révision du manifest wilk@1008: partiellement écrite à partir du changelog, et ne lira jamais un wilk@1008: pointeur vers une révision du filelog partiellement écrite dans le wilk@1008: 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 wilk@1008: de l'atomicité 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 wilk@1008: lecture a lieu. Ceci a un grand impact sur la fiabilité ; vous youshe@1001: pouvez avoir un nombre arbitraire de processus Mercurial qui lisent wilk@1008: sans risque les données d'un dépôt en même temps, 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 wilk@1008: votre dépôt pour qu'ils soient capable de faire un clone ou un pull andre@1017: 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 wilk@1008: fonctionnalité commune à travers les systèmes de gestion de révisions, andre@1017: donc ne prenez pas ça pour argent comptant ! 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 wilk@1008: écriture, sur au moins un répertoire, ce qui provoque bien sûr toutes andre@1017: sortes de problèmes pénibles et agaçants relatifs à la sécurité et à youshe@1001: l'administration.) youshe@1001: wilk@1008: Mercurial utilise des locks pour assurer qu'un seul youshe@1001: processus peut écrire dans le dépôt à un moment donné (le mécanisme wilk@1008: de lock est sûr, même sur des systèmes de fichiers qui sont connus wilk@1008: pour être hostiles aux locks, comme NFS). Si un dépôt dispose d'un wilk@1008: lock, un processus qui cherche à écrire va attendre un peu avant de wilk@1008: retenter pour voir si le dépôt perd son lock, mais si le dépôt garde wilk@1008: trop longtemps son lock, le processus qui tente d'écrire va expirer wilk@1008: (time out) après un moment. Cela veut dire par exemple que vos wilk@1008: scripts lancés quotidiennement n'attendront pas toujours et boucleront wilk@1008: si un système plantait sans avertissement, par exemple. (Oui, le youshe@1001: timeout est configurable, de zéro à l'infini.) bos@559: bos@559: wilk@1008: Accès <quote>dirstate</quote> sûr wilk@1008: wilk@1008: Comme avec les données de révision, Mercurial n'utilise pas wilk@1008: de lock pour lire le fichier dirstate ; il n'acquiert pas un lock pour wilk@1008: y écrire. Pour empêcher la possibilité de lire une copie partiellement wilk@1008: écrite du fichier dirstate, Mercurial écrit sur un fichier avec un nom wilk@1008: 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: wilk@1008: 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: wilk@1008: C'est pour ça, par exemple, que le dirstate est stocké wilk@1008: dans un fichier unique. S'il y avait eu un dirstate par répertoire wilk@1008: que Mercurial suivrait, le disque aurait recherché une fois par wilk@1008: répertoire. Au lieu de ça, Mercurial lit entièrement un wilk@1008: fichier unique, 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. wilk@1008: 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 wilk@1008: révisions ont montré que cette idée de faire une copie privée complète wilk@1008: d'un fichier n'est pas vraiment efficace au niveau 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 wilk@1008: la complexité du logiciel, mais la vitesse et la simplicité sont les wilk@1008: clefs du confort de l'utilisation youshe@1001: quotidienne. youshe@1001: youshe@1001: youshe@1001: wilk@1008: Autres contenus du <quote>dirstate</quote> wilk@1008: wilk@1008: Puisque Mercurial ne vous force pas à signaler que wilk@1008: 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 andre@1017: met à jour le dirstate afin de savoir que faire lorsque vous wilk@1008: effectuez un commit. wilk@1008: wilk@1008: Le dirstate aide Mercurial à vérifier efficacement le wilk@1008: statut 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 wilk@1008: dirstate qui correspond à celle que Mercurial a écrit en dernier sur ce andre@1017: fichier. Si la date de dernière modification correspond à la date youshe@1001: où Mercurial a écrit le fichier, celui ci n'a pas été modifié, andre@1017: donc Mercurial n'a pas besoin de revérifier. wilk@1008: Si la taille du fichier a changé, celui-ci wilk@1008: 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: