Désormais, Sally et vous travaillez sur des branches parallèles du projet : vous travaillez sur une branche privée et Sally travaille sur le tronc, la branche de développement principale.
Pour les projets qui ont un grand nombre de contributeurs, il est d'usage que la plupart des gens aient des copies de travail du tronc. Dès que quelqu'un doit faire des modifications de longue haleine, susceptibles de perturber le tronc, une procédure standard est qu'il crée une branche privée et qu'il y propage les modifications jusqu'à ce que tout le travail soit terminé.
Bref, la bonne nouvelle est que Sally et vous n'empiétez pas l'un sur l'autre. La mauvaise nouvelle est qu'il est très facile de dériver chacun de son côté. Rappelez-vous qu'un des problèmes lié à la stratégie d'« isolement » est que lorsque vous en aurez fini avec votre branche, il risque d'être quasi impossible de refusionner vos modifications dans le tronc sans avoir à faire face à un grand nombre de conflits.
À la place, Sally et vous pourriez continuer de partager vos changements au fur et à mesure de votre travail. C'est à vous de décider quelles modifications valent la peine d'être partagées ; Subversion vous offre la possibilité de « copier » sélectivement des modifications entre les branches. Et quand vous aurez tout fini dans votre branche, l'ensemble de vos modifications pourra être recopié en entier vers le tronc. Dans la terminologie Subversion, l'action générale de réplication des modifications d'une branche vers une autre s'appelle la fusion et elle s'effectue à l'aide de plusieurs exécutions de la commande svn merge.
Dans les exemples qui suivent, nous supposerons que le client et le serveur Subversion sont tous deux en version 1.5 (ou plus récente). Si l'un ou l'autre sont en version plus ancienne, les choses sont plus compliquées : le système ne gére pas les changements de façon automatique et vous devrez utiliser des méthodes manuelles pénibles pour obtenir des résultats similaires. Vous devrez en effet toujours utiliser la syntaxe détaillée de la fusion spécifiant l'éventail des révisions à répliquer (voir la section intitulée « Syntaxe de la fusion : pour tout vous dire » plus loin dans ce chapitre) et penser à garder trace de ce qui a déjà été fusionné et de ce qui ne l'a pas encore été. Pour cette raison, nous recommandons fortement de vous assurer que client et serveur sont au moins en version 1.5.
Avant que nous n'allions plus loin, nous devons vous avertir que les pages suivantes contiennent de nombreuses discussions portant sur les « modifications ». Beaucoup de gens ayant de l'expérience dans les systèmes de gestion de versions utilisent le terme « modifications » et le terme « ensemble de modifications » de façon interchangeable et nous allons donc clarifier ce que Subversion entend par ensemble de modifications.
Chacun semble avoir sa propre définition, variant légèrement, d'un ensemble de modifications, ou tout du moins a une attente différente quant à leur traitement par le système de gestion de versions. En ce qui nous concerne, disons qu'un ensemble de modifications n'est qu'un simple regroupement de modifications identifié par un nom unique. Les modifications peuvent inclure des changements textuels du contenu des fichiers, des modifications de l'arborescence ou des ajustements portant sur les méta-données. En langage plus courant, un ensemble de modifications n'est qu'un correctif avec un nom auquel vous pouvez vous référer.
Dans Subversion, un numéro de révision globale N désigne
une arborescence dans le dépôt : c'est ce à quoi le dépôt
ressemblait après la N-ième propagation. C'est aussi le nom d'un
ensemble de modifications implicite : si vous comparez
l'arborescence N avec l'arborescence N−1, vous pouvez en
déduire exactement le correctif qui a été propagé. Pour cette
raison, il est facile de se représenter une révision N non
seulement comme une arborescence, mais aussi comme un ensemble
de modifications. Si vous utilisez un système de gestion des
incidents pour gérer vos bogues, vous pouvez utiliser les
numéros de révision pour vous référer à des correctifs
particuliers permettant de résoudre des bogues — par
exemple, « cet incident a été corrigé par r9238 ».
Quelqu'un peut alors lancer
svn log -r 9238
pour obtenir le détail
des modifications qui ont corrigé le bogue et lancer
svn diff -c 9238
pour voir le
correctif lui-même. De plus (comme nous le verrons bientôt),
la commande svn merge de Subversion est
capable d'utiliser les numéros de révision. Vous pouvez
fusionner des listes de modifications spécifiques d'une
branche à une autre en les nommant dans les paramètres de
la fusion : donner comme argument
-c 9238
à svn merge
fusionne la liste de modifications r9238 avec
votre copie de travail.
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 propres
modifications. En fait, c'est là 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.
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 », c'est-à-dire que svn status ne liste aucune modification locale. Puis lancez juste :
$ pwd /home/user/ma-branche-calc $ svn merge http://svn.exemple.com/depot/calc/trunk --- Fusion de r345 à r356 dans '.': U bouton.c U entier.c
La syntaxe de base, svn merge
, indique à Subversion
qu'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 :URL
$ svn status M . M bouton.c M entier.c
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 indique 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).
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 annule 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 dans le dépôt :
$ 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.
À présent, votre branche privée est désormais « synchro » avec le tronc, vous pouvez donc vous détendre, sachant qu'en continuant votre travail en isolation, vous ne dériverez pas trop loin de ce que les autres font.
Supposons qu'une autre semaine s'est écoulée. Vous avez propagé 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 svn merge à nouveau !
$ svn merge http://svn.exemple.com/depot/calc/trunk --- Fusion de r357 à r380 dans '.': U bouton.c U Makefile A LISEZMOI
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 propager les modifications locales à votre branche.
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 du fruit de votre travail). La procédure est simple. Premièrement, synchronisez à nouveau votre branche avec le tronc, comme vous le faites depuis le début :
$ 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.
À présent, utilisez svn merge
pour répercuter les modifications de votre branche sur le tronc.
Vous avez alors besoin d'une copie de travail de
/trunk
qui soit à jour. Vous pouvez
vous la procurer soit en effectuant un
svn checkout, soit en reprenant une vieille
copie de travail du tronc, soit en utilisant
svn switch (voir
la section intitulée « Parcours des 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 facilement évitables liés à des
conflits et svn merge renverra probablement
une erreur en retour.
Une fois que vous avez une copie de travail propre du tronc, vous êtes prêt pour y fusionner votre branche :
$ 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, vérifier, ... $ 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.
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 des modifications ayant eu lieu dans une ligne de
développement (le tronc) et de les dupliquer vers une autre
(votre branche). C'est assez simple à réaliser 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.
Cependant, lors de la réintégration d'une branche dans
le tronc, la logique sous-jacente est assez
différente. 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 l'arborescence la plus récente du tronc
avec l'arborescence la plus récente de la branche :
la différence qui en résulte constitue exactement les
modifications de votre branche !).
Votre branche privée ayant réintégré le tronc, vous voudrez peut-être la supprimer du dépôt :
$ svn delete http://svn.exemple.com/depot/calc/branches/ma-branche-calc \ -m "Supprime ma-branche-calc." Révision 392 propagée.
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
la section intitulée « Résurrection des éléments effacés »).
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 :
$ 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 "Crée 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.
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 la section intitulée « Parcours des branches ».
Le mécanisme de base que Subversion utilise pour gérer
les ensembles de modifications, c'est-à-dire quelles
modifications ont été fusionnées dans quelles branches, est
l'enregistrement de données dans les propriétés. Plus
précisément, les informations de fusion sont conservées dans
la propriété svn:mergeinfo
qui est
associée aux fichiers et aux dossiers (si les propriétés de
Subversion ne vous sont pas familières, c'est le moment de
lire la section intitulée « Propriétés »).
Vous pouvez examiner cette propriété comme n'importe quelle autre :
$ cd ma-branche-calc $ svn propget svn:mergeinfo . /trunk:341-390
Il est déconseillé de changer
soi-même la valeur de cette propriété, à moins de savoir
vraiment ce que vous faites. Cette propriété est manipulée
automatiquement par Subversion à chaque fois que vous lancez
svn merge. Sa valeur indique quelles
modifications (pour un chemin donné) ont été recopiées dans
le dossier en question. Dans le cas présent, le chemin est
/trunk
et le dossier qui a reçu les
modifications spécifiées est
/branches/ma-branche-calc
.
Il existe également une sous-commande, svn mergeinfo, qui peut être utile pour voir non seulement quels ensembles de modifications un dossier a absorbés, mais aussi quels ensembles de modifications il est encore susceptible de recevoir. Ceci donne une sorte d'aperçu du prochain ensemble de modifications que svn merge recopiera vers votre branche.
$ cd ma-branche-calc # Quelles modifications ont déjà été fusionnées du tronc vers la branche ? $ svn mergeinfo http://svn.exemple.com/depot/calc/trunk r341 r342 r343 … r388 r389 r390 # Quelles modifications sont encore susceptibles d'être fusionnées du tronc vers la branche ? $ svn mergeinfo http://svn.exemple.com/depot/calc/trunk --show-revs eligible r391 r392 r393 r394 r395
La commande svn mergeinfo prend en
paramètres une URL « source » (d'où les
modifications viennent) et une URL « cible »
optionnelle (vers laquelle les modifications sont
fusionnées). Si aucune URL cible n'est fournie, elle suppose
que le dossier actuel est la cible. Dans l'exemple précédent,
puisque nous interrogeons la copie de travail de notre
branche, la commande suppose que ce qui nous intéresse est de
recevoir les modifications de l'URL spécifiée du tronc vers
/branches/ma-branche-calc
.
Une autre manière d'obtenir un aperçu plus précis d'une
opération de fusion est d'utiliser l'option
--dry-run
:
$ svn merge http://svn.exemple.com/depot/calc/trunk --dry-run U entier.c $ svn status # rien ne s'affiche, la copie de travail n'a pas changé.
L'option --dry-run
n'effectue en fait
pas de modification locale sur la copie de travail. Elle ne
fait qu'indiquer les codes d'état qui
seraient affichés par une vraie fusion.
Ceci permet d'obtenir un « aperçu général »
d'une fusion potentielle, pour les fois où
svn diff renvoie trop de détails.
Astuce | |
---|---|
Après avoir effectué une opération de fusion, mais avant
d'en avoir propagé les résultats, vous pouvez utiliser
|
Bien sûr, la meilleure façon d'avoir un aperçu d'une
opération de fusion est tout simplement de la réaliser !
Souvenez-vous que lancer svn merge n'est
pas une opération risquée en soi (à moins que vous ayez
effectué des modifications locales dans votre copie de
travail, mais nous avons déjà souligné que vous ne devriez
pas faire de fusion dans un tel environnement). Si les
résultats de la fusion ne vous plaisent pas, lancez juste
svn revert . -R
pour ôter les
modifications de votre copie de travail et réessayez la
commande avec des options différentes. La fusion n'est
définitive qu'une fois que vous en avez propagé
les résultats.
Astuce | |
---|---|
Bien qu'il soit parfaitement légitime de lancer svn merge et svn revert à plusieurs reprises pour préparer la fusion, vous risquez de rencontrer quelques obstacles (facilement surmontables). Par exemple, si l'opération de fusion ajoute un nouveau fichier (ou plus exactement programme son ajout), svn revert ne supprime pas le fichier ; il va juste déprogrammer l'ajout. Vous vous retrouvez avec un fichier non suivi en versions. Si ensuite vous tentez à nouveau de lancer la fusion, il risque d'y avoir des conflits dus au fichier non suivi en versions resté « en travers du chemin ». La Solution ? Après avoir effectué un retour en arrière à l'aide de svn revert, pensez à nettoyer la copie de travail et supprimer les fichiers et dossiers non suivis en versions. Il faut que le résultat de svn status soit le plus propre possible, et dans l'idéal vide. |
Un usage très répandu de svn merge
est le retour en arrière sur une modification qui a déjà
été propagée. Supposons que vous travaillez tranquillement
sur une copie de travail de /calc/trunk
et que vous découvrez tout à coup que la modification faite
il y a longtemps lors de la révision 303, qui affectait
entier.c
, est complètement incorrecte.
Elle n'aurait jamais du être propagée. Vous pouvez utiliser
svn merge pour revenir en arrière sur
cette modification dans votre copie de travail, puis propager
la modification locale au dépôt. Il suffit juste de spécifier
une différence inversée (en indiquant
soit --revision 303:302
, soit
--change -303
, les deux se valent).
$ svn merge -c -303 http://svn.exemple.com/depot/calc/trunk --- Fusion inverse de r303 dans 'entier.c': U entier.c $ svn status M . M entier.c $ svn diff … # vérifier que la modification est supprimée … $ svn commit -m "Retour en arrière sur la modification propagée en r303." Envoi entier.c Transmission des données . Révision 350 propagée.
Comme nous l'avons signalé précédemment, une façon de se
représenter une révision du dépôt est de la considérer comme
un ensemble de modifications spécifique. En utilisant l'option
-r
, vous pouvez demander à
svn merge d'appliquer un ensemble de
modifications, ou tout un groupe d'ensembles de modifications,
à votre copie de travail. Dans le cas présent, pour revenir
en arrière, nous demandons à svn merge
d'appliquer dans le sens inverse
l'ensemble de modifications nº303 à notre copie de travail.
Gardez à l'esprit que revenir en arrière sur une
modification de cette façon est similaire à toute autre
opération svn merge, vous devez donc
ensuite utiliser svn status et
svn diff pour vous assurer que votre
travail est dans l'état que vous voulez, puis utiliser
svn commit pour propager la version
finale au dépôt. Après la propagation, cet ensemble de
modifications particulier n'est plus présent dans la
révision HEAD
.
À nouveau vous vous dites : bon, ceci n'a pas vraiment annulé la propagation, n'est-ce pas ? La modification existe toujours en révision 303. Si quelqu'un extrait une version du projet calc entre les révisions 303 et 349, il verra toujours la mauvaise modification, non ?
Oui, c'est vrai. Quand nous parlons de
« supprimer » une modification, il s'agit de la
supprimer de la révision HEAD
. La
modification originale existe toujours dans l'historique du
dépôt. Dans la plupart des situations, c'est suffisant. La
plupart des gens ne s'intéressent d'ailleurs qu'à la révision
HEAD
du projet. Il y a des cas particuliers,
cependant, où l'on voudra vraiment détruire toute preuve de
la propagation (quelqu'un a peut-être accidentellement propagé
un document confidentiel). Cela ne s'avère pas si facile, parce
que Subversion a été conçu délibérément pour ne jamais perdre
d'information. Les révisions sont des arborescences immuables
qui sont empilées les unes par dessus les autres. Supprimer
une révision de l'historique créerait un effet domino,
engendrant le chaos dans les révisions ultérieures et
invalidant potentiellement toutes les copies de travail
[22].
Ce qu'il y a de formidable dans les systèmes de gestion
de versions, c'est que les informations ne sont jamais
perdues. Même si vous effacez un fichier ou un dossier, s'il
disparaît bien de la révision HEAD
, l'objet
existe toujours dans les révisions précédentes. Une des
questions les plus courantes que posent les nouveaux
utilisateurs est : « Comment est-ce que je récupère
mon ancien fichier ou dossier ? »
La première étape est de définir exactement quel élément vous essayez de ressusciter. Voici une métaphore utile : vous pouvez imaginer votre objet dans le dépôt comme existant dans une sorte de système à deux dimensions. La première coordonnée est une révision correspondant à une arborescence particulière ; la deuxième coordonnée est un chemin à l'intérieur de cette arborescence. Ainsi, toute version d'un fichier ou d'un dossier peut être définie par une paire de coordonnées qui lui est propre (souvenez-vous de la syntaxe des « piquets de révisions » : machin.c@224, mentionnée dans la section intitulée « Piquets de révisions et révisions opérationnelles »).
Tout d'abord, vous allez peut-être avoir besoin de
svn log pour identifier précisément les
coordonnées du fichier ou dossier que vous voulez ressusciter.
À cette fin, une bonne stratégie est de lancer
svn log --verbose
dans un dossier qui
contenait votre élément effacé. L'option
--verbose
(-v
) renvoie la
liste de tous les éléments modifiés par chaque révision ;
il vous suffit alors de trouver la révision dans laquelle
vous avez effacé le fichier ou le dossier en question.
Vous pouvez accomplir cette recherche soit visuellement
soit en utilisant un autre outil pour examiner
le résultat de la commande svn log
(via grep ou peut-être via une recherche
incrémentale dans un éditeur).
$ cd dossier-parent $ svn log -v … ------------------------------------------------------------------------ r808 | paul | 2003-12-26 14:29:40 -0600 (ven. 26 déc 2003) | 3 lignes Chemins modifiés : D /calc/trunk/reel.c M /calc/trunk/entier.c Ajouté les fonctions des transformées de fourier dans entier.c. Supprimé reel.c car code désormais dans double.c. …
Dans l'exemple ci-dessus, nous supposons que vous
recherchez un fichier effacé nommé reel.c
.
En examinant le journal du dossier parent, vous avez découvert
que ce fichier a été effacé en révision 808. La dernière
version du fichier à avoir existé était donc dans la révision
précédant celle-ci. Conclusion : vous voulez ressusciter
le chemin /calc/trunk/reel.c
tel qu'il
était en révision 807.
Voilà, c'était la partie difficile : la recherche. Maintenant que vous savez ce que vous voulez récupérer, deux options s'offrent à vous.
Une possibilité serait d'utiliser
svn merge pour appliquer la révision 808
« à l'envers » (nous avons déjà parlé de comment
revenir sur des modifications dans la section intitulée « Retour en arrière sur des modifications »). Ceci aurait
pour effet de ré-ajouter reel.c
en tant
que modification locale. Le fichier serait alors programmé
pour être ajouté et après la propagation le fichier existerait
à nouveau dans HEAD
.
Cependant, dans cet exemple particulier, ce n'est
probablement pas la meilleure stratégie. Appliquer la
révision 808 à l'envers programmerait non seulement l'ajout
de reel.c
, mais le message de propagation
indique qu'il reviendrait aussi sur certaines modifications
de entier.c
, ce que vous ne voulez pas.
Vous pourriez certainement fusionner à l'envers la révision
808 et ensuite revenir sur les modifications locales faites
dans entier.c
, mais cette technique
fonctionne mal à plus grande échelle. Que dire, si 90 fichiers
avaient été modifiés en révision 808 ?
Une seconde stratégie plus ciblée est de ne pas utiliser svn merge du tout, mais plutôt d'utiliser la commande svn copy. Copiez juste la révision et le chemin exacts (vos deux « coordonnées ») du dépôt vers votre copie de travail :
$ svn copy http://svn.exemple.com/depot/calc/trunk/reel.c@807 ./reel.c $ svn status A + reel.c $ svn commit -m "Ressuscité reel.c à partir de la révision 807, /calc/trunk/reel.c." Ajout reel.c Transmission des données . Révision 1390 propagée.
Le symbole plus dans le résultat de la commande
svn status indique que l'élément n'est
pas simplement programmé pour ajout, mais programmé pour ajout
« avec son historique ». Subversion se souviendra
d'où il a été copié. Dans le futur, lancer
svn log sur ce fichier parcourra tout son
historique en passant par la résurrection du fichier ainsi que
tout ce qui précédait la révision 807. En d'autres termes,
ce nouveau reel.c
n'est pas vraiment
nouveau ; c'est un descendant direct du fichier original
qui avait été effacé. En général c'est une bonne chose, dont
l'utilité est avérée. Si cependant vous vouliez récupérer
le fichier sans conserver de lien
historique avec l'ancien fichier, la technique suivante
fonctionnerait tout aussi bien :
$ svn cat http://svn.exemple.com/depot/calc/trunk/reel.c@807 > ./reel.c $ svn add reel.c A reel.c $ svn commit -m "Recréé reel.c à partir de la révision 807." Ajout reel.c Transmission des données . Révision 1390 propagée.
Bien que notre exemple ne porte que sur la résurrection d'un fichier, remarquez que ces mêmes techniques fonctionnent tout aussi bien pour ressusciter des dossiers effacés. Remarquez aussi que cette résurrection ne doit pas forcément avoir lieu dans votre copie de travail ; elle peut avoir lieu entièrement dans le dépôt :
$ svn copy http://svn.exemple.com/depot/calc/trunk/reel.c@807 \ http://svn.exemple.com/depot/calc/trunk/ \ -m "Ressuscite reel.c dans la révision 807." Révision 1390 propagée. $ svn update A reel.c À la révision 1390.
[22] Le projet Subversion prévoit néanmoins d'implémenter, un jour, une commande qui accomplirait la tâche de supprimer des informations de façon permanente. En attendant, en guise de palliatif, voir la section intitulée « svndumpfilter ».