belaran@964: belaran@964: belaran@976: belaran@976: belaran@976: Un rapide tour de Mercurial: fusionner les travaux belaran@976: belaran@976: Nous avons maintenant étudié comment cloner un dépôt, effectuer belaran@976: des changements dedans, et récupérer ou transférer depuis un belaran@976: autre dépôt. La prochaine étape est donc de fusionner les belaran@976: modifications de différents dépôts. belaran@976: belaran@976: belaran@976: Fusionner différents travaux belaran@997: La fusion est un aspect fondamental lorsqu'on belaran@976: travaille iavec un gestionnaire de source distribué. belaran@976: belaran@976: belaran@995: belaran@995: Alice et Bob ont chacun une copie personnelle du dépôt d'un belaran@995: projet sur lequel ils collaborent. Alice corrige un bug belaran@995: dans son dépôt, et Bob ajoute une nouvelle fonctionnalité dans le belaran@995: sien. Ils veulent un dépôt partagé avec à la fois le correctif du belaran@995: bug et la nouvelle fonctionnalité. belaran@995: belaran@995: belaran@995: Je travaille régulièrement sur plusieurs tâches différentes sur belaran@995: un seul projet en même temps, chacun isolé dans son propre dépôt. belaran@995: Travailler ainsi signifie que je dois régulièrement fusionner une belaran@995: partie de mon code avec celui des autres. belaran@995: belaran@995: belaran@995: belaran@995: Parce que la fusion est une opération si commune à réaliser, belaran@995: Mercurial la rend facile. Étudions ensemble le déroulement des belaran@995: opérations. Nous commencerons encore par faire un clone d'un autre belaran@995: dépôt (vous voyez que l'on fait ça tout le temps ?) puis nous ferons belaran@995: quelques modifications dessus. belaran@995: belaran@995: &interaction.tour.merge.clone; belaran@995: belaran@995: Nous devrions avoir maintenant deux copies de belaran@995: hello.c avec des contenus différents. Les belaran@995: historiques de ces deux dépôts ont aussi divergés, comme illustré dans belaran@995: la figure . belaran@995: belaran@995: &interaction.tour.merge.cat1; belaran@995: belaran@995: Et ici est notre légèrement différente version du belaran@995: dépôt. belaran@995: belaran@995: &interaction.tour.merge.cat2; belaran@995: belaran@995:
belaran@995: Historique divergent des dépôts <filename belaran@995: class="directory">my-hello</filename> et <filename belaran@995: class="directory">my-new-hello</filename>. belaran@995: belaran@995: belaran@995: XXX ajoute un test belaran@995: belaran@995:
belaran@995: belaran@995: Nous savons déjà que récupérer les modifications depuis belaran@995: notre dépôt my-hello n'aura belaran@995: aucun effet sur l'espace de travail. belaran@995: belaran@995: &interaction.tour.merge.pull; belaran@995: belaran@995: Néanmoins, la commande hg belaran@995: pull nous indique quelque chose au sujet des belaran@995: heads. belaran@995: belaran@995: belaran@995: Les révisions 'heads' belaran@995: belaran@995: Rappellez vous que Mercurial enregistre quelle révision belaran@995: est le parent de chaque révision. Si une révision a un parent, nous belaran@995: l'appelons un enfant(child) ou un descendant de ce parent. Une belaran@995: "head" est une révision qui n'a donc pas d'enfant. La révision tip belaran@995: est donc une "head", car c'est la révision la plus récente du dépôt belaran@995: qui n'a pas d'enfant. Il y a des moments où un dépôt peut contenir belaran@995: plusieurs "head". belaran@995: belaran@997:
belaran@995: Contenu du dépôt après une récupération ("pull") depuis le belaran@995: dépôt <filename belaran@995: class="directory">my-hello</filename> vers le dépôt <filename belaran@995: class="directory">my-new-hello</filename> belaran@995: belaran@995: belaran@995: belaran@995: belaran@995: XXX ajoute un texte belaran@995: belaran@995:
belaran@995: belaran@995: Dans la figure , belaran@995: vous pouvez constater l'effet d'un \textit{pull} depuis le dépôt belaran@995: my-hello dans le dépôt belaran@995: my-new-hello. L'historique qui belaran@995: était déjà présent dans le dépôt my-new-hello reste intact, mais une belaran@995: nouvelle révision a été ajoutée. En vous reportant à la figure , vous pouvez voir que le belaran@995: ID de révision (changeset ID) reste le même dans belaran@995: le nouveau dépôt, mais que le numéro de belaran@995: révision reste le même. (Ceci est un parfait exemple de belaran@995: pourquoi il n'est fiable d'utiliser les numéros de révision lorsque belaran@995: l'on discute d'un \textit{changeset}.) Vous pouvez voir les "heads" belaran@995: présentes dans le dépôt en utilisant la commande hg heads. belaran@995: belaran@995: &interaction.tour.merge.heads; belaran@995:
belaran@995: belaran@995: belaran@995: Effectuer la fusion belaran@995: belaran@997: Que se passe-t-il quand vous essayez d'utiliser la belaran@995: commande hg update pour mettre à belaran@995: jour votre espace de travail au nouveau "tip" belaran@995: belaran@995: &interaction.tour.merge.update; belaran@995: belaran@995: belaran@995: Mercurial nous prévient que la commande hg update n'effectuera pas belaran@995: la fusion, il ne veut pas mettre à jour l'espace de travail quand il belaran@995: estime que nous pourrions avoir besoin d'une fusion, à moins de lui belaran@995: forcer la main. À la place, il faut utiliser la commande hg merge pour fusionner les deux belaran@995: "heads". belaran@995: belaran@995: Pour commencer une fusion (merge) entre deux "heads", belaran@995: nous utilisons la commande hg merge. belaran@995: belaran@995: &interaction.tour.merge.merge; belaran@995: belaran@995: Nous résolvons les conflits dans le fichier belaran@995: hello.c. Ceci met à jour le répertoire de travail belaran@995: de sorte qu'il ne contienne les modifications ne provenance des belaran@995: deux "heads", ce qui est indiqué par la belaran@995: la sortie de la commande hg belaran@995: parents et le contenu du fichier belaran@995: hello.c. belaran@995: belaran@995: &interaction.tour.merge.parents; belaran@995: belaran@995: belaran@995: belaran@995: Effectuer l'ajout (commit) du résultat de la fusion belaran@995: belaran@995: Dès l'instant où vous avez effectué une fusion belaran@995: (merge), hg parents vous belaran@995: affichera deux parents, avant que vous n'exécutiez la commande belaran@995: hg commit sur le résultat de la belaran@995: fusion. belaran@995: belaran@995: &interaction.tour.merge.commit; belaran@995: belaran@995: Nous avons maintenant un nouveau tip, remarquer qu'il belaran@995: contient à la fois nos anciennes "heads" et leurs belaran@995: parents. Ce sont les mêmes révisions que nous avions affichées avec belaran@995: la commande hg parents. belaran@995: belaran@995: &interaction.tour.merge.tip; belaran@995: belaran@995: Dans la figure , belaran@995: vous pouvez voir une représentation de ce qui se passe dans l'espace belaran@995: de travail pendant la fusion, et comment ceci affecte le dépôt lors belaran@995: du "commit". Pendant la fusion, l'espace de travail, qui a deux belaran@995: révisions (changesets) comme parents, voit ces derniers devenir le parent belaran@995: d'une nouvelle révision (changeset). belaran@995: belaran@995:
belaran@995: Working directory and repository during merge, and belaran@995: following commit belaran@995: belaran@995: belaran@995: belaran@995: belaran@995: XXX ajoute texte belaran@995: belaran@995:
belaran@995: belaran@995:
belaran@995:
belaran@995: belaran@995: belaran@995: Fusionner les modifications en conflit belaran@995: belaran@995: La plupart des fusions sont assez simple à réaliser, mais belaran@995: parfois vous vous retrouverez à fusionner des fichiers où la modification belaran@995: touche la même portion de code, au sein d'un même fichier. À moins belaran@995: que ces modification ne soient identiques, ceci aboutira à un belaran@995: conflit, et vous devrez décider comment réconcilier belaran@995: les différentes modifications dans un tout cohérent. belaran@995: belaran@997:
belaran@995: Modifications en conflits dans un document belaran@995: belaran@995: belaran@995: XXX ajoute texte belaran@995: belaran@995:
belaran@995: belaran@995: La figure belaran@995: illustre un cas de modifications conflictuelles dans un document. Nous belaran@995: avons commencé avec une version simple de ce fichier, puis nous avons belaran@995: ajouté des modifications, pendant que quelqu'un d'autre modifiait le même belaran@995: texte. Notre tâche dans la résolution du conflit est de décider à quoi le belaran@995: fichier devrait ressembler. belaran@995: belaran@995: Mercurial n'a pas de mécanisme interne pour gérer belaran@995: les conflits. À la place, il exécute un programme externe appelé belaran@995: hgmerge. Il s'agit d'un script shell qui est belaran@995: embarqué par Mercurial, vous pouvez le modifier si vous le voulez. belaran@995: Ce qu'il fait par défaut est d'essayer de trouver un des différents belaran@995: outils de fusion qui seront probablement installés sur le système. belaran@995: Il commence par les outils totalement automatiques, et si ils belaran@995: échouent (parce que la résolution du conflit nécessite une belaran@995: intervention humaine) ou si ils sont absents, le script tente belaran@995: d'exécuter certains outils graphiques de fusion. belaran@995: belaran@995: Il est aussi possible de demander à Mercurial d'exécuter belaran@995: un autre programme ou un autre script en définissant la variable belaran@995: d'environnement HGMERGE avec le nom belaran@995: du programme de votre choix. belaran@995: belaran@995: belaran@995: Utiliser un outil graphique de fusion belaran@995: belaran@995: Mon outil de fusion préféré est belaran@995: kdiff3, que j'utilise ici pour illustrer les belaran@995: fonctionnalités classiques des outils graphiques de fusion. Vous pouvez belaran@995: voir une capture d'écran de l'utilisation de kdiff3 belaran@995: dans la figure . Cet outil belaran@995: effectue une fusion \textit{three-way}, car il y a belaran@995: trois différentes versions du fichier qui nous intéresse. Le fichier belaran@995: découpe la partie supérieure de la fenêtre en trois panneaux: belaran@995: belaran@995: A gauche on la version de belaran@995: base du fichier, soit la plus récente version belaran@995: des deux versions qu'on souhaite fusionner. belaran@995: Au centre, il y a notre belaran@995: version du fichier, avec le contenu que nous avons modifié. belaran@995: Sur la droite, on trouve belaran@995: leur version du fichier, celui qui contient la belaran@995: révision que nous souhaitons intégré. belaran@995: belaran@995: Dans le panneau en dessous, on trouve le belaran@995: résultat actuel de notre fusion. Notre tâche belaran@995: consiste donc à remplacement tous les textes en rouges, belaran@995: qui indiquent des conflits non résolus, avec une fusion manuelle et belaran@995: pertinente de notre version et de la leur. belaran@995: belaran@995: belaran@997: Tous les quatre panneaux sont accrochés ensemble, belaran@995: si nous déroulons les ascenseurs verticalement ou horizontalement dans chacun belaran@995: d'entre eux, les autres sont mis à jour avec la section correspondante dans leurs belaran@995: fichiers respectifs. belaran@995: belaran@995:
belaran@995: Utiliser <command>kdiff3</command> pour fusionner les belaran@995: différentes version d'un fichier. belaran@995: belaran@995: belaran@995: belaran@995: belaran@995: XXX ajoute texte belaran@995: belaran@995: belaran@995:
belaran@995: belaran@995: Pour chaque portion de fichier posant problème, nous belaran@995: pouvons choisir de résoudre le conflit en utilisant une combinaison de belaran@995: texte depuis la version de base, la notre, ou la leur. Nous pouvons belaran@995: aussi éditer manuellement les fichiers à tout moment, si c'est nécessaire. belaran@995: belaran@995: Il y a beaucoup d'outils de belaran@995: fusion disponibles, bien trop pour en parler de tous ici. Leurs belaran@995: disponibilités varient selon les plate formes ainsi que leurs belaran@995: avantages et inconvénients. La plupart sont optimisé pour belaran@995: la fusion de fichier contenant un texte plat, certains sont spécialisé belaran@995: dans un format de fichier précis (généralement XML). belaran@995:
belaran@995: belaran@995: belaran@995: Un exemple concret belaran@995: belaran@995: Dans cet exemple, nous allons reproduire la belaran@995: modification de l'historique du fichier de la figure ci dessus. Commençons par créer belaran@995: un dépôt avec une version de base de notre document. belaran@995: belaran@995: &interaction.tour-merge-conflict.wife; belaran@995: belaran@995: Créons un clone de ce dépôt et faisons une belaran@995: modification dans le fichier. belaran@995: belaran@995: &interaction.tour-merge-conflict.cousin; belaran@995: belaran@995: Et un autre clone, pour simuler que quelqu'un d'autre effectue une belaran@995: modification sur le fichier. (Ceci pour suggérer qu'il n'est pas rare belaran@995: de devoir effectuer des fusions (merges) avec vos propres travaux quand belaran@995: vous isolez les tâches dans des dépôts distincts. En effet, vous belaran@995: aurez alors à trouver et résoudre certains conflits). belaran@995: belaran@995: &interaction.tour-merge-conflict.son; belaran@995: belaran@995: Maintenant que ces deux versions différentes du même fichier sont belaran@995: créées, nous allons configurer l'environnement de manière appropriée pour belaran@995: exécuter notre fusion (merge). belaran@995: belaran@995: &interaction.tour-merge-conflict.pull; belaran@995: belaran@995: Dans cette exemple, je n'utiliserais pas la commande Mercurial belaran@995: habituelle hgmerge pour effectuer le belaran@995: fusion (merge), car il me faudrait abandonner ce joli petit exemple automatisé belaran@995: pour utiliser un outil graphique. À la place, je vais définir la belaran@995: variable d'environnement HGMERGE pour indiquer à belaran@995: Mercurial d'utiliser la commande non-interactive merge. belaran@995: Cette dernière est embarquée par de nombreux systèmes à la Unix. belaran@995: Si vous exécutez cet exemple depuis votre ordinateur, ne vous belaran@995: occupez pas de définir HGMERGE. belaran@995: belaran@995: &interaction.tour-merge-conflict.merge; belaran@995: belaran@995: belaran@995: Parce que merge ne peut pas résoudre belaran@995: les modifications conflictuelles, il laisse des marqueurs de belaran@995: différences à l'intérieur du fichier qui a des conflits, belaran@995: indiquant clairement quelles lignes sont en conflits, et si elles belaran@995: viennent de notre fichier ou du fichier externe. belaran@995: belaran@995: belaran@995: Mercurial peut distinguer, à la manière dont la belaran@995: commande merge se termine, qu'elle n'a pas été belaran@995: capable d'effectuer la fusion (merge), alors il nous indique que nous belaran@995: devons effectuer de nouveau cette opération. Ceci peut être très utile belaran@995: si, par exemple, nous exécutons un outil graphique de fusion et que belaran@995: nous le quittons sans nous rendre compte qu'il reste des conflits ou belaran@995: simplement par erreur. belaran@995: belaran@995: Si la fusion (merge) automatique ou manuelle échoue, belaran@995: il n'y a rien pour nous empêcher de corriger le tir en belaran@995: modifiant nous même les fichiers, et enfin effectuer le "commit" du belaran@995: fichier: belaran@995: belaran@995: &interaction.tour-merge-conflict.commit; belaran@995: belaran@995: belaran@997: Où est la <command>hg resolve</command> ? belaran@995: belaran@995: La commande hg resolve a été belaran@995: introduit dans la version 1.1 de Mercurial, qui a été publié en belaran@995: décembre 2008. Si vous utilisez une version plus anciennne de belaran@995: Mercurial (exécutez la command hg version pour en belaran@995: avoir le coeur net), cette commande ne sera pas disponible. Si votre belaran@995: version de Mercurial est plus ancienne que la 1.1, vous devriez très belaran@995: fortement considérer une mise à jour à une version plus récente avant belaran@995: d'essayer de régler des fusions complexes. belaran@995: belaran@995: belaran@995:
belaran@995: belaran@995: belaran@995: Simplification de la séquence pull-merge-commit belaran@995: belaran@995: La procédure pour effectuer la fusion indiquée belaran@995: ci-dessus est simple, mais requiert le lancement de trois commandes à la belaran@995: suite. belaran@995: belaran@995: hg pull -u belaran@995: hg merge belaran@995: hg commit -m 'Merged remote changes' belaran@995: belaran@995: Lors du "commit" final, vous devez également saisir un belaran@995: message, qui aura vraisemblablement assez peu d'intérêt. belaran@995: belaran@995: Il serait assez sympathique de pouvoir réduire le belaran@995: nombre d'opérations nécessaire, si possible. De fait Mercurial est belaran@995: fourni avec une extension appelé fetch belaran@995: qui fait justement cela. belaran@995: belaran@995: Mercurial fourni un mécanisme d'extension flexible qui permet à chacun belaran@995: d'étendre ces fonctionnalités, tout en conservant le cœur de Mercurial belaran@995: léger et facile à utiliser. Certains extensions ajoutent de nouvelles belaran@995: commandes que vous pouvez utiliser en ligne de commande, alors que belaran@995: d'autres travaillent en coulisse, par exemple en ajoutant des belaran@995: possibilités au serveur. belaran@995: belaran@995: L'extension fetch belaran@995: ajoute une nouvelle commande nommée, sans surprise, hg fetch. Cette extension résulte en une belaran@995: combinaison de hg pull, hg update and hg belaran@995: merge. Elle commence par récupérer les modifications d'un belaran@995: autre dépôt dans le dépôt courant. Si elle trouve que les belaran@995: modifications ajoutent une nouvelle "head", elle effectue un "merge", belaran@995: et ensuite "commit" le résultat du "merge" avec un message généré belaran@995: automatiquement. Si aucune "head" n'ont été ajouté, elle met à jour le belaran@995: répertoire de travail au niveau de la nouvelle révision tip. belaran@995: belaran@995: Activer l'extension fetch est facile. Modifiez votre .hgrc, et soit allez à la section extensions soit créer une section belaran@995: extensions. Ensuite ajoutez belaran@995: une ligne qui consiste simplement en \Verb+fetch =. belaran@995: belaran@995: [extensions] belaran@995: fetch = belaran@995: belaran@995: (Normalement, sur la partie droite de belaran@995: = devrait apparaître le chemin de belaran@995: l'extension, mais étant donné que l'extension fetch fait partie de la distribution standard, belaran@995: Mercurial sait où la trouver.) belaran@995: belaran@995: belaran@995: belaran@995: belaran@995: Renommer, copier, et fusionner (merge) belaran@995: belaran@995: En cours de la vie d'un projet, nous allons souvent belaran@995: vouloir changer la disposition de ses fichiers et de ses répertoires. belaran@995: Ceci peut être aussi simple que de changer le nom d'un seul fichier, belaran@995: et aussi compliqué que de restructurer une hiérarchie entiere de fichier belaran@995: au sein du projet. belaran@995: belaran@995: Mercurial permet de faire ce genre de modification de belaran@995: manière fluide, à condition de l'informer de ce que nous faisons. Si belaran@995: vous voulez renommenr un ficher, vous devriez utiliser les commande belaran@995: hg rename belaran@995: Si vous un utilisateur de Unix, vous serez content belaran@995: de savoir que la commande hg rename command belaran@995: peut être abrégée en hg mv. belaran@995: pour changer son nom, ainsi Mercurial peut ensuite prendre belaran@995: la bonne décision, plus tard, en cas de fusionv (merge). belaran@995: belaran@995: Nous étudierojns en détail l'utilisation de ces commandes, belaran@995: en détail, dans le chapitre . belaran@995: belaran@964:
belaran@964: belaran@964: