Repository 32bit  Forum
Repository 64bit  Wiki

Breve introduzione a CVS

Da Slacky.eu.
Versione delle 18:47, 9 set 2006, autore: Slacky (Discussione | contributi)

(diff) ← Versione meno recente | Versione attuale (diff) | Versione più recente → (diff)

In questo breve articolo viene presentato il sistema di controllo delle versioni CVS (Concurrent Versions System) ed il suo front-end per KDE, Cervisia.

Indice

Introduzione al problema

Quando un programmatore sviluppa un software di discrete dimensioni, spesso, si trova a dover affrontare tutta una serie di problemi che non hanno direttamente a che fare con il software oggetto di sviluppo. Vediamone alcuni esempi nel particolare.
Immaginiamo, ad esempio, un programmatore alle prese con un software perfettamente funzionante. Nel caso in cui una importante modifica al codice, necessaria per poter aggiungere una nuova feature, renda il programma non più in grado di funzionare oppure crei un pericoloso bug, la possibilità di tenere traccia di tutte le modifiche effettuate e di poter ritornare ad una versione priva di problemi risulterebbe piuttosto utile.
Dobbiamo poi notare che, in generale, nessun software di discrete dimensioni viene sviluppato da un singolo programmatore ma, più realisticamente, da un team composto da più persone che possono anche lavorare in luoghi e tempi diversi. Con queste premesse si deve tener conto quindi anche dei noti problemi che il settore definito computer-supported cooperative work (CSCW) tenta di risolvere, come, ad esempio, la gestione di modifiche effettuate contemporaneamente ad uno stesso file da parte di due programmatori differenti.
L’obiettivo di un sistema di controllo delle versioni è proprio quello di permettere ad una o più persone di lavorare ad uno stesso progetto in maniera semplice ed efficace riducendo al minimo il carico organizzativo necessario.

I primi passi

Un primo tentativo di risolvere questi problemi prevede l’utilizzo del tool Unix diff in combinazione con il programma sviluppato da Larry Wall, patch. diff è stato pensato per permettere il confronto di due file simili (F1 e F2) e restituire in output una lista (d) con le differenze riscontrate (diff : F2 − F1 = d). Sulla base di questo output, poi, patch è in grado di modificare il file originale (F1) andando ad inserire le modifiche e creando così una versione (F2) cosiddetta "patched" (patch : F2 = F1 + d).
Sebbene questa soluzione renda più semplice incorporare numerose modifiche effettuate da diversi programmatori su un singolo progetto, essa è ancora priva della capacità di tenere traccia della project’s history. Nell’eventualità, infatti, che una modifica debba essere eliminata dal codice, anche nel caso ottimistico in cui il programmatore sappia quale patch ha prodotto le modifiche, l’eliminazione manuale è comunque un processo noioso e destinato a produrre errori. Un passo avanti nella gestione di progetti software si ha con il programma sviluppato da Walter Tichy Revision Control System (RCS)4 nel 1982 che mantiene, per ogni file, i dati storici ad esso relativi. I vantaggi però finiscono qui. RCS, infatti, è privo di numerose features quali la possibilità di lavorare utilizzando una rete, questo obbliga gli sviluppatori a lavorare alla stessa macchina su cui vengono salvati i dati storici del progetto oppure ad avvalersi di script che mantengano aggiornato il server RCS. In questo software manca inoltre l’idea stessa di progetto, ogni file infatti viene gestito singolarmente e non ci sono relazioni tra file nemmeno se questi si trovano nella stessa directory. Il problema maggiore però deriva dallo stile di sviluppo basato sul modello “lock-modify-unlock”. In questo modo uno sviluppatore che desideri lavorare su un file deve prima assicurarsi dei diritti di scrittura esclusivi per quel file (un lock), in modo che nessun altro possa modificarlo contemporaneamente, effettuare le modifiche e rilasciare il file (unlock). Con questo modello si rende necessaria una negoziazione tra gli sviluppatori per decidere chi possa lavorare o meno sul file in questione, con lo spiacevole imprevisto che, se un programmatore dimentica di sbloccare il file, l’unico modo per gli altri di lavorare è quello di “rubargli il lock”.

Lo sviluppo open source

In un contesto classico di sviluppo del software, basato cioè su un’unica azienda al cui interno lavorino tutti i programmatori associati al progetto, l’uso di RCS è possibile anche se si rende necessario organizzare il lavoro del team di sviluppo in maniera molto precisa per evitare “sovrapposizioni di modifiche”.
Con il crescere del movimento open source, però, i problemi non risolti da RCS vengono percepiti in maniera molto più pesante. Lo sviluppo di un software open source, infatti, prevede il contributo di un numero estremamente elevato di programmatori sparsi in tutto il pianeta. In questo contesto appare chiaro come il modello “lock-modify-unlock” fallisca. Evidentemente non è possibile coordinare un gruppo di sviluppatori se nemmeno si conoscono i membri che in un dato momento lavorano al progetto, e non è nemmeno pensabile, dato il gran numero di persone coinvolte, permettere la modifica di un file ad un solo programmatore alla volta.

Una soluzione: CVS

Nel 1986, Dick Grune, ha dato il via al progetto CVS (Concurrent Versions System) con l’intento di risolvere i problemi lasciati aperti da RCS. In origine CVS era una collezione di script, riscritti in linguaggio C da Brian Berliner nel 1989, basati sul formato di salvataggio dei dati storici di RCS.
I miglioramenti più evidenti riguardano:

  • la possibilità di gestire un progetto come un’unica entità;
  • il networking;
  • l’abbandono del modello "lock-modify-unlock" in favore del migliore "copy-modify-merge".

A differenza di RCS, che gestisce ogni singolo file come entità autonoma, CVS fornisce la possibilità di associare ad un progetto un insieme di directory e file. In questo modo è possibile gestire il progetto come una singola entità a cui applicare i comandi di gestione. Nel 1990, Jim Kingdon, ha aggiunto a CVS la possibilità di networking. Finalmente gli sviluppatori possono accedere ai file del progetto da ogni parte del mondo sfruttando Internet. Invece di proibire la modifica simultanea di un file costringendo gli sviluppatori ad un’attenta attività di coordinamento, CVS permette di lavorare contemporaneamente sullo stesso file, si incarica di applicare le modifiche apportate e di segnalare eventuali conflitti. Il modello usato è il "copymodify-merge" che possiamo riassumere nei seguenti passi.

  1. Lo sviluppatore (A) scarica una copia del progetto, definita working copy, dal server CVS (repository). Questa azione prende il nome di check out.
  2. Applica liberamente tutte le modifiche al progetto. Nello stesso tempo altri programmatori potrebbero fare lo stesso (B).
  3. Terminato il lavoro il programmatore (A) aggiorna il progetto contenuto nel server CVS. In questo caso si parla di commit oppure, alternativamente, check in.
  4. Nel frattempo altri programmatori (B) potrebbero richiedere a CVS le modifiche al progetto non presenti nella loro working copy oppure l’ultima versione disponibile (C). CVS scaricherà o aggiornerà automaticamente (update) i file in questione.
Cvs.png

Nel caso in cui due programmatori modifichino un file nello stesso punto, cioè vengano modificate le stesse linee di codice, CVS se ne accorge e, al tempo del commit o dell’update, notifica il conflitto (conflict). La soluzione dei conflitti viene comunque lasciata ai programmatori coinvolti. Dando uno sguardo più approfondito si può notare come, vista la necessità di CVS di tenere traccia di tutte le modifiche al progetto fin dal suo inizio, queste vengano salvate internamente come una sequenza di diffs. Grazie a questo accorgimento CVS è in grado di ricostruire ogni versione precedente del progetto applicando a rovescio le modifiche. Sebbene un sistema di gestione delle versioni dia i maggiori vantaggi se usato per lo sviluppo di un progetto da parte di un team composto da numerose persone, ci sono buoni motivi perchè venga utilizzato anche per progetti sviluppati da un singolo programmatore. Oltre alla facilità di applicare o togliere modifiche ad un progetto si può anche citare l’evidente risparmio di spazio su disco. Così facendo infatti non si rende più necessario copiare più volte l’intero progetto per mantenerne diverse versioni. Un sistema di gestione delle revisioni rende inoltre più semplice la creazione di documenti riguardanti lo stato delle modifiche effettuate sul progetto (ad esempio i ChangeLog). Il numero di progetti sviluppati utilizzando CVS è sicuramente molto elevato e, tra di essi, possiamo ricordare a titolo di esempio il server Web Apache, i sistemi operativi FreeBSD, OpenBSD e NetBSD, il desktop manager Gnome e il database PostreSQL.

CVS in pratica

Nella seguente sezione verrà presentata la procedura di installazione del software a partire dai sorgenti. Verrà inoltre presentata l’interfaccia grafica Cervisia che attualmente è un’applicazione ufficiale del desktop manager KDE.

Installazione

CVS

Come prima cosa è necessario procurarsi i sorgenti della versione che si desidera installare, il sito di riferimento per il progetto CVS è http://www.cvshome.org, in cui si può trovare l’ultima versione stabile del programma.
Al momento della scrittura di questa relazione è la versione 1.11.18 contenuta nel file cvs-1.11.18.tar.bz2. Terminato il download decomprimiamo l’archivio così ottenuto con il classico comando:

root# tar xvfj cvs-1.11.18.tar.bz2

e, nel caso non si siano verificati errori, sul nostro disco troviamo una directory chiamata cvs-1.11.18. Per cominciare la fase di installazione vera e propria portiamoci all’interno della directory appena creata:

root# cd cvs-1.11.18

ed utilizziamo il comando

root#./configure --help

per avere un elenco delle possibili opzioni passabili allo script di configurazione. Per installare CVS nella directory /opt/cvs/ digitiamo i seguenti comandi:

root#./configure --prefix=/opt/cvs/ && make

e, come utente root,

root# make install

A questo punto possiamo inserire la directory /opt/cvs/bin nel $PATH oppure linkare gli eseguibili in una directory già contenuta in esso come nel seguente esempio:

root# ln -s /opt/cvs/bin/cvs /usr/local/bin/cvs
root# ln -s /opt/cvs/bin/cvsbug /usr/local/bin/cvsbug
root# ln -s /opt/cvs/bin/rcs2log /usr/local/bin/rcs2log

Per avere a disposizione anche le “man pages” e il manuale “info” questi sono i comandi da eseguire:

root# ln -s /opt/cvs/man/man1/cvs.1 /usr/local/man/man1/cvs.1
root# ln -s /opt/cvs/man/man5/cvs.5 /usr/local/man/man5/cvs.5
root# ln -s /opt/cvs/man/man8/cvsbug.8 /usr/local/man/man8/cvsbug.8
root# ln -s /opt/cvs/info/cvs* /usr/local/info/.
root# cat /opt/cvs/info/dir >> /usr/info/dir

Cervisia

Cervisia è una GUI per CVS sviluppata all’interno del progetto KDE e quindi di norma viene installata assieme al desktop manager. Nel caso manchi, basterà installare il pacchetto kdesdk dai sorgenti con il classico:

root#./configure && make && make install

Cervisia è un front-end grafico di CVS “lato client” e quindi non permette di impostare gli aspetti di configurazione di un server CVS, argomento del prossimo paragrafo.

Configurazione

Se siamo interessati soltanto allo sviluppo di un progetto già mantenuto su un server CVS, non dobbiamo fare alcuna configurazione; se invece desideriamo utilizzare CVS per lo sviluppo dei nostri progetti è necessario configurare CVS affinchè operi da server.
Di seguito verrà presentata, per semplicità, la configurazione di un server CVS per un singolo utente/sviluppatore (nel caso in cui si volgiano aggiungere altri utenti questo non crea particolari problemi oltre al tempo necessario per farlo materialmente). Viene inoltre configurato l’utente anonimo in modo tale da permettere a chiunque disponga di una connessione al nostro server di scaricare il progetto che stiamo sviluppando. Il primo passo è quello di creare un repository in questo modo:

root# mkdir /usr/local/cvsrepos
root# cvs -d /usr/local/cvsrepos/ init

così facendo CVS crea automaticamente la directory CVSROOT all’interno di /usr/local/cvsrepos/, tale directory contiene file necessari a CVS per il corretto funzionamento. Per problemi di sicurezza è fortemente consigliato creare un gruppo cvs: root#groupadd cvs a cui aggiungere gli utenti che hanno necessità di accedere al repository. Ecco come appare la corrispondente linea nel file /etc/group con l’elenco di utenti abilitati (è probabile che ci siano piccole differenze oltre ovviamente ai nomi degli utenti):

cvs:*:504:slack,anonymous

L’ultimo passo consiste nell’assegnare al repository i permessi corretti in modo che riflettano questi cambiamenti:

root# cd /usr/local/
root# chgrp -R cvs cvsrepos/
root# chmod -R ug+rwx cvsrepos/

a questo punto tutti gli utenti elencati nel gruppo cvs possono iniziare un nuovo progetto nel nostro repository. Per permettere l’accesso al repository via rete ad utenti privi di un account locale è necessario configurare il password-authenticating server, il servizio si rende indispensabile nel caso si desideri permettere gli accessi anonimi.

Password-Authenticating server

Per prima cosa bisogna accertarsi che nel file /etc/services sia presente un riga come questa:

cvspserver 2401/tcp

che ha il compito di associare il password-authenticating server di CVS alla porta 2401. A questo punto bisogna informare l’Unix Internet Daemon (inetd) su come gestire una richiesta di connessione per il servizio cvspserver, modifichiamo quindi il file /etc/inetd.conf aggiungendo la seguente riga:

cvspserver stream tcp nowait root /usr/local/bin/cvs \
cvs --allow-root=/usr/local/cvsrepos pserver

e riavviamo il demone inetd. Adesso è il turno degli utenti, creiamo il file /usr/local/cvsrepos/CVSROOT/passwd ed inseriamo gli utenti desiderati come nell’esempio:

slackcvs:$1$WuA/mI/0$7XO16pEouKtVlwPylKShr0:slack
anonymous:$1$.Gs0DG/0$KeNxi291fp264R1SHOcT5/

il formato del file è molto semplice e prevede il seguente schema:

<NOME_UTENTE>:<PASSWORD_CRITTATA6>:[UTENTE_DEL_SISTEMA]

dove UTENTE_DEL_SISTEMA è opzionale ed è un login valido sul server CVS, dobbiamo fare attenzione che in /etc/passwd sia presente un utente anonymous:

anonymous:x:1006:100:Anonymous CVS User,,,:/usr/local/cvsrepos/:/bin/false

L’ultimo passo consiste nel creare i file readers e writers nella directory /usr/local/cvsrepos/CVSROOT/ nei quali inserire la lista degli utenti a cui concedere il diritto di sola lettura o di lettura-scrittura. Ovviamente il file readers conterrà almeno l’utente anomimo:

root# cat readers
anonymous

mentre writers conterrà l’altro utente che abbiamo impostato in /usr/local/cvsrepos/CVSROOT/passwd:

root# cat writers
slackcvs

si noti come sia indispensabile una linea vuota al termine di questi file. La configurazione del server CVS è conclusa, ora possiamo iniziare lo sviluppo.

Uso

Iniziare un nuovo progetto

Immaginiamo ora di voler sviluppare un’ipotetica applicazione HelloWorld. Ci mettiamo al lavoro e dopo aver creato sul nostro hard disk la directory hello_world con al suo interno i primi file:

slack$ cd hello_world/
slack$ ls
DirA DirB HelloWorld.java

per poter sfruttare le potenzialità di CVS dobbiamo importare il progetto nel repository. Prima di eseguire il comando, però, CVS ci obbliga a loggarci sul server in modo che venga creato il file ~/.cvspass nella home dell’utente. Questo file contiene i valori di login per il Password-Authenticating server:

slack$ cvs -d :pserver:slackcvs@localhost:2401/usr/local/cvsrepos login
Logging in to :pserver:slackcvs@localhost:2401/usr/local/cvsrepos
CVS password:
cvs login: warning: failed to open /home/slack/.cvspass for reading: \
No such file or directory

come possiamo notare al primo login avremo un warning che ci informa che il file ~/.cvspass non esiste, non preoccupiamocene in quanto verrà creato dopo l’esecuzione del comando e, ad un secondo login, il warning sparirà.
Il flag -d serve per indicare a cvs dove si trova il repository su cui vogliamo lavorare. Per evitare di riscrivere tutta la stringa ad ogni comando possiamo settare la variabile d’ambiente CVSROOT in questo modo:

slack$ export CVSROOT=":pserver:slackcvs@localhost:2401/usr/local/cvsrepos"

Ora siamo pronti per importare il progetto hello_world nel repository. Posizioniamoci nella directory contenente i file:

slack$ cd hello_world/

e utilizziamo il comando import:

slack$ cvs import -m "Inizio del progetto" hello_world slack start
N hello_world/HelloWorld.java
cvs import: Importing /usr/local/cvsrepos/hello_world/DirA
N hello_world/DirA/Agnul.java
cvs import: Importing /usr/local/cvsrepos/hello_world/DirB
N hello_world/DirB/Predi.java
cvs import: Importing /usr/local/cvsrepos/hello_world/DirB/SubDirB
N hello_world/DirB/SubDirB/SubPredi.java
No conflicts created by this import

come possiamo vedere:

root# cd /usr/local/cvsrepos/
root# ls hello_world/
DirA DirB HelloWorld.java,v

il repository adesso contiene il nostro progetto. Il flag -m serve per inserire un commento nei log che CVS mantiene per il progetto. Questo commento è obbligatorio e, nel caso ci si dimentichi di crearlo esplicitamente, CVS ci ricorderà di farlo automaticamente lanciando un editor di testo al momento dell’import. hello_world è il nome del progetto e anche della directory che verrà creata all’interno del repository. Gli ultimi due campi sono rispettivamente il vendortag e il releasetag e generalmente non sono significativi, per questo motivo si possono scegliere valori casuali senza preoccuparsene troppo. Bene, adesso che i sorgenti della nostra applicazione fanno parte del repository CVS possiamo incominciare lo sviluppo vero e proprio. Non volendo utilizzare la linea di comando possiamo affidarci alla comoda interfaccia grafica che ci fornisce Cervisia. Nel resto della relazione faremo riferimento alla versione 2.0 di questo software, per chi comunque fosse interessato ai parametri da passare alla linea di comando, Cervisia mette a disposizione un’ampio riquadro, nella zona inferiore della finestra, in cui viene mostrato il comando eseguito per portare a termine l’operazione richiesta.

Checkout, commit e update

Il primo passo è ovviamente quello di definire il repository che desideriamo utilizzare. I passi da seguire sono i seguenti:

  • cliccate sul menu “Repository” e in seguito sulla voce “Repository”;
  • apparirà il box denominato “Configura l’accesso ai repository”;
  • cliccate il pulsante “Aggiungi” ed inserite il valore desiderato, nel nostro caso :pserver:slackcvs:secret@192.168.1.1:/usr/local/cvsrepos/, come mostrato in Figura 2
Cvs2.png
  • quindi “OK” ed ancora “OK”.

Cervisia è in grado di gestire più repository contemporaneamente quindi, se ne abbiamo necessità, possiamo ripetere la procedura precedente il numero di volte desiderato.

Cvs3.png

Ora che il repository è stato identificato dobbiamo scaricare i file del progetto. Questo può sembrare strano visto che abbiamo gli originali ancora sul nostro disco ma, a ben guardare, quella directory non contiene informazioni riguardanti CVS. Andiamo a fare quindi il nostro primo checkout con il quale verrà creata la sandbox:

  • selezioniamo la voce “Checkout” dal menu “Repository”;
  • indichiamo il repository, il progetto (“Modulo”), la directory di destinazione e diamo l’“OK”.
Cvs4.png

Nel luogo indicato per la creazione della sandbox, CVS creerà gli stessi file e directory che abbiamo importato sul server, con l’aggiunta di un’ulteriore directory CVS in tutta la struttura11. CVS utilizza l’omonima directory per immagazzinare le informazioni di controllo delle versioni. Nel file CVS/Entries troviamo infatti le informazioni riguardanti ogni singolo file contenuto in quel livello:

slack$ cat CVS/Entries
/HelloWorld.java/1.1.1.1/Tue Feb 8 16:46:04 2005//
D/DirA////
D/DirB////

il formato di queste informazioni segue il modello /nome file/numero di revisione/data e ora// per i file (che possono tranquillamente avere numero di revisione differente l’uno dall’altro), le directory invece non hanno numeri di revisione o data e vengono indicate con la lettera “D”. La Figura 5 mostra il risultato delle nostre azioni. Nella parte alta della finestra troviamo le cartelle e i file che compongono il progetto hello_world, nella parte bassa abbiamo l’output del comando di checkout. Accanto adogni file, Cervisia mostra il suo stato (attualmente tutti i file sono in stato "Aggiornato" a causa del checkout), il numero di revisione (tutti i file partono dalla revisione 1.112) e il timestamp con l’indicazione della data.

Cvs5.png

Applichiamo qualche semplice modifica al file HelloWorld.java e DirB/Predi.java. Notiamo come lo stato dei file rimanga "Aggiornato" anche se noi sappiamo che questo non corrisponde a verità. Come mai? La risposta è semplice: dal momento del checkout CVS non ha più comunicato con il server e quindi non può fare nessuna supposizione sul reale stato del file (teniamo presente che in un contesto reale, con più programmatori impegnati nello sviluppo, il file sul server potrebbe essere cambiato dopo il nostro checkout). Per forzare CVS a darci lo stato reale dei file dobbiamo eseguire un update di controllo. Il modo più semplice per farlo è quello di selezionare l’opzione "Fai commit e update ricorsivamente" nel menu "Impostazioni" e, in seguito, "File → Stato" dopo aver selezionato la directory principale del progetto. Noteremo lo stato dei due file modificati diventare "Modificato localmente". Se non desideriamo effettuare ulteriori modifiche e giudichiamo soddisfacente il nostro lavoro siamo pronti per spedire al server la versione aggiornata del progetto. È tempo di fare un commit e, quindi, selezioniamo la directory principale e poi "File → Fai Commit". Ci verrà presentato un box in cui sono elencati i file che stiamo inviando ed un’apposito campo di testo in cui inserire il commento al commit. Effettuata l’operazione lo stato dei file tornerà ad "Aggiornato" e verrà incrementato di uno il valore della revisione. HelloWorld.java e DirB/Predi.java adesso saranno in revisione 1.2, tutti gli altri ancora fermi a 1.1. La Figura 6 mostra la situazione dopo un’ulteriore modifica a Hello-World.java seguita da un update. Un nuovo commit porterà Hello-World.java alla revisione 1.3 e così via.

Cvs6.png

Aggiungere e rimuovere file o directory

Checkout, update e commit sono i tre comandi base per lavorare con CVS. Spesso però capita di dover aggiungere o rimuovere file o directory dal progetto; per questi compiti abbiamo bisogno dei comandi add e remove. Aggiungere o rimuovere un file è un processo che si sviluppa in due passi:

  1. prima bisogna aggiungere il file alla working copy utilizzando il comando add o remove (in Cervisia bisogna selezionare il file interessato e "File → Aggiungi al Repository" oppure "File → Rimuovi dal

Repository");

  1. in seguito è necessario eseguire un commit per inviare le modifiche al server.

L’aggiunta di una directory invece si esegue in un solo passo (add), con le stesse modalità viste per i file, senza però la necessità del commit. Per la rimozione si consiglia di eliminare prima tutti i file contenuti nella directory ed in seguito di utilizzare il comando di update con il flag -P attivo.

Ma c’è di più

Nel nostro esempio siamo gli unici sviluppatori a poter effettuare delle modifiche al repository, in una situazione reale invece ci saranno un certo numero di programmatori che, come noi, andranno a modificare alcune parti del progetto. Per tenere traccia di tutte queste modifiche e sincronizzare la nostra working copy con il repository, si utilizza ancora una volta il comando update. In Cervisia si trova nel menu “File” e si chiama ovviamente "Aggiorna". Nell’eventualità che altri programmatori abbiano modificato alcuni file esattamente negli stessi punti in cui lo abbiamo fatto noi, CVS ci segnala il conflitto e si rifiuta di portare a termine il commit o l’update per quei particolari file. Nel seguente esempio è stato creato volutamente un conflitto per evidenziare come CVS lo segnali all’interno del codice:

public class HelloWorld {
public static void main(String[] args) {
System.out.println("Ciao!!!");
<<<<<<< HelloWorld.java
System.out.println("Bonjour!);
=======
System.out.println("Mandi!");
>>>>>>> 1.8
}
}

in questo caso il codice contenuto tra "<<<<<<< HelloWorld.java" e "=======" è quello che abbiamo inserito noi e crea un conflitto con la linea "System.out.println(Mandi!);" presente nella revisione 1.8 del file contenuta nel server. La soluzione dei conflitti è lasciata ai programmatori coinvolti. Spesso è utile conoscere l’altro autore della porzione di codice che crea il conflitto, per fare ciò è sufficente andare a leggere i logs utilizzando il comando "Visualizza → Sfoglia log". Adesso siamo a conoscenza delle interazioni fondamentali con un server CVS, nel caso sorgano esigenze più specifiche si rimanda ai manuali in bibliografia.

Lo sviluppo di software

Adesso che padroneggiamo le basi dello sviluppo di un progetto software con CVS è necessario approfondire alcuni aspetti che sono rilevanti ai fini del rilascio del nostro software al mondo.

Snapshots (Data e Tags)

Immaginiamo di aver raggiunto una situazione in cui il nostro software abbia una stabilità tale da diventare una release ufficiale. Generalmente, se non si vuole concedere l’accesso al server CVS, si crea un pacchetto da distribuire e, fatto questo, lo sviluppo prosegue andando ad aggiungere nuove features. A questo punto il progetto contenuto nel repository potrebbe essere profondamente differente dall’ultimo rilascio ufficiale e non necessariamente funzionante. Nel malaugurato caso che venga scoperto un pericoloso bug nell’ultima versione ufficiale, si rende necessaria un’operazione di bugfix. Sorge però un problema e riguarda il fatto che in CVS la versione rilasciata al pubblico non corrisponde più alla versione nel repository. L’unico modo per poter lavorare sui sorgenti con cui è stato creato il pacchetto è di ricordarsi in che revisione erano tutti file al momento del rilascio, il che non è proprio agevole. CVS ci viene in soccorso fornendoci due metodi per accedere a vecchie revisioni del progetto. La prima si basa sull’utilizzo della data: molto semplicemente, si richiede a CVS il progetto esattamente come era un particolare giorno del passato:

cvs -q update -D "2005-02-13 23:59:59 GMT"

in questo modo la nostra sandbox conterrà uno snapshot del progetto nello stesso stato in cui si trovava il 13 febbraio 2005. Questa soluzione però ci costringe a ricordarci le date di, almeno, tutti i rilasci effettuati e per questo viene usata solo in casi particolari. Quello che generalmente si desidera fare è di rendere disponibile un progetto nello stato in cui si trovava al tempo di uno specifico evento (un rilascio pubblico, una versione stabile, . . . ). Per rendere possibile questa astrazione dalla data si utilizza la tecnica del tagging. Un tag è un’etichetta aggiunta a tutti i file sulla base della working copy di uno sviluppatore:

cvs -q tag Rilascio_2005-02-13

Bisogna notare come ciò non significhi aggiungere un tag a tutti i file con uguale numero di revisione, bensì marcare i file con il più alto numero di revisione disponibile nella working copy associandoli allo stesso tag (la Figura 7 mostra questa situazione). Il tag è applicato immediatamente sia nella working copy che nel repository, non c’è quindi la necessità di effettuare un commit poichè i file coinvolti non vengono modificati ma soltatno le informazioni contenute nei logs. Se nella working copy dello sviluppatore sono presenti delle modifiche ai file, rispetto al repository, queste non verranno prese in considerazione da cvs e il tag interesserà il numero di revisione più alto per quel file al momento presente nel repository. Per questo motivo si tende a sincronizzare la sandbox con il repository prima di applicare un tag.

Cvs7.png

Per ottenere uno snapshot basato sui tag è sufficiente passare il suo nome a CVS come fosse un numero di revisione:

cvs checkout -r Rilascio_2005-02-13

con questo comando otterremo il checkout dei file associati al tag "Rilascio_2005-02-13", da notare che questo risultato lo si avrà anche anche a distanza di molte modifiche al repository. Sia che si utilizzi il metodo basato sulla data che quello basato sui tag, CVS non ci permette di effettuare commit di versioni modificate del progetto a partire da uno snapshot. Questo avviene perchè i file sono stati già modificati una volta nel passato e quelle modifiche non possono essere sovrascritte a meno di andare incontro ad un’inconsistenza della history del repository. Nella prossima sezione verrà presentato il modo utilizzato da CVS per aggirare questo limite e permetterci di sistemare il bug nella nostra applicazione.

Branches e sviluppo ad albero

Un progetto/modulo in CVS e’ paragonabile ad un albero. La versione iniziale del modulo e’ definita HEAD e forma il tronco (trunk) dell’albero. Proprio come gli alberi anche un modulo CVS puo’ avere dei rami (branches). Il modulo puo’ essere spezzato in piu’ rami, il cui sviluppo puo’ continuare senza intaccare l’HEAD del modulo. Un modulo può avere più di un ramo che poggia sull’HEAD ed è possibile far nascere rami nuovi da quelli gia’ esistenti. Il processo appena descritto prende il nome di Braching e consiste nel duplicare la linea di sviluppo in due rami separati. Una modifica effettuata ad un ramo non influenzerà l’altro. Riprendiamo il nostro esempio. L’ultimo rilascio è stato associato al tag "Rilascio_2005-02-13" e quindi effettuiamo un checkout basato su quel tag per ottenere i sorgenti del progetto su cui lavorare. Affinchè CVS ci permetta di apportare le modifiche necessarie creiamo un branch con il comando tag -b:

cvs -q tag -b Rilascio_2005-02-13-bugfix-branch

a questo punto è possibile apportare tutte le modifiche necassarie a risolvere il bug ed effettuare il commit che ci permette di tenere traccia del nostro lavoro. Il commit creerà una versione parallela del progetto basata sui sorgenti associati al tag utilizzato (Figura 8). Da questa versione parallela possiamo ricavare una patch da distribuire priva del bug. Nel caso ci rendessimo conto che anche la versione attualmente in sviluppo è soggetta allo stesso bug, CVS ci permette di utilizzare il lavoro fatto sul branch per risolvere la questione. È possibile infatti eseguire un merge dal branch al trunk:

Cvs8.png
cvs -q update -j Rilascio_2005-02-13-bugfix-branch

attraverso il quale le modifiche effettuate sul branch vengono incorporate nel codice sorgente della revisione attualmente in sviluppo, ovviamente nel caso in cui non si verifichino conflitti.

Riferimenti bibliografici

[BF] M. Bar, K. Fogel: Open Source Development with CVS, Paraglyph Press, 2003 (http://cvsbook.red-bean.com/)

[C] P. Cederqvist et al: Version Management with CVS (for CVS 1.11.18), Free Software Foundation, 2004 (https://www.cvshome.org/docs/manual/)

[V] V. Venugopalan: CVS Best Practice, 2002 (http://www.magiccauldron.com /cm/cvs-bestpractices/)

[W] C. L. Woelz: Learning CVS Using KDE’s Cervisia, 2004 (http://osnews.com/story.php?news_id=6096&page=1)

Arjuna Del Toso

Strumenti personali
Namespace

Varianti