Guida rapida a subversion

Autore: Matteo Lucarelli
ultima versione su: matteolucarelli.altervista.org
Breve guida all'uso di subversion

Subversion (abbreviato svn) è un sistema di controllo del versionamento. Si utilizza principalmente sul codice sorgente, ma può funzionare con qualsiasi tipo di file.

L'esistenza di un rapporto server client è necessaria al meccanismo di versionamento, che funziona essenzialmente controllando lo scambio tra i file sul server (repository) e quelli sul client (copia di lavoro). I file versionati non sono direttamente accessibili neanche dal server, infatti nelle cartelle dei repository si trovano in forma di database. Per accedervi è necessario creare un copia di lavoro locale. Naturalmente server e client possono anche risiedere sulla stessa macchina. In tal caso l'unica differenza consisterà nell'uso dell'indirizzo 127.0.0.1 (loopback) per riferirsi al server.

L'indice di versione è globale del repository ma ovviamente il sistema tiene traccia delle modifiche di ogni file. Nell'organizzazione di un server svn si tenderà quindi a creare più repository, ognuno contenente un raggruppamento logico o funzionale di file (a esempio un repository per ogni progetto o gruppo di progetti affini).

Qualsiasi operazione illustrata nel seguito ammette l'uso del flag (fondamentale)

-r NUM
-r NUM1:NUM2
che specifica la revisione, o l'intervallo di revisioni, a cui riferire l'operazione richiesta. In assenza di specifica si intende sempre l'ultima versione, cioè la più recente.

inoltre alcune revisioni salienti sono identificate anche da etichette:

Tutti i comandi sono dotati di help in linea:

svn help merge     : stampa l'help del sottocomando merge
svnadmin help      : stampa l'help generale di svnadmin

Risulta chiaro che avendo a disposizione un sistema di controllo delle versioni converrà effettuare un upload dei sorgenti sul server ogni volta che sia implementata una caratteristica completa, in modo da poter etichettare in modo chiaro ogni versione salvata. Non è necessario preoccuparsi dell'eventuale occupazione di disco conseguente ad un elevato numero di versioni, perchè il sistema limita l'effettiva scrittura fisica allo stretto necessario, quindi in generale non viene salvata una intera copia dei sorgenti ma solo le differenze con la versione precedente.

INSTALLAZIONE

Utilizzando la modalità tunnel con ssh (che non è l'unica possibile) l'installazione e l'avvio sono quanto di più semplice:

L'autenticazione sarà compito di ssh, che chiederà una password di sistema ad ogni accesso al server. L'inserimento della password ad ogni richiesta può risultare un po' noiso, ma tutto sommato è una buona norma di sicurezza e permette di distinguere chiaramente quando un'operazione viene effettuata sul server piuttosto che in locale.

NOTA: utilizzando il tunnel ssh il servizio svn non deve essere avviato, perchè sarà il servizio ssh ad restare in ascolto delle connessioni. Eventuali script (/etc/rc o /etc/init) installati dal sistema andranno quindi rimossi.

L'umask di default, usando il tunnel ssh, viene settata a 002, quindi i file creati saranno leggibili a tutti ma modificabili solo dall'utente proprietario. Per modificare questo comportamento spostare il vero svnserve

mv /usr/bin/svnserve /usr/bin/svnserve-real
e creare uno script in sostituzione con il seguente contenuto
#!/bin/sh

umask 002
/usr/bin/svnserve-real "$@"
che va reso eseguibile
chmod 755 /usr/bin/svnserve

Scelte di installazione

Nel seguito del testo si assumono:

Oltre ad svnserve (incluso nel pacchetto) è possibile integrare il modulo con apache, utilizzando quindi il protocollo http. L'uso di svnserve in accoppiata con ssh ha il vantaggio di permettere l'autenticazione tramite gli account di sistema, quindi non è necessario inserire password e utenti. Nella maggior parte delle distribuzioni Linux inotre questa modalità non richiede alcuna installazione aggiuntiva.

Dove necessario si assume per i repository il seguente layout:

/
|--trunk/
|  |--dir/
|  |  \...
|  \...
|--tags/
|  |--dir/
|  |  \...
|  \...
\--branches/
   |--dir/
   |  \...
   \...
con le directory trunk, tags e branches posizionate nella root del repository e contenenti la medesima struttura, non necessariamente completa. La struttura utilizzata è arbitraria e rispecchia le necessità del codice e dei progetti custoditi. Il codice principale è contenuto nella directory trunk, mentre tags e branches contengono rispettivamente delle versioni che si vogliono conservare, ad esempio delle release, e dei fork cioè dei rami di sviluppo differenziati. Per tale motivo non sono necessariamente complete, visto che per un certo progetto potrebbe non esistere alcun fork nell sviluppo.

USO

L'uso si intende effettuato da una macchina remota in rete con il server. L'URL del repository avrà quindi la forma:

svn+ssh://x.x.x.x/path/assoluto/sul/server
dove x.x.x.x è ovviamente l'indirizzo del server.

Se invece è necessario specificare l'utente:

svn+ssh://utente@x.x.x.x/path/assoluto/sul/server

In generale per le operazioni locali è possibile usare sia path relativi che assoluti. Dove non si specifichi il path si intende di default la cartella corrente, quindi la maggior parte delle operazioni di lavoro andranno effettuate dall'interno della propria copia di lavoro.

In generale il lavoro tramite svn prevede i seguenti passi:

Importazione

Per listare la struttura del repository si utilizza il comando:

svn list --verbose -R svn+ssh://x.x.x.x/var/svn/repository

Per creare una copia di lavoro di una parte di repository:

svn co svn+ssh://x.x.x.x/var/svn/repository/trunk/path/to/project/ PROJECT
l'operazione crea nella directory corrente una directory PROJECT contenente i file estratti dalla cartella "path/project/trunk" del repository.

Da questo momento in poi non sarà più necessario specificare l'URL di origine dei dati, visto che ovviamente il sistema ne tiene traccia.

Per creare una copia di lavoro di un intero repository:

svn co svn+ssh://x.x.x.x/var/svn/repository
l'operazione crea nella directory corrente una directory nominata come il repository contenente una copia completa.

L'operazione di checkout va effettuata solo alla prima creazione della copia di lavoro. Successivamente per sincronizzare la copia locale con quella del repository (si noti che non è più necessario specificare l'URL):

cd /path/della/copia/di/lavoro/
svn update
l'output di update elenca i file convolti nell'aggiornamento. Ognuno dei file elencati è etichettato con una lettera: I casi G e C segnalano la necessità di un controllo manuale (si veda la sezione Risoluzione dei conflitti).

Editing

I file della propria copia di lavoro possono essere modificati liberamente. le operazioni di filesystem vanno invece segnalate al sistema svn.

Per aggiungere un file o una directory già esistenti usare il comando:

svn add file_or_dir
se la directory aggiunta contiene dei file questi verranno automaticamente aggiunti a loro volta, per modificare questo comportamento usare il flag -N. Si noti che in assenza di specifica i file aggiunti durante il normale lavoro non verranno uploadati sul server. Questa comportamento permette di non doversi preoccupare di eventuali file temporanei (file oggetto, dati di prova, ecc.)

Per creare una nuova directory:

svn mkdir directory

Per cancellare un file usare il comando:

svn delete file

Per rinominare o copiare un file:

svn move oldfile newfile
svn copy file newfile

Tutte le operazioni illustrate possono accettare anche un URL come argomento. In tal caso l'operazione viene effettuata direttamente sul repository.

Analisi ed esportazione delle modifiche

Per esportare i cambiamenti sul server si utilizza, dall'interno della copia di lavoro uno dei due comandi:

svn commit -m "Commento"
svn commit -F file_di_commento
L'uso del commento in linea (-m) oppure di un file di commento (-F) è obbligatorio. In caso contrario verrà avviato automaticamente un editor per inserire il commento. La scelta dell'editor è modificabile nel file ~/.subversion/config

E' possibile esportare anche singoli file:

svn commit path/relativo/al/file

Nel caso in cui i sorgenti sul server siano stati modificati dall'ultima importazione si viene a creare un conflitto al momento dell'applicazione delle modifiche al repository. Svn avverte della situazione ed il commit fallisce. E' quindi necessario provvedere ad una analisi manuale (si veda la sezione Risoluzione dei conflitti).

Prima di effetture una commit è comunque buona abitudine dare un'occhiata ai cambiamenti effettuati, anche solo per ideare un significativo messaggio di commento. Per interrogare sui cambiamenti effettuati localmente rispetto all'ultima update (si noti che il risultato è indipendente dall'attuale contenuto del repository in rete):

svn status -v
L'output del comando status comincia sempre con una lettera maiuscola che identifica la situazione del file elencato, i più comuni sono:

Per confrontare la versione locale con quella sul server si usa il comando:

svn status -vu
In particolare l'output di quest'ultimo comando segnala tramite un asterisco i file che sono stati aggiornati sul server:
M      *        44        23    sally     README
M               44        20    harry     main.c
       *        44        35    harry     utils.c
In questo caso è evidente che il commit genererà un conflitto sul file README, che è stato modificato localmente (segnale M) pur essendone disponibile una versione aggiornata nel repository (asterisco).

Per avere un output dettagliato è disponibile il comando diff:

svn diff                 : visualizzale modifiche locali dall'ultimo update
svn diff file.txt        : visualizza le modifiche a file.txt dall'ultimo update
svn diff -r 5:BASE       : mostra le differenze tra la copia di lavoro e la rev 5 sul server
svn diff -r 5:6          : mostra le modifiche effettuate tra le revisioni 5 e 6 sul server
svn diff URL@R1 URL@R2   : mostra le modifiche tra i due URL nelle revisioni R1 ed R2
L'output è quello standard per il comando diff, cioè riporta solo le differenze, marcando le linee eliminate con il carattere '-' e quelle aggiunte con il carattere '+'. L'output di diff è modificabile utlizzando i flag del comando standard (man diff). Ad esempio se si vuole un output a colonne parallele (molto più leggibile):
svn diff --diff-cmd /usr/bin/diff -x -y

Il comando merge ha una sintassi analoga al comando diff, ma mentre il primo visualizza le differenze, il secondo le applica alla copia di lavoro. Quindi:

svn merge -r A:B http://x.x.x.x/repository/path
applica le differenze tra le revisioni A e B del repository indicato alla copia di lavoro attuale. Questo comando è utile per annullare modifiche precedenti- Ad esempio se A è maggiore di B verranno rimosse dalla copia di lavoro le modifiche effettuate tra la revisione B e la A.

Per visualizzare la storia delle modifiche di un file, o di un intero repository si utilizza il comando log:

svn log             : mostra il log sintetico
svn log -v          : mostra il log completo
svn log file        : mostra il log relativo ad un file
svn log -r a:b      : mostra il log limitato all'intervallo di revisioni a-b
Il comando log agisce sempre sul repository remoto. Quando il path specificato è locale mostra la storia del file nel repository originario. Se non si specificano versioni si intende da 1 a BASE della copia locale.

Risoluzione dei conflitti

Visto che il sistema di versionamento non può entrare nel merito del contenuto dei file esistono casi che richiedono un intervento manuale. In particolare ciò avviene quando una modifica locale si sovrappone a modifiche sul server effettuate successivamente alla nostra ultima update.

Il caso più semplice viene risolto eliminando i cambiamenti locali, cioè riportando la situazione all'ultimo update tramite il comando:

svn revert dir_o_file

Negli altri casi si procederà come segue.

  1. Aggiornare i sorgenti
    svn update
    
    nell'output del comando update il conflitto è segnalato con una C. Subversion provvede quindi a creare tre versioni del file in conflitto:
    FILE.mine   : versione presente nella copia di lavoro prima dell'update
    FILE.rOLD   : versione precedente alle modifiche della copia di lavoro
    FILE.rNEW   : versione attualmente presente sul server
    
    oltre a inserire nella copia originale dei markers:
    <<<<<< .mine
    // linee presenti nella versione in conflitto
    =======
    // linee presenti nella versione sul server
    >>>>>> .r2
    
    Disponendo dei tre file è quindi possibile analizzare i cambiamenti che hanno dato luogo al conflitto.
  2. Dopo avero corretto il problema e modificato il file originale impartire il comando:
    svn resolved FILE
    
    che provvede a rimuovere i file temporanei e ad informare subversion della risoluzione del problema.
  3. A questo punto si può effettuare una nuova commit.

AMMINSTRAZIONE

I comandi svnadmin e svnlook vengono utilizzati sul server, quindi non attraverso la rete. I path utilizzati sono quindi percorsi locali e possono essere sia assoluti che relativi.

Creazione ed eliminazione di un repository

Per creare un repository:

svnadmin create /var/svn/projectname

Per importare un progetto creare in una cartella temporanea la struttura base del repository:

mkdir /tmp/projectname
mkdir /tmp/projectname/branches
mkdir /tmp/projectname/tags
mkdir /tmp/projectname/trunk
quindi copiare tutti i file (e l'eventuale struttura di directory) nella cartella /tmp/projectname/trunk/.
A questo punto impartire il comando di importazione:
svn import /tmp/projectname file:///var/svn/projectname -m "Versione Iniziale"
NOTE:

Per eliminare un repository è sufficiente cancellare la sua directory:

rm -rf /mnt/svn/projectname

Backup

Il backup può essere fatto in diversi modi:

gli ultimi due sistemi permettono di salvare anche tutte le informazioni di revisione.

Per effettuare un dump, ovvero un file di testo contenente tutte le informazioni:

svnadmin dump /path/del/repository > dump-file
E' naturalmente possibile fare il dump di una revisione o di un intervallo di revisioni:
svnadmin dump /path/del/repository --revision N > dump-file
svnadmin dump /path/del/repository --revision N1:N2> dump-file
Il dump potrà successivamente essere caricato in un repository con il comando:
cat dump-file > svnadmin load /path/del/repository
Le due operazioni possono anche essere messe in pipe:
svnadmin dump repository1 | svnadmin load repository2

Per modificare i dump esiste inoltre un comando specifico, svndumpfilter, utlizzabile ad esempio per isolare un singolo progetto:

cat dump-file | svndumpfilter include project > dump-file-parziale

Per effettuare una copia del repository si possono semplicemente copiare i file. In modo più sicuro, su un repository in uso, si può usare il comando:

svnadmin hotcopy /path/del/repository /path/del/backup

Branch e Tag

La creazione di branch e tag consiste essenzialmente nella duplicazione delle informazioni del repository in una nuova destinazione. I branch vengono utilizzati per il mantenimento di versioni parallele, ad esempio dei fork del codice principale, mentre i tag per conservare delle istantanee di particolari versioni, ed esempio delle release. L'unica differenza tra le due operazioni consiste quindi nel fatto che un tag si suppone congelato al momento della sua creazione, mentre un brach continuerà ad essere sviluppato, e quindi versionato.

L'operazione di creazione di un branch o di un tag può essere effettuata in remoto tramite un singolo comando che effettua un commit immediato della modifica:

svn copy svn+ssh://x.x.x.x/var/svn/repository/trunk/percorso/nome_progetto/ \
         svn+ssh://x.x.x.x/var/svn/repository/branches_o_tags/percorso/nome_branch_o_tag/ \
         -m "Creazione del nuovo branch o tag nome_branch_o_tag del progetto nome_progetto"

Dopo la creazione un brach o un tag continuerà a condividere il numero di versione (che è globale del repository), ma le storie delle variazioni saranno separate (facendo il log di uno specifico ramo si visualizzano solo le revisioni che lo hanno modificato).

Esistono diversi modi per evitare che un tag venga modificato dopo la sua creazione, in ogni caso ciò non è normalmente necessario, visto che in ogni momento le modifiche possono essere annullate.

Per applicare delle variazioni effettuate su un altro ramo di sviluppo è si utilizza il comando merge.

matteolucarelli.altervista.org
©opyright info