Software-Entwicklung ohne Versionsmanagement ist eine organisatorische Qual. Entwickler müssten sich Sourcen hin- und hermailen, selbst dafür sorgen, dass immer die richtigen Änderungen eingefügt werden und wenn dann drei Entwickler das gleiche Projekt bearbeiten, ist das Chaos vorprogrammiert. Für Ordnung im Chaos sorgt ein Versionsmanagement: subversion ist die aktuelle Fortentwicklung der Klassiker.
Ein Vorfahre von Versionsmanagement-Programmen ist RCS - das Revision Control System. Auf dieser Basis entwickelte sich CVS - das Concurrent Versioning System mit vielen Verbesserungen, um Entwicklern die Arbeit zu erleichtern. CVS ist von Anwendern sehr einfach zu bedienen; selbst ein Einsteiger versteht binnen Minuten, was cvs update und cvs commit bewirkt - um den Rest kümmert sich die Software selbst. Der Erfolg - aber vor allen Dingen die Grenzen von CVS - hat zur Implementation von subversion geführt. Subversion wird mit seiner Fertigstellung verschiedene Schönheitsfehler von CVS beheben: Es soll Binaries ordentlich verwalten, Dateien, Verzeichnisse und symbolische Links werden der Versionskontrolle unterliegen. Von vielen Entwicklern benötigt, sollen wichtige Aktionen wie move bei Fertigstellung funktionieren. Ganz fertig gestellt ist subversion noch nicht - viele Features befinden sich noch in der Implementation. Trotzdem funktioniert subversion heute gut genug, um ein paar neugierige Blicke darauf zu werfen.
Installation
Die Installation von subversion ist nicht schwierig: Für den Single-User Modus braucht man nur subversion, Berkeley-DB 4.x, den XML-Parser Expat und ein installiertes Python 2.x. und kann die Netzwerkkomponenten einfach weglassen. Für ein netzwerktaugliches subversion braucht man ein paar Komponenten mehr: Die Sourcen von Apache 2, die Neon-Library für WebDAV und die OpenSSL-Bibliotheken, um eine verschlüsselte Übertragung zu gewährleisten. Apache 2 übernimmt mittels HTTP 1.1 die Arbeit des Transports der Daten übers Netz. WebDAV erledigt später bestimmte Zugriffe auf das Repository. subversion, WebDAV und OpenSSL lädt der Apache automatisch. Sowohl für den Netzwerkbetrieb als auch lokal benötigt man Berkeley-DB als Backend zur Aufbewahrung der verwalteten Daten. Durch die Delegierung der Netzwerkfähigkeit an Apache fallen bei subversion Arbeitsweisen wie der
pserver unter CVS weg. Das Anmelden am subversion-Server funktioniert über htaccess-Passworte und andere Mechanismen, die der Apache beherrscht. Für den Administrator bedeutet dies natürlich, dass er sich mit grundlegenden Verwaltungsarbeiten am Apache vertraut machen muss. Wer sich mit Apache und WebDAV gar nicht anfreunden kann, erhält in den Sourcen von subversion übrigens auch einen kleinen subversion-Server
svnserve, der als Dämon läuft.
Die Installation für den lokalen Modus ohne Netz - gut geeignet für erste Tests - erfordert zuerst die Installation von Berkeley-DB und Expat. Beide sind voneinander unabhängig und lassen sich leicht mit
configure, make, make install installieren. Wer kein Python 2.x hat, braucht dies auch nur für den Buildvorgang - man muss also nicht erst das neue Python gegen Expat und Berkeley-DB linken. Nach dem Auspacken der Sourcen von subversion ruft man
./configure --with-berkeley-db=/pfad/zu/db4 auf.
Danach folgt das übliche
make und
make install - wer will, kann noch ein
make check für ein paar Tests durchlaufen lassen. In einigen Tutorials werden subversion, Berkeley-DB und der neue Apache mit Prefixen versehen, die die Binaries von Apache und subversion später in einem Verzeichnis (z.B.
/usr/local/subversion/) vorhalten. Notwendig ist das nicht - wer den Apache 2 oder Berkeley-DB sowieso installiert hat, muss subversions
configure die korrekten Prefixes seines Systems mitteilen. Viele Distributionen haben eine ältere Berkeley-DB vorinstalliert - kompiliert man die falsche Version ein, meldet subversion später einen Fehler wie
svnadmin create SVN
svn: General filesystem error svn: bad database version: got 3.1.17, should be at least 4.0.14
Ein subversion im Netz benötigt Apache 2 mit WebDAV-Modul, OpenSSL mit der Neon-Bibliothek und natürlich auch Berkeley-DB, Expat und die Sourcen von subversion. Wenn Berkeley-DB schon für den clientseitigen Betrieb installiert ist, kompiliert man als nächstes die Neon-Bibliothek für WebDAV. Neon installiert man nach Expat, weil Neon Expat oder libxml als XML-Parser erwartet. Hier genügt ein
configure, make, make install. Danach folgt der Apache mit einer längeren
configure-Option:
./configure --enable-dav \ --enable-so \ --with-dbm=db4 \ --with-berkeley-db=/pfad/zu/berkeleydb4
Zum Schluss kompiliert man subversion; diesmal mit den passenden Flags für den Apache-gestützten Netzwerkbetrieb:
./configure --with-berkeley-db=/pfad/zu/db4 \ --with-apxs=/apachepfad/bin/apxs
Für OpenSSL-Support ruft man bei Neon, Apache und subversion den Schalter
--with-ssl bzw.
--enable-ssl auf. Danach muss der Apache für subversion konfiguriert werden, indem man in der
http.conf das Verzeichnis für das Repository einträgt:
<Location /SVN>
DAV svn
SVNPath /var/SVN
</Location>
Diese Direktive teilt Apache mit, dass Anfragen mit dem Pfad SVN vom DAV-Handler
svn bearbeitet werden und auf dem physikalischen Verzeichnis
/var/SVN arbeiten. Man ruft später nicht den ganzen Pfad zum Repository auf, sondern bloß
http://subversionserver.de/SVN/ - der Apache versteht durch diese Direktive, dass SVN auf
/var/SVN/ umgesetzt wird. Die Rechte für den Apache-Zugriff nicht vergessen!

Abb. 1: Im Logfile von Apache 2 sieht man, was WebDAV wirklich tut.
Svnserve als Alternative zum Apache wird einfach mit
svnserver -d gestartet. Der Server nimmt dann Requests mit
svn://localhost/repository/project an und kann vom Benutzer in
~/.subversion/servers außerdem noch für ssh-Zugriff konfiguriert werden.
Trunk, Branch, Tag - Grundbegriffe in subversion
Die Grundbegriffe von subversion kennen die meisten Benutzer bereits aus der CVS-Welt: Das Repository ist die komplette Datenstruktur, die in CVS als Dateien und Verzeichnisse auf der Festplatte gehalten wird. In subversion erledigt dies Berkeley-DB. Ein Projekt ist eine Unterstruktur innerhalb eines Repositorys - ganz banal das entsprechende (versionierte!) Verzeichnis. Verzeichnisse mit besonderen Eigenschaften (Properties - dazu später mehr) sind Module: Zu einem Modul kann man mehrere Unterverzeichnisse aus mehreren Repositories zusammenfassen. Das Versioning vollzieht sich immer bezogen auf ein Repository - deswegen kann es bei vielen Projekten sinnvoll sein, auch mehrere Repositorys anzulegen. Als Trunk bezeichnet man den Hauptbaum eines Projekts und als Branch einen Nebenzweig. Ein Branch ist bei subversion eine Kopie des Trunks. Es handelt sich dabei nicht um eine echte, verdoppelnde Kopie, sondern um eine Art Hardlink: Trunk und Branch sind nur einmal in der Berkley-DB vorhanden, werden aber ab der Abzweigung (seit dem Branch) getrennt bearbeitet und verwaltet. Natürlich kann ein Branch (oder mehrere) wieder zurück in einen Trunk migriert werden: Mittels eines Merges fügt subversion Änderungen verschiedener Branches über einen bestimmten Revisionsraum zusammen. Ein Revisionsraum kann eine Angabe wie von Revision 352 - Revision 763 oder die Änderungen seit April 2002 sein - subversion akzeptiert genau wie CVS bei vielen Befehlen sehr flexible Datums- und Versionsangaben. Ist man mit den Änderungen und Migrationen zufrieden und hat eine lauffähige Version, kann man einen Tag setzen: Damit wird ein bestimmter Zustand eines Projekts markiert. Der Tag ist im Grunde nur das Erzeugen eines Branches, mit dem man unterschiedliche Revisionen von Dateien und Verzeichnissen als zu einem Tag gehörig deklariert: Man kann damit wie über ein Alias arbeiten, z.B.
release-0.7-stable auschecken oder als Archiv packen.
Erste Schritte: subversion als Anwender
Wenn alles installiert ist, experimentiert man am Besten lokal mit dem ersten Archiv: Mit
svnadmin create SVN ist das erste Repository erstellt. Wirft man einen Blick hinein, finden sich ein paar ungewohnte Unterverzeichnisse:
README conf/ dav/ db/ format hooks/ locks/ - in
/db findet sich in Form von Berkeley-DB Dateien das Repository. In diesen Verzeichnissen editiert normalerweise nur der Administrator des Repositorys; der Anwender hat - genau wie bei CVS - nach dem Auschecken eines Projekts oder Moduls sein eigenes
.svn/ in jedem Verzeichnis der lokalen Arbeitskopie. Subversions Befehlssyntax ist allgemein
svn command options target
Alle möglichen Kommandos zeigt
svn --help an; alle möglichen Optionen für ein Kommando sieht man mit
svn help command. Mit
svn import file:////home/user/SVN /home/user/TheProject MyProject
holt man sich das unverwaltete
TheProject als Quelle ins Repository unter dem Zielnamen
MyProject. Die Syntax von
svn ist immer URI- bzw. URL-basiert: Um ein lokales Projekt in einen entfernten subversion-Server zu importieren, gibt man einfach
svn import http://subversionserver.de/SVN/ /home/user/TheProject MyProject an.
Subversion legt dann auf dem Server im Repository das neue Projekt
MyProject an und importiert alles aus
/home/user/TheProject/ dorthin.
Jetzt arbeitet man wie unter CVS gewohnt. Mit
svn checkout file:///home/user/SVN/MyProject MyCopy
checkt man sich lokal ein Projekt (oder Modul) als Arbeitskopie ins Verzeichnis
MyCopy aus; mit
svn checkout http://subversionserver.de/SVN/MyProject MyCopy
holt man das gleiche von einem entfernten Server. Dank WebDAV ist via HTTP keine absolute Pfadangabe nötig. Während man mit
svn arbeitet, fällt die Vertrautheit mit den üblichen CVS-Befehlen angenehm auf:
svn update aktualisiert die lokale Arbeitskopie und mit
svn commit checkt man eigene Änderungen ins Repository ein.

Abb. 2: Dank der Zusammenarbeit mit Apache gibt es ein kleines Web-SVN gleich dazu.
Erst vergewissern - dann ändern
Bevor man Änderungen einpflegt, zeigen
svn status und
svn diff Änderungswünsche an, ohne sie durchzuführen.
svn diff,
svn status und
svn revert können dank des Caching-Systems von subversion auch ohne Netzwerkverbindung arbeiten: Die betreffenden Änderungen werden in den Metadaten in
~/.svn vorgehalten, bevor alles an den Server beim
svn commit gesendet wird. Diese Metadaten sind XML-Files, in denen die Eigenschaften, Dateilisten, Namen, Autor, Checksumme, Timestamps und vieles mehr festgehalten werden. Wer neugierig ist, kann die Metadaten in
~/.svn im Klartext angucken.
Svn status zeigt an, welche Änderungen der Datei anstehen: ein
--verbose (
-v) ergänzt die Revisionsnummer, wer die Änderungen gemacht hat und in welcher Revision die letzte Änderung stattfand. Kombiniert man
--verbose noch mit
--show-updates (
-u) markiert subversion die Dateien, die beim Update bearbeitet werden. Für
-u braucht man wieder eine Verbindung zum Repository:
-u vergleicht die Arbeitskopie mit der Repository-Version der Dateien. Ein typischer Output sieht dann wie folgt aus:
4 4 banshee .
M * 6 6 banshee Grammatik
M 8 8 banshee Lyrik
M 4 2 someone adjektiv.txt
Head revision: 9
A(dded),
D(elete),
M(odified), (Mer)
G(ed),
U(pdate),
C(onflict) zeigen in den ersten beiden Spalten den Status der Datei und der Eigenschaften separat an. Das * erscheint, wenn im Repository neuere Dateien liegen als in der Arbeitskopie. Die Revisionen der Arbeitskopie und der Commits werden aufgelistet als Ziffern, dann folgt der Name desjenigen, von dem der letzte Commit stammte.
Natürlich gibt es auch
svn diff - um sich die Unterschiede zwischen lokaler Kopie und der entsprechenden Datei im Repository anzeigen zu lassen oder um Patch-Files zu erstellen. Ein einfaches
svn diff > mypatch genügt, um einen Patch zu erstellen. Subversions
diff arbeitet bereits mit unified
diff: Durch die Angabe von Zeilennummern, - und + versteht
patch, welche Zeilen gelöscht und welche hinzugefügt werden sollen. Stellt man beim Blick in den Status oder ins Diff fest, dass man Fehler gemacht hat, hilft
svn revert weiter: Damit werden Änderungen der lokalen Arbeitskopie wieder zurückgenommen.
Mit verschiedenen Parametern kann
svn noch filigraner Nachrichten anzeigen oder Diffs erstellen: Die Option
-r wird von
list (Verzeichnisse unter Versionskontrolle auflisten),
cat (Datei anzeigen),
log und
diff verstanden und zeigt Mitteilungen einer bestimmten Revision:
svn log -r4 zeigt beispielweise nur die Logmessages von Revision 4 an.
svn diff -r3:4 http://subversionserver.de/SVN/source.c > mypatch
würde aus Revision 3 und 4 ein Diff erstellen und es in ein Patchfile umleiten. Der Schalter
-r versteht Angaben wie:
22:55 - Revisionsnummer 22 bis 55, oder
10:{today} - von Revision 10 bis zum Datum von heute.
HEAD kennzeichnet mit
-r2:HEAD alle Revisionen von Nummer 2 bis zur letzten aktuellen Revision. Ein
svn cat -r7 foobar.c > foobar.c
leitet den Inhalt von
foobar.c, Revision 7, in eine neue Datei um - sehr bequem, um alte Versionen zu restaurieren.
Mit Branches und Mergers arbeiten
Um in einem Projekt über mehrere Monate hinweg mit unstabilen Sourcen arbeiten zu können oder größere Projektumstellungen zu bewältigen, braucht man früher oder später einen Branch (Zweig) des Hauptprojekts. Mit subversion erledigt man das mit
svn copy http://subversionserver.de/SVN/trunks/projectA \ http://subversionserver.de/SVN/branches/projectA-branch
Ist der Branch kopiert, checkt man sich die Kopie mit
svn checkout http://subversionserver.de/SVN/branches/projectA-branch MyBranch
neu aus und arbeitet darin wie gewohnt weiter. Jetzt existieren virtuell zwei Projekte, die sich beim Bearbeiten nicht ins Gehege kommen. Interessant wird es, wenn man einen Branch wieder zurück in den Trunk, also ins Ursprungsprojekt einfügen will: Mit
svn merge kann man das bequem (wenn auch meistens nicht konfliktfrei) erledigen.
svn merge ist eine Schwester von
diff: statt ein Diff vom Branch zu erstellen und den Patch dann auf den Trunk anzuwenden, erledigt
svn merge dies in einem Rutsch.
merge versteht genau wie
diff auch den Parameter
-r, um ganz bestimmte Revisionen für einen Merger auszuwählen.
merge hat ein paar Fähigkeiten mehr als ein normaler Patch: bewegte Verzeichnisse, Namensänderungen oder kopierte Files erkennt
svn merge und fügt diese Veränderungen mit ein. In der Theorie klingt das natürlich toll - in der Realität dürften viele Konflikte zwischen Änderungen auftreten.
Files, die mit
C für
Conflicts markiert sind, müssen geordnet und bearbeitet werden, bis der Konflikt aufgelöst ist. Subversion legt dafür diverse Temp-Files mit speziellen Markierungen in der Arbeitskopie des Users an. Nach der Konfliktbehebung räumt ein
svn resolve die Markierungen der Konflikte sauber wieder weg. Liegen bereits viele Megabyte von Sourcen eines Projekts in der Arbeitskopie, kann man einen Branch davon ressourcenschonend erzeugen, indem man mit
svn switch die aktuelle Arbeitskopie zu einer Arbeitskopie des Branches macht. Subversion ändert die Arbeitskopie in den Branch um - commitet man jetzt Änderungen, landen diese im Branch des Repositorys und nicht im ursprünglichen Trunk.
Metadaten und Eigenschaften
Die oben kurz erwähnten Metadaten in
~/.svn in jeder Arbeitskopie können übrigens vom Benutzer verwendet werden und unterliegen auch der Versionskontrolle - deswegen hat
svn status zwei Spalten. Verschiedene Kommandos wie
svn propset, propedit, prodel, proplist und
propget können die Eigenschaften (Properties) bezogen auf jede einzelne Datei bearbeiten. Die Eigenschaften sind dabei frei wählbar und werden so vergeben:
svn propset Autor "Susanne Schmidt" lyrik.cgi
setzt die Eigenschaft Autor mit dem Wert
Susanne Schmidt auf die Datei
lyrik.cgi.
svn proplist und
proplist -v zeigen, welche Eigenschaften mit welchen Werten gesetzt sind. Sind die Eigenschaften bearbeitet, folgt der übliche
commit. Ein Blick in
~/.svn/props/lyrik.cgi.svn-work zeigt die Änderungen dieser Datei. Alle subversion-Eigenschaften beginnen mit
svn: -
svn:executable,
svn:eol-style,
svn:keywords oder
svn:ignore sind einige Eigenschaften, die subversion bearbeiten kann. Will man gezielt für ein Verzeichnis das Ignorieren von bestimmten Dateitypen - typischerweise Sicherheitskopien von Editoren, Objectfiles oder Logfiles von LateX - anschalten, ruft man einfach
svn propset svn:ignore "~" Verzeichnis auf. Ein
svn commit ignoriert die Dateien mit der Endung ~ jetzt - erst ein gezieltes
svn add foobar~ fügt eine ignorierte Datei dem Repository hinzu. Wer aus CVS-Zeiten noch ein
.cvsignore hat, kann dies ganz einfach als Pattern für ein
svn:ignore verwenden:
svn propset svn:ignore -F .cvsignore . setzt die Pattern aus dem File (
-F)
.cvsignore als subversion-Eigenschaft bezogen auf das aktuelle Verzeichnis.
Die oben bereits erwähnten Module erzeugt man ebenfalls mit Eigenschaften: Man weist einem Verzeichnis mit der Eigenschaft
svn:externals einfach eine Liste mit Verzeichnissen, Dateien und Repositories zu. Bei
svn checkout,
update und
commit werden die
svn:externals einfach über den Verzeichnisnamen des Moduls aufgelöst und bearbeitet.
Als Administrator eines Projekts
Die Administration von subversion unterscheidet sich natürlich grundlegend vom Gebrauch von subversion als Benutzer. Als Administrator kann man unterschiedlichste Anweisungen an subversion übergeben, die sich auf die Arbeit von Benutzern auswirken. subversion versteht Anweisungen - so genannte Hooks die vor einem Commit, beim Start eines Commits und nach einem Commit ausgeführt werden können. Das typische
post-commit-Skript ist die Benachrichtung einer Mailingliste über Änderungen einer Datei inklusive ihrer
commit-Messages. Ein klassisches
pre-commit-Skript ist beispielsweise die Kontrolle über den Einrückungsstil der Sourcen oder die Verpflichtung, keine Funktion ohne Kommentar einzuchecken und dergleichen mehr. Natürlich kann man hier auch Tools wie
indent verwenden und Einrückungen automatisch vornehmen lassen. Mit
start-commit-Hooks kann man sogar benutzerspezifische Aktionen durchführen - je nachdem, wer gerade einen Commit ausführt. Ein Hook wird in einem Template-File (
start-commit.tmpl) eingetragen, dass subversion in
/hooks des Repository erwartet; das auszuführende Skript legt man mit passenden Rechten dazu. Im Source-Paket von subversion liegen mehrere fertige Hook-Skripte griffbereit. Als Administrator sind außerdem noch Befehle wie
svnadmin dump, um ein Backup im dump-Format anzulegen oder
svnadmin lock, um einzelne Teile des Repositorys gegen Schreibzugriff zu schützen, wichtig.
Wer also subversion benutzen will, findet sich als CVS-User leicht in die Syntax ein; die Installation klappt problemlos und viele Features funktionieren bereits und der Gebrauch ist wirklich
sehr einfach. Wer allerdings eine fertige Release erwartet, wird sich doch noch einige Zeit gedulden müssen - solange sollte man das vielversprechende Projekt nicht aus den Augen verlieren!
Links