SVNBOOK Chap4 Branching and Merging Basic Merging Keeping a Branch in Sync

De Framalang Wiki.

Cette page fait partie du projet Version control with subversion.

Pseudo Code Rôle Statut
Sub Versif SVF Traduction Terminé
Hotshot92 Relecture Fait
Validation


Sommaire

Titre

Keeping a Branch in Sync

Garder une branche synchronisée

Paragraphe 1

Continuing with our running example, let's suppose that a week has passed since you started working on your private branch. Your new feature isn't finished yet, but at the same time you know that other people on your team have continued to make important changes in the project's /trunk. It's in your best interest to replicate those changes to your own branch, just to make sure they mesh well with your changes. In fact, this is a best practice: frequently keeping your branch in sync with the main development line helps prevent “surprise” conflicts when it comes time for you to fold your changes back into the trunk.

Continuons avec notre exemple précédent, et imaginons qu'une semaine a passé depuis que vous avez commencé à travailler sur votre branche privée. Votre nouvelle fonctionnalité n'est pas encore terminée, mais en même temps vous savez que d'autres personnes de votre équipe ont continué à faire des modifications importantes sur le /trunk du projet. Vous avez intérêt à recopier ces modifications dans votre propre branche, juste pour vous assurer qu'elles se combinent bien avec vos modifications. En fait, c'est une bonne pratique : synchroniser fréquemment votre branche avec la ligne de développement principale permet d'éviter les conflits "surprise" le jour où vous reversez vos modifications dans le tronc.

Paragraphe 2

Subversion is aware of the history of your branch and knows when it divided away from the trunk. To replicate the latest, greatest trunk changes to your branch, first make sure your working copy of the branch is “clean”—that it has no local modifications reported by svn status. Then simply run:

Subversion connaît l'historique de votre branche et sait à quel moment elle s'est séparée du tronc. Afin de récupérer les modifications du tronc les plus récentes et les plus importantes, assurez-vous en premier lieu que votre copie de travail est "propre" - que svn status ne liste aucune modification locale. Puis lancez juste :

Paragraphe 3

$ pwd
/home/user/my-calc-branch

$ svn merge http://svn.example.com/repos/calc/trunk
--- Merging r345 through r356 into '.':
U    button.c
U    integer.c
 $ pwd
 /home/utilisateur/ma-branche-calc
 
 $ svn merge http://svn.exemple.com/depot/calc/trunk
 --- Fusion de r345 à r356 dans '.':
 U    bouton.c
 U    entier.c

Paragraphe 4

This basic syntax—svn merge URL—tells Subversion to merge all recent changes from the URL to the current working directory (which is typically the root of your working copy). After running the prior example, your branch working copy now contains new local modifications, and these edits are duplications of all of the changes that have happened on the trunk since you first created your branch:

La syntaxe de base - svn merge URL - indique à Subversion qi'il doit fusionner toutes les modifications récentes depuis l'URL vers le répertoire de travail actuel (qui est bien souvent la racine de votre copie de travail). Après l'exécution de la commande de l'exemple précédent, la copie de travail de votre branche contient de nouvelles modifications locales, ces changements étant des duplications de toutes les modifications qui ont eu lieu sur le tronc depuis que vous avez créé votre branche :

Paragraphe 5

$ svn status
 M     .
M      button.c
M      integer.c
$ svn status
 M     .
M      bouton.c
M      entier.c

Paragraphe 6

At this point, the wise thing to do is look at the changes carefully with svn diff, and then build and test your branch. Notice that the current working directory (“.”) has also been modified; the svn diff will show that its svn:mergeinfo property has been either created or modified. This is important merge-related metadata that you should not touch, since it will be needed by future svn merge commands. (We'll learn more about this metadata later in the chapter.)

Une fois rendu là, le plus sage est d'examiner attentivement les modifications avec svn diff, et ensuite de compiler et de tester votre branche. Notez que le répertoire de travail actuel (".") a aussi été modifié ; svn diff indiquera que sa propriété svn:mergeinfo a été créée ou modifiée. Ceci est une méta-information importante liée à la fusion, à laquelle vous ne devriez pas toucher, puisqu'elle sera nécessaire aux futures commandes svn merge. (Nous en apprendrons plus sur cette métadonnée plus loin dans ce chapitre.)

Paragraphe 7

After performing the merge, you might also need to resolve some conflicts (just as you do with svn update) or possibly make some small edits to get things working properly. (Remember, just because there are no syntactic conflicts doesn't mean there aren't any semantic conflicts!) If you encounter serious problems, you can always abort the local changes by running svn revert . -R (which will undo all local modifications) and start a long “what's going on?” discussion with your collaborators. If things look good, however, you can submit these changes into the repository:

Après avoir effectué la fusion, vous aurez peut-être aussi besoin de résoudre des conflits (comme vous le faites pour svn update) ou éventuellement d'effectuer de petites modifications afin que les choses fonctionnent correctement (Souvenez-vous, ce n'est pas parce qu'il n'y a pas de conflits syntaxiques qu'il n'y a pas de conflits sémantiques !). Si vous rencontrez de graves difficultés, vous pouvez toujours annuler les modifications locales en lançant svn revert . -R (qui annulera toutes les modifications locales) et entamer avec vos collègues une longue discussion sur le thème "Qu'est-ce qui se passe ?". Par contre, si les choses se passent bien, vous pouvez propager ces modifications au dépôt :

Paragraphe 8

$ svn commit -m "Merged latest trunk changes to my-calc-branch."
Sending        .
Sending        button.c
Sending        integer.c
Transmitting file data ..
Committed revision 357.
$ svn commit -m "Fusionné les dernières modifications de trunk avec ma-branche-calc"
Envoi          .
Envoi          bouton.c
Envoi          entier.c
Transmission des données ..
Révision 357 propagée.

Paragraphe 9

At this point, your private branch is now “in sync” with the trunk, so you can rest easier knowing that as you continue to work in isolation, you're not drifting too far away from what everyone else is doing.

À présent, votre branche privée est désormais "synchro" avec le tronc, donc vous pouvez vous détendre, sachant qu'en continuant votre travail en isolation, vous ne dériverez pas trop loin de ce que tous les autres font.

Paragraphe 10

Why Not Use Patches Instead?

A question may be on your mind, especially if you're a Unix user: why bother to use svn merge at all? Why not simply use the operating system's patch command to accomplish the same job? For example:

$ cd my-calc-branch
$ svn diff -r 341:HEAD http://svn.example.com/repos/calc/trunk > patchfile
$ patch -p0  < patchfile
Patching file integer.c using Plan A...
Hunk #1 succeeded at 147.
Hunk #2 succeeded at 164.
Hunk #3 succeeded at 241.
Hunk #4 succeeded at 249.
done

In this particular example, there really isn't much difference. But svn merge has special abilities that surpass the patch program. The file format used by patch is quite limited; it's able to tweak file contents only. There's no way to represent changes to trees, such as the addition, removal, or renaming of files and directories. Nor can the patch program notice changes to properties. If Sally's change had, say, added a new directory, the output of svn diff wouldn't have mentioned it at all. svn diff outputs only the limited patch format, so there are some ideas it simply can't express.

The svn merge command, however, can express changes in tree structure and properties by directly applying them to your working copy. Even more important, this command records the changes that have been duplicated to your branch so that Subversion is aware of exactly which changes exist in each location (see the section called “Mergeinfo and Previews”.) This is a critical feature that makes branch management usable; without it, users would have to manually keep notes on which sets of changes have or haven't been merged yet.

Pourquoi ne pas utiliser des patches à la place?

Une question vous trotte peut-être dans la tête, surtout si vous êtes un utilisateur d'Unix : pourquoi s'embêter à utiliser svn merge ? Pourquoi ne pas tout simplement utiliser la commande de patch du système d'exploitation pour accomplir la même tâche ? Par exemple :

$ cd ma-branche-calc
$ svn diff -r 341:HEAD http://svn.exemple.com/depot/calc/tronc > fichierpatch
$ patch -p0  < fichierpatch
Patching file entier.c using Plan A...
Hunk #1 succeeded at 147.
Hunk #2 succeeded at 164.
Hunk #3 succeeded at 241.
Hunk #4 succeeded at 249.
done

Dans cet exemple, il n'y a pas vraiment pas grande différence. Mais svn merge possède des fonctionnalités spécifiques qui surpassent le programme patch. Le format de fichier utilisé par patch est assez limité ; il ne sait manipuler que les contenus de fichier. Il n'y a pas moyen de représenter des changements dans l'arborescence, tels que l'ajout, la suppression ou le renommage de fichiers ou de dossiers. Le programme patch n'est pas non plus capable de prendre en compte des modifications de propriétés. Si Sally avait, par exemple, ajouté un nouveau dossier, svn diff ne l'aurait pas mentionné du tout en sortie. Le résultat de svn diff est seulement au format patch, il y a donc des concepts qu'il ne peut tout simplement pas exprimer.

La commande svn merge, par contre, peut gérer des modifications dans l'arborescence et dans les propriétés en les appliquant directement à votre copie de travail. Et, ce qui est encore plus important, cette commande enregistre les modifications qui ont été dupliquées vers votre branche de telle sorte que Subversion sait exactement quelles modifications existent dans chaque endroit (voir le paragraphe appelé "Mergeinfos et aperçus"). C'est une fonctionnalité cruciale qui rend la gestion des branches utilisable ; sans elle, les utilisateurs seraient forcés de conserver des notes manuelles relatant quelles listes de modifications ont été fusionnées ou pas.

Paragraphe 11

Suppose that another week has passed. You've committed more changes to your branch, and your comrades have continued to improve the trunk as well. Once again, you'd like to replicate the latest trunk changes to your branch and bring yourself in sync. Just run the same merge command again!

Supposons qu'une autre semaine s'est écoulée. Vous avez livré des modifications supplémentaires dans votre branche, et vos camarades ont également continué à améliorer le tronc. Une fois encore, vous aimeriez répercuter les dernières modifications du tronc vers votre branche et ainsi être synchro. Lancez juste la même commande merge à nouveau !

Paragraphe 12

$ svn merge http://svn.example.com/repos/calc/trunk
--- Merging r357 through r380 into '.':
U    integer.c
U    Makefile
A    README
$ svn merge http://svn.exemple.com/depot/calc/trunk
--- Fusion de r357 à r380 dans '.':
U    bouton.c
U    Makefile
A    LISEZMOI

Paragraphe 13

Subversion knows which trunk changes you've already replicated to your branch, so it carefully replicates only those changes you don't yet have. Once again, you'll have to build, test, and svn commit the local modifications to your branch.

Subversion sait quelles sont les modifications du tronc que vous avez déjà répercutées vers votre branche, il ne répercute donc que les modifications que vous n'avez pas encore. Une fois de plus, vous devrez compiler, tester et livrer les modifications locales à votre branche.

Paragraphe 14

What happens when you finally finish your work, though? Your new feature is done, and you're ready to merge your branch changes back to the trunk (so your team can enjoy the bounty of your labor). The process is simple. First, bring your branch in sync with the trunk again, just as you've been doing all along:

Cependant, que se passe-t-il quand vous finissez enfin votre travail ? Votre nouvelle fonctionnalité est terminée et vous êtes prêt à fusionner les changements de votre branche avec le tronc (pour que votre équipe puisse bénéficier de votre travail). La procédure est simple. Premièrement, synchronisez à nouveau votre branche avec le tronc, comme vous l'avez fait depuis le début :

Paragraphe 15

$ svn merge http://svn.example.com/repos/calc/trunk
--- Merging r381 through r385 into '.':
U    button.c
U    README

$ # build, test, ...

$ svn commit -m "Final merge of trunk changes to my-calc-branch."
Sending        .
Sending        button.c
Sending        README
Transmitting file data ..
Committed revision 390.
$ svn merge http://svn.exemple.com/repos/calc/tronc
--- Fusion de r381 à r385 dans '.':
U    bouton.c
U    LISEZMOI

$ # compiler, tester, ...

$ svn commit -m "Fusion finale des modifications du tronc dans ma-branche-calc."
Envoi          .
Envoi          bouton.c
Envoi          LISEZMOI
Transmission des données ..
Révision 390 propagée.

Paragraphe 16

Now, you use svn merge to replicate your branch changes back into the trunk. You'll need an up-to-date working copy of /trunk. You can do this by either doing an svn checkout, dredging up an old trunk working copy from somewhere on your disk, or using svn switch (see the section called “Traversing Branches”.) However you get a trunk working copy, remember that it's a best practice to do your merge into a working copy that has no local edits and has been recently updated (i.e., is not a mixture of local revisions). If your working copy isn't “clean” in these ways, you can run into some unnecessary conflict-related headaches and svn merge will likely return an error.

À présent vous allez utiliser svn merge pour répercuter les modifications de votre branche sur le tronc. Vous aurez besoin d'une copie de travail de /trunk qui soit à jour. Vous pouvez le faire soit en effectuant un svn checkout, soit en reprenant une vieille copie de travail du tronc, soit en utilisant svn switch (voir le paragraphe appelé "Parcourir les branches".) Quelle que soit la manière dont vous obtenez une copie de travail, souvenez-vous qu'une bonne méthode est d'effectuer la fusion dans une copie de travail qui n'a pas été modifiée localement et qui a été mise à jour récemment (en d'autres termes, qui n'est pas un mélange de révisions locales). Si votre copie de travail n'est pas "propre" comme expliqué à l'instant, vous risquez de rencontrer des problèmes inutiles liés à des conflits, et svn merge renverra probablement une erreur en retour.

Paragraphe 17

Once you have a clean working copy of the trunk, you're ready to merge your branch back into it:

Une fois que vous avez une copie de travail propre du tronc, vous êtes prêt pour y fusionner votre branche :

Paragraphe 18

$ pwd
/home/user/calc-trunk

$ svn update  # (make sure the working copy is up to date)
At revision 390.

$ svn merge --reintegrate http://svn.example.com/repos/calc/branches/my-calc-branch
--- Merging differences between repository URLs into '.':
U    button.c
U    integer.c
U    Makefile
U   .

$ # build, test, verify, ...

$ svn commit -m "Merge my-calc-branch back into trunk!"
Sending        .
Sending        button.c
Sending        integer.c
Sending        Makefile
Transmitting file data ..
Committed revision 391.
$ pwd
/home/user/calc-tronc

$ svn update  # (s'assurer que la copie de travail est à jour)
À la révision 390.

$ svn merge --reintegrate http://svn.exemple.com/depot/calc/branches/ma-branche-calc
--- Fusionne toutes les modifications non fusionnées des URLs sources dans '.':
U    bouton.c
U    entier.c
U    Makefile
U   .

$ # compiler, tester, verifier, ...

$ svn commit -m "Fusionner ma-branche-calc dans le tronc !"
Envoi          .
Envoi          bouton.c
Envoi          entier.c
Envoi          Makefile
Transmission des données ..
Révision 391 propagée.

Paragraphe 19

Congratulations, your branch has now been remerged back into the main line of development. Notice our use of the --reintegrate option this time around. The option is critical for reintegrating changes from a branch back into its original line of development—don't forget it! It's needed because this sort of “merge back” is a different sort of work than what you've been doing up until now. Previously, we had been asking svn merge to grab the “next set” of changes from one line of development (the trunk) and duplicate them to another (your branch). This is fairly straightforward, and each time Subversion knows how to pick up where it left off. In our prior examples, you can see that first it merges the ranges 345:356 from trunk to branch; later on, it continues by merging the next contiguously available range, 356:380. When doing the final sync, it merges the range 380:385.

Félicitations, votre branche a maintenant réintégré la ligne de développement principale. Notez bien l'utilisation de l'option --reintegrate à cette occasion. L'option est essentielle pour répercuter les modifications d'une branche sur sa ligne de développement d'origine - ne l'oubliez pas ! Elle est nécessaire car ce type de "réintégration" est un type de tâche différent de ce que vous avez fait jusqu'à présent. Précédemment, nous demandions à svn merge de faire la liste suivante des modifications d'une ligne de développement (le tronc) et de les dupliquer vers une autre (votre branche). C'est assez simple et à chaque fois Subversion sait reprendre là où il s'était arrêté. Dans nos exemples précédents, vous pouvez voir qu'il fusionne en premier les modifications 345:356 du tronc vers la branche ; ensuite il continue en fusionnant le groupe contigu immédiatement suivant, 356:380. Quand il effectue la synchronisation finale, il fusionne le groupe 380:385.

Paragraphe 20

When merging your branch back to the trunk, however, the underlying mathematics is quite different. Your feature branch is now a mishmosh of both duplicated trunk changes and private branch changes, so there's no simple contiguous range of revisions to copy over. By specifying the --reintegrate option, you're asking Subversion to carefully replicate only those changes unique to your branch. (And in fact, it does this by comparing the latest trunk tree with the latest branch tree: the resulting difference is exactly your branch changes!)

Cependant, lors de la réintégration d'une branche dans le tronc, les mathématiques sous-jacentes sont assez différentes. Votre branche dédiée est à présent un amoncellement de modifications provenant à la fois du tronc et de votre branche privée, et il n'y a donc pas de groupe de révisions contigu à recopier. En spécifiant l'option --reintegrate, vous demandez explicitement à Subversion de ne recopier que les modifications spécifiques à votre branche. (Et en fait il le fait en comparant la dernière arborescence du tronc avec l'arborescence de la branche la plus récente : la différence qui en résulte constitue exactement les modifications de votre branche !).

Paragraphe 21

Now that your private branch is merged to trunk, you may wish to remove it from the repository:

Votre branche privée ayant réintégré le tronc, vous voudrez peut-être la supprimer du dépôt :

Paragraphe 22

$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m "Remove my-calc-branch."
Committed revision 392.
$ svn delete http://svn.exemple.com/depot/calc/branches/ma-branche-calc \
      -m "Supprime ma-branche-calc."
Révision 392 propagée.

Paragraphe 23

But wait! Isn't the history of that branch valuable? What if somebody wants to audit the evolution of your feature someday and look at all of your branch changes? No need to worry. Remember that even though your branch is no longer visible in the /branches directory, its existence is still an immutable part of the repository's history. A simple svn log command on the /branches URL will show the entire history of your branch. Your branch can even be resurrected at some point, should you desire (see the section called “Resurrecting Deleted Items”).

Mais attendez ! L'historique de votre branche ne possède-t-il pas une certaine valeur ? Et si un beau jour quelqu'un voulait auditer l'évolution de votre fonctionnalité et examiner toutes les modifications de votre branche ? Pas la peine de s'inquiéter. Souvenez-vous que même si votre branche n'est plus visible dans le dossier /branches, son existence demeure une partie immuable de l'historique du dépôt. Une simple commande svn log appliquée à l'URL /branches vous renverra l'historique complet de votre branche. Votre branche pourrait même ressusciter un jour ou l'autre, si vous le désirez (voir le paragraphe appelé "Résurrection des éléments effacés").

Paragraphe 24

In Subversion 1.5, once a --reintegrate merge is done from branch to trunk, the branch is no longer usable for further work. It's not able to correctly absorb new trunk changes, nor can it be properly reintegrated to trunk again. For this reason, if you want to keep working on your feature branch, we recommend destroying it and then re-creating it from the trunk:

Dans Subversion 1.5, une fois que la fusion d'une branche vers le tronc a été faite avec l'option --reintegrate, la branche n'est plus utilisable. Elle ne peut absorber correctement de nouvelles modifications du tronc, ni être réintégrée à nouveau proprement dans le tronc. Pour cette raison, si vous voulez continuer à travailler sur la branche de votre fonctionnalité, nous vous recommandons de la détruire et de la recréer depuis le tronc :

Paragraphe 25

$ svn delete http://svn.example.com/repos/calc/branches/my-calc-branch \
      -m "Remove my-calc-branch."
Committed revision 392.

$ svn copy http://svn.example.com/repos/calc/trunk \
           http://svn.example.com/repos/calc/branches/new-branch
      -m "Create a new branch from trunk."
Committed revision 393.

$ cd my-calc-branch

$ svn switch http://svn.example.com/repos/calc/branches/new-branch
Updated to revision 393.
$ svn delete http://svn.exemple.com/depot/calc/branches/ma-branche-calc \
      -m "Supprime ma-branche-calc."
Révision 392 propagée.

$ svn copy http://svn.exemple.com/depot/calc/trunk \
           http://svn.exemple.com/depot/calc/branches/nouvelle-branche
      -m "Cree une nouvelle branche a partir du tronc."
Révision 393 propagée.

$ cd ma-branche-calc

$ svn switch http://svn.exemple.com/depot/calc/branches/nouvelle-branche
À la révision 393.

Paragraphe 26

The final command in the prior example—svn switch—is a way of updating an existing working copy to reflect a different repository directory. We'll discuss this more in the section called “Traversing Branches”.

La dernière commande de l'exemple précédent - svn switch - est une façon de mettre à jour une copie de travail existante afin qu'elle pointe vers un autre dossier du dépôt. Nous en parlerons plus en détail dans le paragraphe appelé "Parcourir les branches".