Utilisation de CVS

Alain LESNÉ et Olivier BERGER, pour IDEALX

$Date: 2000/12/28 10:53:33 $
Conçu pour faciliter le travail de développement en équipe, cvs conserve les révisions successives et facilite la collaboration de multiples intervenants sur un même projet. Qu'il travaille localement (sur la même machine) ou à distance (en réseau), chacun n'accède jamais qu'à une copie des fichiers, tandis que les originaux demeurent sur le « référentiel » et ne sont modifiés qu'à travers les mécanismes sécurisés et « journalisés ») de cvs.

1. Diffusion du présent document

2. Première utilisation

3. Intérêt de cvs

4. cvs approfondi

5. Interfaces

6. Références


1. Diffusion du présent document

Ce document appartient à IDEALX. Il est librement diffusable dans les termes de la Licence de Documentation Libre GNU ( GNU Free Documentation License).

2. Première utilisation

Afin de faciliter l'exposé de cette première approche, on supposera cvs déjà installé et configuré sur le serveur. Côté client, cvs ne requiert aucune intervention particulière, hormis la mise en place de variables système. La présence de l'exécutable cvs suffit, mais le paquetage est de toutes façons fourni avec les distributions de Linux courantes, ou les BSD libres.

Du point de vue de l'utilisateur, quelles sont les commandes essentielles à retenir pour commencer à l'utiliser ?

2.1 Création d'une copie de travail privée d'un projet

Tout d'abord, pour créer « l'image » locale d'un projet (pour notre exemple, ce sera : /home/toto/cvs/web, alors que les sources se trouvent à /opt/cvs/web sur le serveur), il faut commencer par créer localement le répertoire dans lequel on souhaite faire un miroir du référentiel (Cf. référentiel) source (repository, également appelé dépôt). Puis en faire le répertoire par défaut, car cvs travaille toujours avec des chemins relatifs au répertoire courant.

$ mkdir ~/cvs; cd ~/cvs

Il faut maintenant renseigner quelques variables d'environnement, qui éviteront de passer de fastidieuses lignes de commande à cvs.

        $ export CVSROOT=toto@cvs.mon-organisation.com:/opt/cvs
        $ export CVS_RSH=ssh
        $ export CVSEDITOR=vim

La syntaxe de la commande export CVSROOT=... suppose qu'un shell compatible Bourne est utilisé (bash, zsh...). Sous csh, ou tcsh, il faut remplacer la commande par setenv CVSROOT .... Cette variable mémoire indiquera à cvs :

La commande export CVS_RSH=ssh est ici nécessaire car cvs invoque rsh par défaut. Le passage de ce paramètre permet d'utiliser ssh (plus satisfaisant du point de vue de la sécurité) de manière transparente.

Remarque: nous décrivons ici une méthode d'accès à CVS par l'intermédiaire de SSH, qui n'est que l'un des protocoles qui peuvent être utilisés avec CVS. Une méthode plus courante, mais moins sécurisée, utilisée fréquemment sur les projets Open-Source est la méthode :pserver:. Ici aussi, il faudra adapter l'utilisation ou non de la variable d'environnement CVS_RSH au contexte de votre projet.

Enfin, la présence de la commande export CVSEDITOR=vim est facultative si le système possède déjà une variable système EDITOR. Naturellement, tout autre éditeur fera l'affaire, pourvu qu'il n'ajoute pas de codes intempestifs (la plupart des « traitements de texte » ne conviennent pas. Cependant, et c'est notamment le cas pour les mises à jour, où cvs peut faire appel à un éditeur pour la saisie de commentaires, l'absence de l'une ou l'autre variable provoque une erreur d'exécution.

Si l'utilisateur travaille sur la machine où se trouve le dépôt, cela ne fait aucune différence, hormis la variable CVSROOT, qui n'indique alors que le chemin du référentiel :

        $ export CVSROOT=/opt/cvs

Maintenant que l'environnement minimal est mis en place, nous pouvons récupérer le projet « web » convoité, tel qu'il se trouve dans son dernier état. L'historique des modifications intervenues dans le projet avant cette copie est tout simplement ignoré, mais demeure consultable en invoquant cvs avec les options appropriées.

        $ cvs checkout web

Cette commande invite cvs à comparer les modifications intervenues sur les fichiers et répertoires du projet (dans la terminologie de cvs : un module (Cf. module)) et à les répercuter localement. Comme il s'agit ici de la première mise à jour, c'est tout simplement l'ensemble du module qui est dupliqué localement.

Par la suite, on préfèrera sans doute un affichage moins « verbeux », ne laissant passer que les informations essentielles (avec l'option -q pour quiet, tranquillité) :

        $ cvs -q checkout <nom_du_module>

Bien sûr, ssh demande le mot de passe de l'utilisateur avant de se connecter au site distant, de la même manière que le ferait rsh (sauf si un fichier ~/.rhosts, sur le serveur, autorisait la connexion sans mot de passe --- ce qui ne serait vraiment pas une bonne idée).

Voilà. Un répertoire web vient d'être créé dans l'arborescence locale (~/cvs/web). On remarquera que le nom de ce répertoire local est identique au nom du répertoire sur le référentiel. Il contient, outre l'ensemble des fichiers sources du projet, un répertoire nommé CVS qu'il ne faut pas éditer, car il contient des données gérées par cvs (ce qui n'interdit pas aux curieux d'aller y jeter un oeil...).

Comme il sera toujours nécessaire de passer les variables en paramètre, autant créer un script destiné à automatiser la tâche. Éditer, par exemple, un fichier ~/bin/cvsaccess :

        #! /bin/sh
        cd ~toto/cvs | exit 4
        export CVSROOT=toto@cvs.mon-organisation.com:/opt/cvs
        export CVS_RSH=ssh
        cvs checkout web

Ne pas oublier de lui donner les droits d'exécution :

        $ chmod u+x ~/bin/cvsaccess

Il suffira ensuite de taper la commande :

        $ ~/bin/cvsaccess

pour que la mise à jour soit automatiquement effectuée. Il convient toutefois de prendre garde à ce que le script charge un sous-shell, et que l'environnement du shell de travail de l'utilisateur n'est de ce fait pas modifié. Toute commande cvs entrée directement au clavier risque alors de ne pas produire le résultat escompté...

On facilitera la mise en place de cet environnement en plaçant toutes les commandes nécessaires dans un fichier que l'on « sourcera » :

        $ source ~/bin/cvsaccess
        $ . ~/bin/cvsaccess             # équivalent et plus concis 

Mais on pourra encore placer ces variables dans ~/.bashrc, par exemple, si l'utilisateur courant n'accède pas couramment à d'autres dépôts cvs.

2.2 Répercuter des modifications locales sur le référentiel

Lorsqu'un fichier a été modifié localement et que l'on se contente de lancer la commande :

        $ cvs checkout <nom_du_projet>

cvs le rappelle par l'affichage d'un M précédant le nom du fichier, mais ne met pas à jour cette modification sur le dépôt.

Pour ce faire, il faut le demander explicitement à cvs :

        $ cvs commit <fichier_modifié>

Ou, le cas échéant :

        $ cvs commit

pour mettre à jour sur le référentiel l'ensemble des fichiers connus de cvs, et qui ont été modifiés dans l'arborescence locale (plus généralement, le fait de ne pas spécifier d'attribut après une instruction cvs implique que celle-ci sera exécutée récursivement. cvs liste alors les fichiers dont les modifications viennent d'être prises en compte. Il est possible de ne traiter que les fichiers du répertoire courant, sans récursion, en ajoutant l'option -l).

cvs propose alors la saisie d'un message associé à cette mise-à-jour. Il invoque l'éditeur spécifié dans les variables CVSEDITOR ou EDITOR pour l'ensemble des fichiers modifiés, ce qui permet d'indiquer un commentaire approprié (nom de l'intervenant, objet...). Mais il est souvent plus commode de passer le commentaire en ligne de commande (option -m, pour message) afin d'éviter que l'éditeur ne soit systématiquement invoqué :

        $ cvs commit -m 'toto: optimisation de l'algo' tri.c

Évidemment, si le fichier a été édité par un autre utilisateur et que ce dernier a validé ses modifications sur le référentiel tandis qu'on l'éditait localement, il y a problème. cvs rapporte alors le conflit. La plupart du temps, il suffira d'un :

        $ cvs update tri.c

pour que cvs fusionne automagiquement les modifications dans le fichier local.

Sauf si elles sont trop imbriquées ou conflictuelles, auquel cas cvs invitera l'utilisateur à intervenir pour régler manuellement les problèmes. Après édition du fichier (qui contient, très lisiblement balisées, les deux versions des sections qui n'ont pu être fusionnées automatiquement) il suffira de retaper la commande :

        $ cvs commit tri.c

pour que les modifications soient finalement validées sur le référentiel.

Afin d'éviter ce genre de désagrément, mieux vaut effectuer de fréquentes mises à jour. Les auteurs insistent d'ailleurs sur le fait que cvs ne saurait se substituer à la communication entre les développeurs...

2.3 Ajouter ou supprimer un fichier

Comme on l'a déjà remarqué, si un fichier est édité localement, un simple checkout ne répercutera pas les modifications sur le serveur. Il en va de même pour une création ou une suppression de fichier. Ce comportement spontané s'avère d'ailleurs bien commode puisqu'il dispense, par exemple, de devoir dupliquer des fichiers ou une arborescence dans une autre arborescence (hors CVS) avant d'entreprendre une compilation. Sauf indication explicite, les binaires (ou tout fichier généré après coup, donc n'ayant pas fait l'objet d'un cvs add) ne seront pas transférés sur le dépôt du serveur. cvs se contentera simplement d'indiquer sur la console qu'il a remarqué la présence de fichiers dont il ne sait pas quoi faire, en faisant précéder leur nom d'un point d'interrogation.

Ainsi, lorsque l'on souhaite inclure un nouvel élément dans un projet, il faut explicitement l'indiquer par :

        cvs add -m "message" <nom_de_fichier>

cvs informe alors que la prise en compte du nouveau fichier ne sera effective qu'après le prochain commit :

        $ cvs commit <nom_de_fichier>

De la même manière, la suppression d'un fichier ne sera effective qu'après le commit :

        $ cvs remove <nom_de_fichier>
        $ cvs commit <nom_de_fichier>

Enfin, s'agissant de la prise en compte de nouveaux éléments dans un projet, il ne faut pas perdre de vue que, destiné à conserver l'historique des versions, cvs s'attend par défaut à enregistrer des fichiers texte. Pour des raisons évidentes, les binaires ou archives (tar...) ne sauraient être traités de la même façon, et c'est pourquoi il faut alors indiquer leur nature « non historicisable » à cvs :

        $ cvs add -kb <NomFichier>

Ainsi, on évitera le plus souvent de placer sous le contrôle de CVS un fichier :

Utiliser des noms de répertoires au singulier, sans caractères spéciaux (ou accents, espaces ...), et sans majuscules sauf si l'une de ces caractéristiques est vraiment discriminante. La circulation s'en trouve facilitée. Exemple : test et non tests ou Test.

Ces quelques commandes de base sont d'ores et déjà suffisantes pour commencer à travailler avec cvs, dont la simplicité n'est pas le moindre intérêt.

3. Intérêt de cvs

3.1 Qu'est-ce que cvs ?

Je ne peux pas imaginer programmer sans... ce serait comme faire du parachutisme sans parachute ! Brian Fitzpatrick.

Placé sous licence GPL, cvs se présente comme a version control system, qui permet d'enregistrer l'historique de fichiers sources. Mais le « c » peut aussi bien s'entendre comme concurrent. De fait, cvs se révèle particulièrement efficace pour la gestion de développements simultanés. Pour la petite histoire, c'est d'ailleurs la mention Concurrent Versions System qui figure en en-tête des pages paires de la documentation officielle. Sophistiqué, ce système constitué d'un ensemble de commandes est généralement considéré comme un « état de l'art » dans son domaine. Une référence.

Outre le fait que les originaux sur le référentiel ne sont jamais affectés directement par les utilisateurs --- qui n'éditent jamais que des copies dont cvs se charge de faire la mise à jour après coup --- l'idée fondamentale est de ne conserver (dans un fichier unique) que l'historique des modifications qui ont affecté un fichier, et non ses multiples « incarnations » successives. D'où un important gain de place, pour parvenir au même résultat : être en mesure de retrouver une version particulière et localiser la première manifestation d'un bogue, longtemps après sa première apparition dans une lignée de révisions.

Une autre caractéristique de cvs repose sur le fait de permettre à chaque développeur de travailler dans son propre répertoire. Que ce dernier se trouve sur la même machine que le référentiel ou en réseau, cvs se charge de fusionner le travail « réparti » dans un référentiel commun, auquel chacun peut à tout moment se reporter.

3.2 Les limites de cvs

En termes d'espace disque, on constate en général le triplement de volume des sources « utiles » d'un projet. Mais ce n'est qu'une indication empirique. Il va se soi que si des remaniements importants interviennent régulièrement dans les sources, l'occupation disque peut croître sensiblement. Moins, dans tous les cas, que s'il fallait conserver l'intégralité des versions successives --- et c'est là l'essentiel.

Quant à l'inévitable mise au point sur ce que n'est pas cvs et qu'il ne faut pas attendre, les auteurs insistent sur sa nature essentiellement technique, qui certes envisage et même gère les conflits de versions concurrentes, mais ne peut cependant pas se substituer à l'indispensable communication entre les développeurs. En particulier, cvs ne peut en rien aider à la résolution de conflits relatifs à des logiques de programmation.

Enfin, cvs ne gère de manière convaincante que le matériau textuel. Les binaires, comme les fichiers graphiques, peuvent être pris en compte, mais il faut renoncer pour eux à certaines possibilités de traitement offertes par cvs.

3.3 Quand « mettre à jour » (commit) ?

Les mises à jour par commit devraient être d'autant plus fréquentes qu'un projet comporte peu de modules mais compte beaucoup de participants.

Il ne faut pas perdre de vue que cvs n'archive qu'un historique par fichier et non pas les fichiers eux-mêmes. Ainsi, en termes d'occupation disque, la différence entre de nombreuses mises à jour par commit (modifications mineures successives des fichiers) et une politique de mises à jour plus espacées (modifications plus substantielles) n'a en pratique que peu d'impact.

Il est parfois recommandé de ne « commiter » que du code ayant été compilé --- voire testé --- avec succès. Le bon sens conduit en effet à considérer qu'il n'est peut n'être pas souhaitable que des éléments incomplets soient envoyés sur le dépôt si d'autres personnes s'attendent à ne trouver que du code fonctionnel. À l'inverse, il ne saurait être question de garantir que tout est en ordre avant de lancer le commit... Bref, c'est là évidemment une décision « politique », qui ne relève pas directement de l'usage de cvs.

Mais il faut noter que la technique des « branches » (Cf. branches) permet de conserver parallèlement une version stable « de référence » accessible au public, et une version de développement (par définition instable) sur le même référentiel. Dans le même esprit, l'usage des « labels » (Cf. labels) se révèle très pratique pour identifier, par exemple, la dernière révision compilable.

3.4 Comment se préserver des collisions ?

Malgré la modeste contrainte qu'imposent les commit fréquents, une politique de mises à jour rapprochées peut faire gagner beaucoup de temps en évitant la survenue de collisions. Si cvs sait en effet identifier --- voire régler tout seul --- les conflits de révision, cela ne dispense guère les utilisateurs d'agir avec prudence et bon sens.

En règle générale, il est souhaitable de vérifier qu'on dispose bien d'une révision « à jour » avant de se lancer dans une intervention. Si la commande status répond Up to date, alors tout va bien. Mais si cvs indique qu'une mise à jour est nécessaire (Needs Checkout), inutile de tergiverser...

De toutes façons, s'il n'y a pas eu de modifications locales depuis le dernier checkout, cette commande est sans doute à lancer avant toute chose. Enfin, si un autre utilisateur est par ailleurs intervenu sur le fichier tandis qu'on l'éditait, c'est le message Needs Update qui en informe. Cela signifie qu'un conflit existe entre la révision locale et celle du référentiel mais, encore une fois, cvs se tire généralement tout seul de cette situation.

Les auteurs de cvs ont également prévu la possibilité de « verrouiller » un fichier pour en empêcher l'édition simultanée. Ce mécanisme n'est toutefois qu'optionnel. D'une part parce qu'il impose de constantes synchronisations entre les copies locales des utilisateurs et le référentiel, mais aussi parce que une bonne communication entre les intervenants s'avère de toute façons préférable, a fortiori si plusieurs développeurs interviennent sur une section de code implémentant un algorithme particulièrement délicat.

On veillera par ailleurs à ne pas intervenir sur la mise en forme des lignes ou paragraphes déjà édités lorsque ce n'est pas indispensable, surtout si elle n'en modifie pas le sens où la compréhension. Ceci afin de ne pas rendre inutilement fastidieuse la lecture des listings produits par diff et, accessoirement, ménager l'espace disque sur le serveur.

4. cvs approfondi

4.1 Suivi des révisions

Comme on l'a vu, cvs offre la possibilité de suivre l'évolution d'un projet et, si nécessaire, de rebrousser chemin. Il est, surtout, très utile de pouvoir remonter à la « source » d'un bogue, si celui-ci n'est découvert qu'après l'édition de plusieurs nouvelles révisions.

Tout d'abord, pour lister un historique sommaire des révisions comprenant les dates et numéros respectifs, ainsi que les commentaires spécifiés lors du commit (option -m ou saisis depuis l'éditeur appelé par cvs), utiliser la commande :

        $ cvs log <nom_de_fichier>

Comme souvent, si un nom du fichier n'est pas précisé c'est l'ensemble des éléments du répertoire courant qui sera pris comme paramètre. Mais, même en indiquant un nom de fichier, la réponse de cvs peut être trop loquace si l'élément a connu de nombreuses modifications. Ainsi, il sera la plupart du temps judicieux de passer une indication temporelle en paramètre :

        $ cvs log -d ">2000-4-1" <nom_de_fichier>

affichera le résumé des révisions postérieures au 1er avril 2000. La syntaxe autorise de multiples variantes. Attention toutefois à la notation « longue », car cvs ne semble pas comprendre le français. Voici quelques exemples « testés » :

        $ cvs log -d "15 days ago" cvs.sgml
        $ cvs log -d "last month" cvs.sgml
        $ cvs log -d yesterday cvs.sgml
        $ cvs log -d  "20 mar 2000<30 mar 2000" cvs.sgml

La syntaxe paraît suffisamment explicite par elle-même. Sans doute n'est-il pas nécessaire de préciser que le dernier exemple liste les révisions intervenues entre deux périodes. Mais même si tout cela s'avère relativement intuitif, il faut parfois « ajuster » pour obtenir le résultat souhaité. En dernier recours, more ou less peuvent rendre des services équivalents.

Une autre option particulièrement intéressante permet de limiter la sortie aux interventions d'un utilisateur particulier :

        $ cvs log -wnat <nom_de_fichier>

liste uniquement les dates, numéros de révision et commentaires réalisés par l'utilisateur « nat ».

Mais ces commandes ne donnent pas encore accès au détail des modifications, qui ont bien été enregistrées par cvs. On verra qu'il était néanmoins préférable de visualiser au préalable un historique des versions. Car si :

        $ cvs diff <nom_de_fichier>

liste les différences entre la version locale d'un fichier et celle qui se trouve actuellement sur le référentiel, il apparaît aussi utile de pouvoir comparer le fichier actuel avec une révision antérieure particulière :

        $ cvs diff -r 1.5 <nom_de_fichier>
        $ cvs diff -r 1.5 -r 1.6 <nom_de_fichier>

voire deux révisions intermédiaires, comme dans le second exemple. La sortie présentée par cvs ressemble à celle que produit l'utilitaire GNU diff, et permet de visualiser ajouts, retraits et modifications. Il est d'ailleurs possible de stocker cette sortie sur disque au moyen d'un tube redirecteur, afin de traiter ensuite le fichier original (pour annulation de modifications, par exemple) avec l'utilitaire GNU diff. À noter que l'option -u, couramment utilisée avec l'utilitaire diff, est disponible avec la commande de cvs et produit le même type d'affichage.

Une autre commande que l'on pourrait apparenter à diff affiche, ligne à ligne, le numéro de dernière révision, l'identifiant de son créateur/réviseur, et la date de la dernière modification, le tout en marge (à gauche) de l'information.

        $ cvs annotate <nom_de_fichier>

Contrairement à diff annotate n'opère pas à proprement parler de comparaison entre deux versions, mais produit une vision chronologique qui peut être pertinente, tant pour estimer la part de nouveauté/persistance d'un fichier que pour « rendre à César » telle ou telle partie....

Enfin la commande status permet de visualiser l'état d'un fichier ou d'une collection de fichiers dans un même répertoire ; par exemple pour confirmer qu'une version locale est à jour par rapport à celle qui se trouve sur le référentiel. Les numéros de révision « locaux » et « distants » sont également indiqués.

        $ cvs status <nom_de_fichier>

Cette commande est utile pour vérifier si un autre utilisateur n'a pas modifié et validé sur le dépôt un fichier qu'on est en train d'éditer localement. Auquel cas (Needs Merge), il faut s'attendre a devoir peut être gérer les conflits de version manuellement lors du prochain commit... Le plus tôt sera le mieux, puisque, bien entendu, les chances d'une résolution « automatique » des conflits s'amenuisent à mesure que les divergences entre les deux copies s'accentuent.

4.2 Gestion et « publication » des révisions

Lorsque les révisions commencent à s'accumuler --- et c'est particulièrement le cas si les intervenants sont nombreux, puisqu'il est judicieux de multiplier les commit pour limiter les risques de collisions (Cf. collisions) --- il peut s'avérer intéressant de « marquer » certaines versions afin de les repérer plus commodément. Cette opération consiste à attribuer un label symbolique (Cf. label symbolique) (symbolic tag), qui pourra être utilisé par la suite comme paramètre en lieu et place du numéro de révision.

Cela peut être utile, par exemple, pour identifier une version qui a été diffusée à plus large échelle. Ou simplement parce qu'un mot s'avère plus commode à retenir qu'un nombre décimal. Mais, surtout, cela permet d'identifier sous un label unique une collection de fichiers (ou plutôt : une collection de révisions (Cf. révision) particulières d'un certain nombre de fichiers). Certaines commandes (comme export exigent d'ailleurs le passage d'un label (tag) en paramètre, et ne fonctionnent pas avec un simple numéro de révision :

        $ cd /usr/src
        $ cvs export -r STABLE-1_0 BeauProjet

Dans cet exemple, la commande export recréera dans /usr/src/BeauProjet l'ensemble de l'arborescence constitutive d'un module (Cf. module), donc d'un projet (Cf. projet), expurgée des fichiers propres à cvs, sous une forme par conséquent mieux adaptée à une diffusion publique (ou distribution (Cf. distribution)). Elle suppose qu'un label de version (Cf. label de version) a été préalablement affecté au module au moyen de la commande :

        $ cvs rtag 1_0-STABLE BeauProjet

Il est possible par ailleurs de cumuler plusieurs labels sur un même fichier, voire une même révision. De sorte que des « familles » regroupant des éléments portant le même identifiant symbolique peuvent être constituées indépendamment de leur numéro de révision. Signalons au passage que l'usage du point n'est pas autorisé dans les noms de labels, probablement afin d'éviter toute confusion avec les numéros de version. La commande :

        $ cvs tag Test <nom_de_fichier>

affecte le label « Test » au fichier indiqué en paramètre. Ainsi :

        $ cvs diff -r Test <nom_de_fichier>

listera les modifications intervenues sur l'élément entre la version courante (telle qu'elle apparaît sur le répertoire local de l'utilisateur) et la version identifiée « Test » sur le référentiel. Suivant le même principe, on pourrait envisager de « rebrousser chemin » vers une version donnée d'un fichier, et « oublier » ce qui a été réalisé depuis :

        $ cvs update -r Fonctionnel <nom_de_ficher>

pour autant, naturellement, qu'une révision ait été préalablement marquée « Fonctionnel ». Ce peut être un moyen commode d'expérimenter des solutions sur des révisions successives (mobilisant plusieurs auteurs) tout en conservant une possibilité de « repli » aisée.

La méthode convient aussi pour attribuer un marqueur à une collection de fichiers, tels qu'ils se trouve à un moment donné. Il suffit de ne pas indiquer de nom de fichier pour que l'ensemble de l'arborescence soit affectée :

        $ cd <répertoire_du_projet>
        $ cvs tag Compilation-Ok

De sorte que, si le besoin s'en fait sentir  :

        $ cd <répertoire_du_projet>
        $ cvs update -r Compilation-Ok

permettra de revenir à un état donné du projet, c'est à dire recouvrer l'ensemble des fichiers qui le composent dans la forme où ils se trouvaient lorsque l'identifiant symbolique (symbolic tag) a été apposé. Attention : la commande tag affecte une arborescence et non un module, contrairement à rtag. Paradoxalement, elle est plus puissante. Si bien que les fichiers de plusieurs modules peuvent être affectés si la commande est exécutée depuis un répertoire parent.

De même, si l'on souhaite créer le miroir local d'un projet à partir d'une version particulière (par exemple parce qu'elle est réputée stable) et non dans sa toute dernière révision, il suffira d'indiquer le label « qui va bien » lors du premier checkout  :

        $ cvs checkout -r STABLE-1_0 <nom_du_projet>

Les marqueurs symboliques (symbolic tags) ne doivent pas contenir d'espaces (même entre guillemets). Par ailleurs, s'ils sont parfois utilisés pour numéroter les distributions « publiques » des projets, il ne faut pas confondre avec la séquence de révision (numérique) qui est automatiquement incrémentée sur le référentiel après chaque commit effectif.

Ces numéros de révision automatiques ne sont rien d'autre qu'un compteur décimal. La plupart du temps, on n'y prête attention que comme indication distinctive et chronologique. Par défaut, cvs considère que la version initiale porte le numéro 1.1. Il est toutefois possible de « forcer » un numéro de révision particulier, pourvu qu'il soit supérieur au numéro courant :

        $ cvs commit -r 2.0 <nom_de_ficher>

voire :

        $ cd <répertoire_du_projet>
        $ cvs commit -r 2.0

pour affecter un numéro de version commun à l'ensemble des fichiers d'un projet, dans l'état où ils se trouvent sur le disque ou le répertoire courant de l'utilisateur. Les révisions prendront par la suite automatiquement les numéros 2.1, 2.2...

Il ne s'agit toutefois pas de la meilleure méthode pour officialiser le passage d'une version à une autre. L'usage des labels collants (sticky tags), surtout à travers la technique des « branches » (Cf. branches) peut s'avérer plus efficace. Surtout, il prévient toute confusion entre « révision » (Cf. révision) (en anglais revision, au sens d'une simple modification d'un fichier) et une « version » (en anglais release, au sens de « distribution »).

De fait, il serait peu élégant qu'à la révision 2.34 corresponde une version publique officiellement baptisée « 2.34 »... qui succéderait immédiatement la 2.0. Or c'est bien ce qui se produirait si trente quatre interventions sur un fichier sont nécessaires avant de pouvoir le considérer à nouveau comme suffisamment satisfaisant pour être « publié ».

4.3 Utilisation des modules CVS

La plupart des commandes cvs prennent en argument un nom de module ou un nom de fichier (contenant un chemin d'accès relatif au sommet du référentiel). Lorsque le référentiel possède une structure complexe contenant plusieurs niveaux d'arborescence, il est préférable de définir des modules.

L'administrateur du référentiel CVS peut donc avoir défini des modules permettant d'accéder directement aux fichiers d'un projet sans avoir besoin d'utiliser des noms de répertoires complets par rapport au sommet du référentiel.

Pour obtenir la liste des noms de modules existants, utiliser la commande suivante :

        $ cvs checkout -c

Cette commande affiche la liste des modules, avec les chemins des répertoires correspondants dans le référentiel.

L'administrateur CVS peut également avoir défini une propriété particulière (dans un format de son choix) pour chaque module, par exemple le nom du mainteneur de chaque module.

Pour afficher la liste des modules triés selon la valeur de cette propriété particulière, on peut utiliser une variante de la commande "checkout -c" :

        $ cvs checkout -s 

A partir de la liste des modules renvoyée par ces deux commandes, l'utilisateur peut alors choisir le nom du module dont il veut récupérer une copie avec la commande checkout.

4.4 Branches de développement

Supposons que quelques temps après qu'une version d'un logiciel déclarée « 1.0 » ait été rendue publique, un bogue soit découvert. Le développement s'est poursuivi depuis, mais la sortie de la distribution « 2.0 » officielle --- qui apportera de nombreuses innovations --- n'est pas encore à l'ordre du jour. Pourtant, la correction du défaut découvert dans la version 1.0 s'avère bel et bien nécessaire.

Évidente, la solution consiste à publier une distribution 1.1 corrigeant le défaut constaté sur la 1.0. La diffusion de la 2.0 pourra ainsi encore attendre, même si le problème est corrigé (et peut être n'est-elle pas concernée par le fameux bogue, si l'élément affecté a été complètement réécrit ou remplacé depuis).

On constate qu'une « branche » s'est alors créée dans le cours du développement de l'application. L'essentiel du travail se poursuit normalement (en vue de la publication d'une version baptisée « 2.0 » dont certains fichiers peuvent parfaitement porter un numéro de révision bien supérieur sur le référentiel cvs) mais des interventions sont toujours nécessaires sur le « vieux » code.

Du point de vue de cvs, il s'agit de faire en sorte que les corrections faites sur une branche « morte » (ou plutôt : « obsolète ») ne se répercutent pas indûment sur la partie en cours de développement. Si la version qu'il faut corriger a été convenablement « labellisée » lors de sa publication, alors la collection de fichiers peut être facilement identifiée, avec, le cas échéant, le bon numéro de révision pour chaque fichier. C'est à partir de ce label que l'on va effectivement créer la « branche », qui n'existait auparavant qu'à l'état virtuel :

        $ cvs rtag -b -r 1_0-STABLE 1_0-CORR MonProjet

Dans cet exemple, le label (symbolic tag) est 1_0-STABLE et la branche créée est 1_0-CORR. Ainsi, toute rectification sur un fichier portant le label 1_0-STABLE (sic, mais comme « tout bien portant est un malade qui s'ignore », un code réputé stable n'est jamais qu'un code dont les défauts ne sont pas encore apparus --- et le mérite de cvs consiste justement à en faciliter la maintenance) prendra à son tour le label 1_0-CORR qui sera transmis aux éventuelles générations postérieures. C'est pourquoi le label est dit « collant » (sticky tag).

À cette occasion, les révisions de fichiers appartenant à une branche « fille » acquièrent deux décimales supplémentaires à leur numéro de révision. Par convention, le premier chiffre attribué après celui de la branche « mère » est pair et commence à 2. En pratique cela ne concerne pas l'utilisateur, mais la connaissance de ce mécanisme devrait aider à comprendre le principe des « branches » cvs en général.

Un peu d'ASCII art ?

                 1.4           1.2.2.2.2.2
                  |   1.2.2.4      |
                 1.3     |         |
                  |   1.2.2.3  1.2.2.2.2.1  
                  |      |    /
                  |      |   /
                  |   1.2.2.2
                  |      |
        1.2.4.1   |   1.2.2.1
               \  |  /
                \ | /
                 1.2
                  |
                 1.1

Dans l'exemple ci-avant une révision (Cf. révision) « 1.2.2.1 » est créée à partir de la branche (Cf. branche) issue de la révision « 1.2 ». Puis une branche « concurrente » (sans descendance) commençant avec avec la révision « 1.2.4.1 ». Ensuite, la révision « 1.2.2.2 » donne naissance à la branche qui commence avec « 1.2.2.2.2.1 »...

Toujours pas clair ? Et puis d'abord, quel rapport avec les distributions publiques ? Un autre exemple totalement fictif, cette fois sans numérotation :

                                 OpenBSD
                                / 
                               /
                              /
        FreeBSD           NetBSD
               \          /
                \        /
                 \      /
                  BSD4.2

Selon ce schéma, « tordu » pour l'exposition des branches cvs, BSD4.2 donnerait naissance à FreeBSD et NetBSD, tandis que ce dernier serait à son tour à l'origine d'OpenBSD.

Hérésie historique mise à part, les labels collants (sticky tags) de l'ensemble des éléments sources qui composent les systèmes BSD pourraient se présenter de cette façon. Supposons maintenant qu'il soit amusant de supprimer toute référence au label « NetBSD » dans la branche « OpenBSD » :

        $ cvs update -A

ôterait tous les marqueurs collants, ainsi que d'éventuelles options de date, mais le mode de numérotation des révisions ne serait pas modifié pour autant. Toutefois il aurait été plus commode, pour qui souhaiterait s'investir dans NetBSD de pouvoir récupérer une copie de l'état de ce projet en spécifiant le label :

        $ cd <répertoire_quelconque>
        $ cvs checkout -r NetBSD

S'il s'avère nécessaire d'intervenir sur une version antérieure d'un projet, la collection des révisions de fichiers qui le constituaient lorsque le label de version (Cf. label de version) (en anglais release label) a été mémorisé peut donc être « rappelée » de cette façon --- le cas échéant dans un répertoire local distinct de celui la dernière version.

Si la branche n'a pas encore été créée, il est même possible de le faire à partir de la copie de travail, en indiquant simplement :

        $ cvs tag -b 1_0-CORR

Encore plus fort : si un problème affectant le fichier tri.c est corrigé dans la révision « 1.4.2.1 », qui se situe dans une branche nommée « 1_0-CORR », mais perdure dans la branche principale, alors que tri.c en est maintenant à la révision « 1.13 », il est parfaitement possible d'envisager une fusion (en anglais merge) entre le fichier corrigé (maintenant « 1.4.2.2 ») de la branche secondaire et sa version actuelle (« 1.13 ») dans la branche principale :

        $ cvs update -j 1.0-CORR tri.c 

Ce qui présuppose, naturellement, que la version de travail courante soit la branche principale, et non pas la branche « 1_0-CORR ». Selon le même principe, il est possible d'envisager la fusion d'une branche complète. Avec des risques de conflits accrus, mais dont la gestion peut s'avérer quand même moins contrainte et plus sûre que la re-saisie manuelle...

Toutes les possibilités du branching n'ont pas été ici exposées. Pour plus de détails, et pour la mise en oeuvre effective de ces puissantes fonctions, la consultation du manuel s'impose. Qu'on retienne au moins la puissance, et la richesse de cvs, qu'on ne soupçonnerait pas nécessairement sous ses allures un peu frustes de scripts évolués.

4.5 cvs côté « serveur »

Afin de mieux comprendre le fonctionnement de cvs un petit détour côté « serveur » s'impose. Créer son propre référentiel (repository) est très simple :

        $ mkdir <où_on_veut>/cvs
        $ export CVSROOT="<où_on_veut>/cvs"
        $ cd <où_on_veut>/cvs; cvs init

Cette série de commandes :

Avec cvs init, une collection de fichiers est créée en même temps qu'un répertoire CVSROOT. La plupart sont éditables --- et auto-documentés --- mais il n'est nullement nécessaire d'intervenir pour obtenir un fonctionnement satisfaisant.

Le détail des opérations en vue d'ajuster les « droits » (lecture et écriture) ne relève pas d'un exposé sur l'utilisation de cvs, mais il ne faut pas oublier que l'exécutable tourne par défaut avec les droits de l'utilisateur courant. A priori, le recours à la gestion de « groupes » d'utilisateurs paraît plus que souhaitable.

Pour créer un module à la racine de ce référentiel, le plus simple est d'importer dans le dépôt une arborescence existant déjà par ailleurs. À condition que la variable d'environnement CVSROOT aie été correctement initialisée, il suffit de se placer dans le répertoire qui contient les sources, puis d'exécuter la commande d'importation en précisant le nom du projet (ici : « projet-XYZ »), son origine (Cf. origine) « Toto », ainsi qu'un label de version « initial » :

        $ cd ~/mon-projet
        $ cvs import -m "Initialisation du projet" projet-XYZ Toto initial

Un répertoire projet-XYZ est créé à la racine du référentiel. Comme le nom de projet ne précise pas un chemin de répertoire, un répertoire correspondant vient d'être créé. Mais on aurait pu tout aussi bien importer de la même manière un répertoire à l'intérieur d'un module (Cf. module) existant déjà dans le référentiel. Soit pour créer un nouveau sous-module, soit simplement pour ajouter d'une passe toute une arborescence à un module existant. Ainsi, la commande import peut se substituer avantageusement à add pour ajouter tout un répertoire dans les sources d'un projet (Cf. projet) donné.

        $ cd ~/répertoire_source
        $ cvs import -m "Initialisation du projet" \
                projets/projet-XYZ/ajout Toto initial

Ces mêmes procédures peuvent être mises en oeuvre pour créer un module aussi bien « en local » que sur un serveur distant. Il suffit d'avoir les droits idoines. Ne pas oublier non plus de renseigner, le cas échéant, la variable CVS_RSH. On peut d'ailleurs remarquer qu'à part la commande init, toutes s'exécutent de façon transparente, que le référentiel soit local ou distant.

Une branche d'import spécifique est créée, portant le nom du label d'origine (Cf. origine), destinée à recevoir éventuellement sur une même branche des imports successifs de versions externes du même projet. Cette branche particulière ne servira pas à tracer des modifications locales, mais plutôt à suivre les évolutions des différents éléments importés entre deux versions externes.

Les labels de version spécifiés à l'import doivent si possible correspondre avec la nomenclature externe des projets importés.

Ceci est particulièrement utile pour la gestion de sous-modules ou bibliothèques d'origine externe, qui sont intégrés dans le projet, en différentes versions successives, et sans qu'on contribue localement à leur développement.

4.6 Astuces diverses

Réservation temporaire

On souhaiterait parfois pouvoir empêcher temporairement la modification d'un fichier par un tiers. À la condition de n'utiliser cette fonctionnalité qu'à bon escient (ce qui implique que les autres utilisateurs soient prévenus ou aient au moins connaissance du procédé), c'est envisageable. Les commandes :

        $ cvs watch on <fichier>
        $ cvs edit <fichier>

« réserveront » l'édition du fichier à l'utilisateur courant. Le mécanisme est le suivant : lors de leur prochain accès au référentiel, tous les autres utilisateurs verront les attributs de leur copie locale passer en « lecture seule ». (Mais il faut savoir que l'administrateur du dépôt peut désactiver cette option, qui n'est donc pas toujours disponible pour tout un chacun.) S'ils tentent d'intervenir sur le fichier, leur éditeur doit normalement indiquer que la sauvegarde des modifications ne sera pas possible.

Bien sûr, si un utilisateur commence à éditer le fichier sans avoir au préalable vérifié son statut ou simplement accédé au projet sur le référentiel, il ne s'apercevra du « verrouillage » qu'au moment du commit --- ce qui n'est certes pas très agréable. À moins de créer une « branche » à la volée --- ce qui ne serait pas une bonne idée --- il va falloir attendre que l'autre utilisateur « rende les droits », puis tenter une fusion automatique (par update) des deux versions... pour peut être ensuite devoir finalement se résoudre à l'effectuer « à la main ».

Attention : status n'indique (malheureusement) pas s'il existe un verrou de ce type sur un fichier. Pour éviter ce genre de désagrément, il faut taper explicitement :

        $ cvs editors

qui permet de vérifier si des fichiers sont ou non actuellement verrouillés pour édition et indique si nécessaire le nom de l'utilisateur, le nom de la machine où se trouve la copie « verrouillée », ainsi que l'heure et la date à laquelle cette action a été entreprise. Le cas échéant, il conviendra d'attendre que l'utilisateur temporairement « privilégié » ait terminé d'éditer le fichier puis ait validé ses modifications sur le référentiel (via commit). Le « verrou » d'édition est alors automatiquement ôté (pas de risque d'oubli ou d'abus involontaire, sauf à « réserver » l'édition et trop tarder à la valider).

Si l'on change d'avis parce que finalement la correction ne s'avère pas nécessaire,

        $ cvs unedit <fichier>

inversera la commande de verrouillage, et rendra à tous les intervenants la possibilité d'éditer le fichier. Attention toutefois aux permissions locales : il semble qu'elles ne soient pas toujours correctement mises à jour ; de sorte que si un fichier local demeure en « lecture seule », il ne sera pas superflu de vérifier (editors) s'il est effectivement « réservé » par un autre utilisateur... puis, s'il y a eu défaillance du mécanisme de déverrouillage automatique, remettre manuellement les droits « qui vont bien ».

Recevoir des alertes

Pour les projets à moyen et long cours, on peut raisonnablement souhaiter que chaque intervenant puisse recevoir une « alerte » par courrier électronique pour l'informer qu'une modification vient d'être faite sur un fichier qui n'avait plus évolué depuis longtemps. Pour l'administrateur du référentiel, la manière d'opérer est simple : il suffit de dé-commenter la ligne :

        $ ALL mail %s -s "CVS notification"

dans le fichier CVSROOT/notify. De sorte que toute intervention sur un fichier du référentiel (par edit, unedit ou commit) provoquera l'envoi d'un mail indiquant le nom du fichier, le nom de l'intervenant, ainsi que le commentaire qui a été ajouté lors du commit à tous les utilisateurs qui en ont fait la demande par :

        $ cvs watch add

L'auteur de la modification ne reçoit pas de message, mais comme ce mécanisme peut toutefois s'avérer assez rapidement fastidieux, il est possible d'indiquer des restrictions supplémentaires :

Voire d'annuler toute réception de messages :

        $ cvs watch remove

Suppression d'un répertoire

La commande remove n'opère que sur les fichiers. Pour supprimer un répertoire, l'opération est un peu plus complexe, et doit être réalisée au moins en trois temps :

        $ rm <répertoire>
        $ cvs release -d <répertoire>
        $ cvs update -P

La commande release indique que le répertoire n'est plus utilisé tandis que l'option -d le supprime effectivement du référentiel. Toutefois, le répertoire demeurera sur les copies locales des utilisateurs, tant que la seconde commande n'aura pas été effectuée.

Renommer un fichier

De la même façon, il n'existe pas de commande explicitement destinée à renommer ou déplacer un fichier. Il est toutefois possible de compenser cette absence, en supprimant puis recréant un élément sur le dépôt, après en avoir préalablement renommée la copie locale. Malheureusement, l'historique du fichier n'est pas conservé. Il convient donc de recourir à cet expédient avec précaution.

        $ mv <ancien_nom> <nouveau_nom>
        $ cvs remove <ancien_nom>
        $ cvs add <nouveau_nom>
        $ cvs commit -m "<ancien_nom> renomme en <nouveau_nom>" <ancien_nom> <nouveau_nom>

Restauration d'un fichier effacé

Lorsqu'un fichier a été supprimé par la commande delete, cvs en conserve bien sûr la trace et l'historique. C'est la raison pour laquelle il est toujours possible de « ressusciter » un élément longtemps après sa destruction ; et cela même si l'on ne dispose pas d'une commande explicitement destinée à cet effet.

Le « truc » consiste à rappeler d'abord localement une révision antérieure à la suppression, au moyen de la commande update. On souhaitera probablement récupérer l'avant-dernière version (la dernière étant exclue, puisqu'elle n'est qu'un « fantôme », apparu post mortem. Mais, si l'on souhaite « remonter » plus avant, cvs log <fichier_effacé> fonctionne, et permet d'identifier la version que l'on souhaite ramener à l'existence :

        $ cvs update -r 1.13 <fichier_effacé>

puis de réinjecter officiellement ce fichier dans le référentiel :

        $ cvs add <fichier_ressuscité>
        $ cvs commit -m "restauration du fichier effacé" <fichier_ressuscité>

Cependant il peut arriver qu'un autre fichier portant le même nom mais exerçant une fonction différente a remplacé l'élément effacé. Afin d'éviter que la restauration de l'ancien n'écrase le plus récent, on utilisera l'option -p, qui permet de créer un « tube » (en anglais : pipe) vers la sortie standard, pour rediriger cette dernière vers le fichier de son choix :

        $ cvs update -r 1.1 ancien_nom -p > nouveau_nom

Mots clés de substitution

On aura sans doute déjà remarqué la présence de lignes telles que :

        $Id: cvs.sgml,v 1.69 2000/12/28 10:53:33 oberger Exp $

dans les fichiers sources, voire dans les documentations ou les pieds de pages HTML. cvs permet en effet d'indiquer quelques mots clés qui seront automatiquement « développés » lors de la sauvegarde du fichier sur le dépôt.

Ainsi, pour obtenir la ligne ci-dessus, l'auteur du document a seulement placé la ligne suivante dans son fichier, avant le commit:

$Id$

Lorsque le fichier géré par cvs est un fichier source dans un langage particulier, les mots-clés de substitution doivent souvent être placés dans des zones du fichier où ils ne perturberont pas les compilateurs ou les interpréteurs : entre commentaires, dans des chaînes de caractères, ...

Différents mots-clés peuvent être utilisés ainsi. Nous détaillerons l'emploi des deux principaux mots-clés utilisés :

$Id$

Le mot clé le plus couramment utilisé est $Id$, dont « l'expansion » indique :

Chacune de ces substitutions est disponible individuellement ($Author$, $Date$, $Revision$...) et peut être insérée à n'importe quel endroit du fichier --- bien qu'on les place généralement en tête, pour des raisons évidentes de lisibilité.

Il peut être particulièrement utile de rendre visible dans un programme, ou dans un document compilé, le résultat des substitutions de ces mots-clés, afin de pouvoir tracer le fichier source à l'origine du programme ou du document manipulé par l'utilisateur final. Si le fichier source a évolué par la suite, on peut ainsi identifier exactement, de façon sûre, dans quelle révision se situe une anomalie, par exemple.

$Log$

Bien qu'on puisse, pour tout fichier géré par cvs, retrouver l'historique des changements qui lui ont été apportés, en examinant les commentaires saisis par les auteurs des modifications, avec la commande log, il peut être utile d'insérer automatiquement l'ensemble de ces commentaires à l'intérieur même du fichier.

Ceci permet d'accéder rapidement, en cours de modification d'un fichier, à l'historique des modifications précédentes, sans avoir à quitter un éditeur de fichiers pour lancer une commande CVS.

Le mot-clé $Log$, placé de préférence en fin de fichier, permet d'ajouter, de façon automatique, lors de chaque commit, le commentaire saisi par l'auteur du commit, en tête d'une série constituant l'historique des commentaires.

A la création du fichier, on placera ainsi, à la fin du fichier, une ligne de la forme :

# $Log$

pour un script shell ou un Makefile.

En effet, le processus de substitution de cvs duplique les caractères (de commentaires) placés avant de mot-clé $Log$ au début de chaque ligne substituée, de la façon suivante :

# $Log: cvs.sgml,v $ # Revision 1.2 2000/08/23 09:21:33 mikl # Correction d'une typo dans le makefile. # # Revision 1.1 2000/08/01 10:55:30 oberger # Version initiale #

Pour un fichier HTML, SGML, ou XML, on utilisera plutôt :

<!&dash;&dash; $Log$ &dash;&dash;>

en fin de fichier, afin que la substitution respecte la syntaxe des commentaires du langage, et que le document reste bien formé.

Remarques

À noter enfin, qu'il est possible d'annihiler temporairement la mise à jour des mots clés lors d'une sauvegarde sur le référentiel :

        $ cvs update -ko <nom de fichier>

Lorsqu'on recourt à ces mots clés de substitution, il faut veiller à « fermer » les documents en cours d'édition, car la copie locale est immédiatement affectée par l'« expansion » ou la mise à jour des balises. Un logiciel éditeur peut donc légitiment s'inquiéter de ce que le fichier en cours de traitement vient d'être modifié par ailleurs... Certes, « l'écrasement » de la version qui vient d'être sauvegardée par la version en cours d'édition n'est guère important (normalement seule l'expansion des mots clés a pu changer) mais cela est de toutes façons source de confusions pour l'utilisateur, qui peut, lorsque l'événement se produit, légitimement s'interroger sur ce qu'il a effectivement validé sur le référentiel.

Configurer le comportement par défaut de certaines commandes cvs

Certaines commandes sont systématiquement employées avec les mêmes options. Ainsi qu'on le ferait en créant un alias pour le shell courant (mais avec une syntaxe simplifiée), ces options peuvent être mémorisées dans un fichier ~/.cvsrc :

        diff -u
        cvs -z3

ces deux lignes d'exemple, produisent respectivement un format « unifié » par défaut avec la commande diff, ou forcent le niveau de compression 3 lors de chaque transfert de données (utile si la liaison s'effectue par modem).

Ignorer certains fichiers avec .cvsignore

Bien qu'un fichier ne puisse s'ajouter spontanément au référentiel, ce qui autorise, encore une fois de compiler sans avoir à se préoccuper de faire une nouvelle copie des sources, la présence de ces fichiers « fantômes » produit un certain « bruit » dans les affichages de cvs (noms de fichiers précédés d'un point d'interrogation qui apparaissent lors d'un checkout même avec l'option -q).

Par défaut, cvs ignore déjà un certain nombre de fichiers portant des extensions comme .old, .bak ou .obj... Il est possible d'en ajouter d'autres dans un fichier .cvsignore placé à la racine de son répertoire personnel (voire dans une variable système CVSIGNORE) ou bien, afin de contrôler les exclusions plus finement, dans les répertoires où se trouvent les fichiers concernés.

        $ cat ~/.cvsignore
        *.htm?
        *.ps
        *.log
        *.tex
        *.out

Inversement, l'ajout d'un ! (point d'exclamation) à gauche d'un motif permettra de prendre exceptionnellement en considération un type de fichier normalement ignoré par cvs.

Commandes « administratives »

On aura remarqué que l'expansion du mot clé $Id$, outre les informations présentées dans la section précédente, traduit généralement l'état du fichier par la chaîne par défaut « Exp » (pour « expérimental »). Il ne s'agit pas d'un « label » mais d'un indicateur d'état (state) modifiable par la commande admin. Par exemple :

        $ cvs admin -sStable <nom_de_module>

appliquera l'indicateur « Stable » aux révisions courantes de l'ensemble des fichiers qui composent ce module. Il est aussi possible de n'affecter qu'un seul fichier, voire une révision particulière :

        $ cvs admin -sStable:1.10 <nom_de_fichier>

L'intérêt de cette possibilité, qui semble faire double emploi avec les labels peut paraître ésotérique, sinon douteux. Elle permet toutefois de connaître immédiatement le « statut » d'un fichier lors de son édition (pour peu que le mot clé $Id$ y figure).

On remarquera encore une option permettant de modifier ou ajouter un commentaire a posteriori à une révision particulière d'un fichier ou d'une collection :

        $ cvs admin -S1.10:"Nouveau commentaire" <nom_de_fichier>

Signalons enfin la possibilité de déverrouiller une révision d'un fichier (où la dernière, si aucun numéro de révision n'est pas passé en paramètre) :

        $ cvs admin -u1.10 <fichier>

Cette commande peut s'avérer nécessaire lorsqu'un élément a été préalablement verrouillé par cvs admin -l <fichier>. Toutefois, il est préférable de recourir au mécanisme de réservation via watch et edit, plutôt qu'au « verrouillage strict ».

Commandes abrégées

Enfin, lorsque le comportement des principales instructions de cvs sont devenues familières, il peut être agréable de savoir que la plupart disposent d'un mode abrégé :

        $ cvs --help-synonyms

en produit la liste à jour (dépendante de la version de cvs). Sans oublier que :

        $ cvs --help-commands

rappelle l'action de chacune en une ligne. Attention, la page de manuel officielle de cvs(1) ignore certaines commandes « avancées ». Paradoxalement, et à condition d'en connaître déjà l'utilité, on obtient souvent plus d'informations (en particulier sur les options disponibles) en tapant :

        $ $ cvs -H <nom_d'_une commande>

5. Interfaces

5.1 TkCvs

TkCvs permet de disposer d'une interface graphique de navigation dans le dépôt (visualisation et opérations globales sur les modules), dans un répertoire contenant une copie de travail d'un projet (gestion des fichiers), et dans l'historique des révisions d'un fichier (visualisation d'arborescence).

Ne pas utiliser en même temps une version de TkCvs dans /usr et une autre dans /usr/local (au risque de créer des conflits entre fichiers sources tcl).

Utiliser la version la plus à jour (V6.3 à l'heure actuelle) de tkcvs.

Il est nécessaire de procéder à une configuration spécifique en cas d'utilisation de cvs par dessus ssh afin de supprimer l'apparition de messages de ssh dans les résultats des commandes cvs interprétés par TkCvs :

6. Références

6.1 Glossaire

Le petit recueil ci-dessous vise à expliciter certains termes employés dans la présente documentation, et lever les ambiguïtés qui pourraient naître de la traduction depuis l'anglais. Il est toutefois probable que, s'agissant des concepts sous-jacents, la lecture de ce lexique ne puisse pas se substituer à celle de la documentation proprement dite, voire à « l'expérimentation ».

6.2 Documentation en ligne

En dehors de la documentation diffusée avec les sources et les versions binaires, le site de référence pour approfondir CVS est  http://www.cvshome.org. On consultera aussi avec profit http://www.loria.fr/~molli/cvs-index.html.

Une excellente introduction (« Mini-HOWTO ») en français rédigée par Antoine Marin est disponible à http://www.loria.fr/~molli/cvs/HowToCVS.ps, sur le site géré par Pascal Molli.

Une autre introduction en français rédigée par Stéphane Bortzmeyer et traitant conjointement des aspects serveur et client se trouve encore à http://www.freenix.org/curiosite/cvs.html.

En anglais, on lira un livre très riche rédigé par Karl Fogel, dont les principaux chapitres, placé sous GFDL (GNU Free Documentation Licence) sont disponible en ligne à http://cvsbook.red-bean.com/cvsbook.html Attention : ce fichier jauge plusieurs centaines de Ko ...

http://www.gnu.org/manual/cvs/ propose le manuel réalisé par la FSF.

Un CVS-RCS-HOWTO écrit pour le Linux Documentation Project est disponible en ligne et inclus dans les distributions récentes. Outre un comparatif des avantages/désavantages des deux systèmes de gestion et de contrôle de sources (RCS est à la fois plus ancien et moins sophistiqué), il propose des scripts « clé en main » censés faciliter l'usage des principales commandes. Une version HTML se trouve à http://sunsite.unc.edu/LDP/HOWTO/CVS-RCS-HOWTO.html

Enfin des tutoriaux spécialisés sont aussi disponibles sur les sites offrant la possibilité de télécharger des sources via cvs anonymous, voire de participer au développement d'un projet.