Bei Versionskontrollsystemen wie CVS und Subversion speichert ein zentraler Server alle Dateien. Fällt er aus, ist mit der Arbeit Schluss. Bazaar löst dieses Problem, indem es das Quellcode-Management über die Rechner der Entwickler verteilt.
Eine Software zur Versionsverwaltung speichert nicht nur den Quellcode selbst, sondern führt auch akribisch Buch über jede einzelne Änderung. Legt ein Programmierer eine neue so genannte Revision an, erstellt die Versionsverwaltung bei diesem Commit genannten Vorgang einen Schnappschuss seiner Arbeitskopie. Damit ist es dem Entwickler möglich, jederzeit zu einer beliebigen Revision zurückzukehren oder sich die Änderungen und die Versionsgeschichte anzuschauen.
Netzwerk- und mehrbenutzerfähige Versionsverwaltungen erlauben die Zusammenarbeit mehrerer Entwickler an unterschiedlichen Orten. Systeme wie Subversion und CVS stellen dazu ein zentrales Repository bereit. Jeder Entwickler erstellt sich eine Arbeitskopie (Checkout) und legt für jede Änderung an seiner Arbeitskopie eine neue Revision an (Commit oder Checkin), die Subversion beziehungsweise CVS von der Arbeitskopie in das zentrale Repository überträgt.
Arbeiten mehrere Entwickler parallel an der gleichen Datei, kommt es mitunter zu Konflikten. Hat der eine Entwickler bereits seine Änderungen in das Repository übertragen, meldet die Versionsverwaltung dem anderen beim Anlegen einer weiteren Revision einen Konflikt. Seine Änderungen vertragen sich nicht mit den Änderungen des Entwicklers, der schneller war.
Zentral versus verteilt
Revisionen landen bei einer zentralen Versionsverwaltung immer im zentralen Repository. Das erschwert komplexe Änderungen, die mitunter kurz- bis mittelfristig erst einmal eine gewisse Instabilität mit sich bringen. Denn solange ein Entwickler nur mit seiner Arbeitskopie arbeitet, registriert die Versionsverwaltung keine Änderungen. Am Ende bleibt ein großer Haufen an Änderungen, für die der Entwickler nur eine einzige Revision anlegt. Oder er möchte seine Änderungen sichern und legt daher mitunter eine Revision mit Änderungen am Quelltext eines Programms an, die sich nicht einmal kompilieren lassen.
Ein Weg, diesen Nachteil zu umgehen, besteht darin, einen Entwicklungszweig (Branch), also eine Kopie des aktuellen Entwicklungsstands, anzulegen, und diesen nach den Änderungen wieder mit dem Hauptzweig zusammenzuführen (Merge). Weder CVS noch Subversion greifen dem Entwickler dabei unter die Arme. Ein Merge ist daher ein zeitaufwändiger manueller Prozess. Die Informationen über die einzelnen Revisionen des Branch gehen verloren, wenn der Entwickler sie nicht einzeln mit dem Hauptzweig vereinigt.
Ein weiterer Nachteil dieses zentralisierten Vorgehens lässt sich auch mit Branching nicht umgehen: Das Anlegen von Revisionen funktioniert nur dann, wenn eine Verbindung zwischen Client und Server besteht. Ist der Entwickler mit dem Laptop unterwegs und ohne Internetzugang oder ist schlimmer noch der Server ausgefallen, hat er keine Möglichkeit, um Änderungen als Revisionen aufzuzeichnen.
Dagegen arbeitet bei einer verteilten Versionsverwaltung wie Bazaar, Git [1], Monotone, Arch [2] oder SVK [3], das auf Subversion aufsetzt, jeder Entwickler von vornherein mit einem eigenen Entwicklungszweig. Revisionen landen zunächst immer im Branch des Entwicklers, der ein Repository zum Aufzeichnen von Revisionen enthält. Jeder Commit ist daher konfliktfrei.
Erst wenn der Entwickler mit seinen Änderungen zufrieden ist, führt er sie mit Änderungen anderer Entwickler zusammen (Merge). Erst dann zeigen sich eventuell Konflikte, die er manuell auflösen muss. Er hat zudem jederzeit die Freiheit, Änderungen anderer Entwickler in seinen Branch zu übernehmen, ohne seine eigenen Änderungen gleichzeitig zu publizieren.
Die dezentrale Versionsverwaltung Bazaar ist in Python implementiert. Sie entstand, als die Ubuntu-Firma Canonical ein solches System benötigte und auf GNU Arch zurückgriff und es unter dem Namen Bazaar, kurz »baz«, an die eigenen Bedürfnisse anpasste. Der Nachfolger Bazaar-NG, trat später an, um einige noch bestehende Beschränkungen von GNU Arch zu überwinden. Neuere Distributionen verwenden aber nur noch den Namen Bazaar.
Arbeiten mit Bazaar
Ein konkretes Beispiel soll den Entwicklungsprozess genauer beschreiben: Zwei Autoren möchten zusammen an einem Linux-Magazin-Artikel arbeiten. Der eine legt ein Verzeichnis an und verwandelt es mit »bzr init« in einen Branch mit einem Repository in ».bzr/repository«. Er kopiert die Vorlage für den Artikeltext in das Verzeichnis, fügt die Datei mit »bzr add« der Versionsverwaltung hinzu und legt mit »bzr commit -m “Vorlage für Artikeltext”« eine initiale Revision an.
Für die Zusammenarbeit mit dem anderen Autor publiziert er seinen Branch beispielsweise mit »bzr push sftp:// Benutzer1@Server1/var/www/ Projekt« auf seinem Server. Bazaar legt dazu in dem angegebenem Verzeichnis einen neuen Branch mit allen Revisionen des Autors an. Eine Arbeitskopie der Dateien erstellt Bazaar aus Performance-Gründen nicht.
Der andere Autor setzt, sofern dies zuvor noch nicht geschehen ist, mit »bzr whoami “Mein Name <Benutzer2@E-Mail-Adresse.de>”« seine Identität und legt sich mit »bzr branch http:// Server2/Projekt« (oder »bzr get«) einen eigenen Branch an, der alle Revisionen seines Kollegen enthält. Er schreibt am Artikeltext und legt mit »bzr commit« für seine Änderungen neue Revisionen an, die Bazaar zunächst nur im lokalen Branch speichert. Mit »bzr push sftp:// Benutzer2@Server2/var/www/ projekt« legt er wieder eine Kopie seines Branch auf seinem eigenen Server ab.
Nun übernimmt jeder Autor bei Bedarf mit »bzr pull« die Änderungen im Branch des anderen. Legen beide Autoren jedoch unabhängig voneinander neue Revisionen an, entstehen so genannte divergierte Branches. In diesem durchaus üblichen Fall reicht ein »bzr pull« nicht mehr aus, um die Änderungen des Partners zu übernehmen, weil dabei Konflikte auftreten können. Stattdessen führt »bzr merge http:// Server/Projekt« divergierte Zweige zusammen.
Dabei übernimmt Bazaar die komplette Revisionsgeschichte des zusammenzuführenden Entwicklungszweigs (siehe Abbildung 1). Die Revisionsnummern dienen der leichteren Orientierung. Intern verwendet Bazaar Revisions-IDs, die aus E-Mail-Adresse, Datum, Zeit und einer zufälligen Nummer bestehen. Der Befehl »bzr log –show-ids« zeigt die Revisionsgeschichte samt dieser eindeutigen Kennungen.
|
Glossar |
|---|
|
Arbeitskopie: Eine Kopie der Revision, mit der der Benutzer arbeitet, einschließlich der lokalen Änderungen des Benutzers. Branch: Ein Entwicklungszweig, eine Entwicklungslinie, eine geordnete Folge von Revisionen. Checkin: Siehe Commit. Checkout: Eine Arbeitskopie mit etwas Meta-Information über den zugehörigen (gebunden) Branch. Man unterscheidet zwischen leichtgewichtigen (ohne eigene Historie) und schwergewichtigen (mit kompletter Historie) Checkouts. Commit: Anweisung an die Versionsverwaltung, für den aktuellen Stand der Arbeitskopie eine Revision, einen Fixpunkt (Checkpoint) anzulegen. Repository: Ein Archiv mit mehreren Revisionen eines Verzeichnisbaums samt Dateien. Revision: Ein Schnappschuss einer Arbeitskopie, erstellt während eines Commit. |
Entwicklungszweige
Haben beide Autoren an unterschiedlichen Stellen der Dateien gearbeitet, führt Bazaar die Änderungen automatisch zusammen und meldet »All changes applied successfully«. Andernfalls entstehen Konflikte in den betroffenen Dateien. In diesem Fall markiert Bazaar die Stellen und überlässt es dem Benutzer, die Konflikte aufzulösen. Als Hilfestellung legt Bazaar mehrere Versionen der Datei mit unterschiedlichen Endungen ab: ».MINE« für die Version aus der letzten Revision, ».OTHER« für die Version aus dem anderem Branch sowie ».BASE« für den gemeinsamen Vorgänger.
Es ist Aufgabe des Benutzers, alle Konflikte in allen betroffenen Dateien zu lösen. Mit »bzr resolved Dateiname« teilt er Bazaar jeden manuell aufgelösten Konflikt mit. Hat der Benutzer alle Konflikte aufgelöst und ist mit dem Zustand seiner Arbeitskopie zufrieden, legt er mit »bzr commit« eine neue Revision an und schließt damit den Merge ab.
Manchmal ist es sehr aufwändig, alle auftretenden Konflikte aufzulösen. Tools wie »kdiff3«, »ediff« oder »xxdiff«, die einen so genannten Three Way Merge visuell unterstützen, helfen dem Entwickler bei dieser Aufgabe. Ruft er eines dieser Werkzeuge mit den drei von Bazaar erstellten Dateien auf, visualisieren sie sogar Änderungen in derselben Zeile.
In regelmäßigen Abständen publiziert jeder Autor seinen Branch mit »bzr push«. Oder er automatisiert diesen Vorgang, indem er seinen Branch an einen anderen bindet. Dazu verwendet er den Befehl »bzr bind sftp:// Benutzer@Server/var/www/ projekt«. Nun versucht Bazaar, eine neu erstellte Revision zuerst im entfernten Branch anzulegen. Klappt dies, legt es diese im lokalen Branch an. Bazaar nennt solche gebundenen Branches auch Checkouts, ähnlich wie bei CVS oder Subversion.
Dabei taucht im entfernten gebundenen Branch mitunter eine neue Revision auf, die noch nicht im lokalem Branch steht. Das passiert zum Beispiel, wenn der Autor mehrere gebundene Branches hat, wenn er sowohl am Laptop als auch an seiner Workstation arbeitet oder wenn ein anderer Autor direkten Schreibzugriff auf diesen Branch hat.
In diesem Fall meldet Bazaar beim Commit »Tree is out of date«. Wie bei CVS oder Subversion verwendet der Autor dann den Befehl »bzr update«, um auf seine Arbeitskopie die Änderungen des entfernten Branch anzuwenden. Dann prüft er die Änderungen, löst Konflikte und legt seinerseits eine neue Revision an, um den Vorgang abzuschließen.
Checkouts benötigen zum Anlegen neuer Revisionen eine Verbindung zum entfernten Branch. Ist der Benutzer zeitweise offline, hat er zwei Möglichkeiten. Entweder er benutzt »bzr unbind« und macht den Branch wieder zu einem allein stehenden (Stand-alone Branch), oder er benutzt »bzr commit –local«, um seine Revision nur im lokalem Branch anzulegen. Sobald er wieder Verbindung zum entfernten Branch hat, synchronisiert er seine Branches mit »bzr pull« und »bzr push«.
|
Bazaar-Features im |
|---|
|
|
Aliases |
|---|
|
Bazaar liest seine Konfiguration aus der Datei »~/.bazaar/bazaar.conf«. Sie gehorcht dem aus der Windows-Welt und vielen Python-Programmen bekannten Ini-Format. Ein Beispiel findet sich in Listing 1. Der Abschnitt »[ALIASES]« erlaubt es dem Benutzer, Abkürzungen für oft verwendete Befehle zu definieren [8]. Der Befehl »bzr lco URL« erledigt so beispielsweise das Anlegen eines leichtgewichtigen Branch. |
|
Listing 1: |
|---|
01 [DEFAULT] 02 email=Anton Onymous <anton@onym.us> 03 04 [ALIASES] 05 co=checkout 06 lco=checkout --lightweight 07 up=update 08 recentlog=log -r-3..-1 09 ll=log --line -r-10..-1 |
Spitznamen für Branches
Die Benutzer dezentraler Versionskontrollsysteme arbeiten im Unterschied zu Benutzern von zentralen also grundsätzlich mit unterschiedlichen Branches. Um dabei die Übersicht nicht zu verlieren, welcher Autor in welchem Branch welche Änderung durchgeführt hat, weist Bazaar jedem Branch einen Spitznamen (Nick) zu. Als initialen Spitznamen wählt es dazu den Verzeichnisnamen, der dann als solcher auch in der Ausgabe von »bzr log« auftaucht. Es steht dem Entwickler jedoch frei, jederzeit mit »bzr nick Integration« den Spitznamen zu ändern.
Häufig wollen Programmierer nicht die komplette Historie eines Branch einsetzen, sondern nur die neueste Revision. Dies ist häufig der Fall, wenn der Branch viele Revisionen hat. Dann hilft am besten ein so genannter Lightweight Checkout. Ein solcher leichtgewichtiger Branch entspricht einer Arbeitskopie von CVS oder Subversion: Sämtliche Operationen (»log«, »annotate« …) benötigen Zugriff auf das Repository. Dafür gehen alle Commits direkt in den zugehörigen Branch. Leichtgewichtige Branches sind schnell angelegt, da Bazaar im Wesentlichen nur eine Arbeitskopie anlegen muss, ohne die gesamte Historie samt Revisionen zu kopieren.
Entwickler des Ubuntu-Projekts halten viele Pakete in Bazaar-Branches. So zum Beispiel der Branch zum Paket Xine, einem bekannten Medien-Abspieler [5], der sämtliche Revisionen seit der Erstellung des CVS-Repository von »xine« auf Sourceforge.net enthält.
Möchte ein interessierter Benutzer einen Patch gegen den aktuellen Stand des Xine-Pakets erstellen, ohne sämtliche Revisionen seit der Erstellung des Xine-Repository von »launchpad.net« herunterzuladen, benutzt er am besten den Befehl »bzr checkout –lightweight https://code.launchpad.net/~ubuntu-core-dev/+branch/xine-lib/ubuntu«. Bazaar legt in diesem Fall einen Branch ohne Repository an.
Geteilte Repositories
Ein schwergewichtiger Checkout dauert mitunter recht lange, da Bazaar alle Revisionen des Quell-Branch dupliziert. Um dieses Problem zu umgehen, besteht die Möglichkeit, dass sich zwei oder mehrere Branches ihre Revisionen teilen. Bazaar stellt hierfür so genannte geteilte Repositories (Shared Repositories) bereit, bei denen sich die Branches nur noch die Abfolge der Revisionen, nicht aber deren Inhalt merken müssen.
Der Befehl »bzr init-repo /srv/repo« legt ein solches geteiltes Repository an. »bzr init /srv/repo/branch1« legt nun einen neuen Branch an, dessen Revisionen Bazaar im geteilten Repository hält. Bestehende unabhängige Branches integriert »bzr push« in das geteilte Repository. Gemeinsam genutzte Revisionen legt Bazaar dabei effizient ab, indem es Redundanzen vermeidet. Auch von diesen Repository Branches legt der Entwickler bei Bedarf alle bisher eingeführten Arten von Branches an, allein stehende sowie leicht- und schwergewichtige Checkouts.
Erweiterungen
Bazaar lebt nicht zuletzt davon, dass eine rege Fangemeinde eigene Erweiterungen entwickelt und pflegt [4]. Plugins erweitern Bazaar in sehr vielfältiger Weise. Um zu verstehen, warum Plugins so mächtig sind, sind ein paar Kenntnisse über den Aufbau des Tools nötig. Bazaar besteht im Wesentlichen aus einer Python-Bibliothek namens »bzrlib«. Sie implementiert einige Klassen, die die Verwaltung von Revisionen, die Merge-Algorithmen oder die Übertragungsmethoden implementieren. Die einzelnen Kommandos, die der Befehl »bzr« verfügbar macht, bilden die Benutzerschnittstelle zur »bzrlib«. Plugins sind also kleine Python-Programme, die auf die »bzrlib« zurückgreifen. Die meisten stellen ihre Funktionalität als Unterbefehl von »bzr« zur Verfügung. Oder sie stellen Klassen bereit, die fest eingebaute Befehle verwenden.
Das meistbenutzte Plugin ist mit Sicherheit »bzrtools« [6]. Äußerst nützlich bei der Entwicklung von Software sind die Befehle »shelve« und »clean-tree«. Der Befehl »shelve« fragt den Benutzer für jede Änderung, ob er sie zurückstellen möchte. Eine zurückgestellte Änderung entfernt »bzrtools« aus der Arbeitskopie und speichert sie zwischen. So erleichtert es das Plugin, mehrere vorgenommene Änderungen einzeln einzuchecken. Der andere häufig benutzte Befehl ist »clean-tree«, der die Arbeitskopie von unbekannten, ignorierten oder Backup-Dateien säubert.
Die meiste Zeit beim Branchen verbringt Bazaar mit dem Anlegen der Arbeitskopie. Falls der Branch bereits als Lightweight Checkout vorliegt, bietet das Plugin zudem den Befehl »switch«, um die Arbeitskopie auf einen neuen Branch umzuschalten. Bazaar ersetzt dazu nur jene Dateien, die sich tatsächlich geändert haben. Dies geht wesentlich schneller als das Anlegen einer kompletten Arbeitskopie.
Ein anderes gern eingesetztes Plugin heißt »bzr-gtk«. Es bietet für viele Kommandos eine in GTK 2 implementierte grafische Oberfläche. So zeigt der Befehl »gannotate«, welche Zeile der Quelldatei in welcher Revision zuletzt verändert wurde (siehe Abbildung 2). Der Befehl »visualize« (früher »bzrk«) visualisiert die Entwicklungszweige in der Vergangenheit des vorliegenden Branch (siehe Abbildung 3). Damit ist leichter nachzuvollziehen, wann und wo Merges stattgefunden haben. Ein grafisches Frontend zum Anlegen neuer Revisionen stellt »gcommit« bereit. Es stellt zudem die Unterschiede aller anstehenden Commits als Context-Diff farbig dar.

Abbildung 2: Das Kommando »gannotate« gibt für jede Zeile einer Datei aus, in welcher Revision sie zuletzt geändert wurde. Neuere Änderungen erscheinen dunkler als ältere.

Abbildung 3: Der Befehl »bzrk« stellt die Änderungen in einem Branch grafisch in Form eines gerichteten Grafen dar. Jeder Knoten ist eine neue Revision, zusammenführende Kanten sind Merges.
Freiheit für Programmierer
Bazaar lässt Freiraum für ganz verschiedene Arbeitsstile. Es definiert dabei bewusst keinen Arbeitsablauf, um den Benutzer möglichst viel Freiheit zu lassen (siehe Abbildung 4 und [7]). So lässt sich mit leichtgewichtigen Branches selbst die Arbeitsweise des zentralen CVS nachbilden. Zudem ist Bazaar ähnlich effizient wie Git verwendbar.

Abbildung 4: Der flexible Aufbau von Bazaar erlaubt ganz unterschiedliche Workflows, die teilweise zentrale Systeme simulieren.
Bei Git existiert zwar anders als bei Bazaar immer ein Repository mit mindestens einem Branch. Das Umschalten von einem Branch auf einen anderen geht schnell, da Git nur geänderte Dateien ersetzt, während »bzr branch« die Arbeitskopie komplett neu anlegt. Liegen Bazaar-Branches jedoch in einem geteilten Repository und existiert die Arbeitskopie als leichtgewichtiger Checkout, schaltet der Befehl »bzr switch« ebenfalls schnell zwischen Arbeitskopien um.
Bazaar ist ein modernes, effizientes und aktiv entwickeltes Versionskontrollsystem. Ein wichtiger Schwerpunkt bei der Entwicklung von Bazaar war eine saubere und klare Benutzerschnittstelle. Zurzeit konzentrieren sich die Entwickler darauf, für Version 1.0 die Geschwindigkeit von Bazaar zu erhöhen und die bereits sehr ausführliche Dokumentation zu verbessern. (ofr)
|
Infos |
|---|
|
[1] Alberto Planas, “Das Versionskontrollsystem des Linux-Kernels”: Linux-Magazin 3/06, S. 98 [2] Nico Schottelius, “Versionskontrolle – Arch versus Monotone”: Linux-Magazin 2/05, S. 104 [3] D. Haischt, “Revisionskontrolle für unterwegs mit SVK”: Linux-Magazin 7/06, S. 48 [4] Sammelstelle für Erweiterungen: [http://bazaar-vcs.org/BzrPlugins] [5] Branch zum Ubuntu-Paket Xine: [https://code.launchpad.net/~ubuntu-core-dev/+branch/xine-lib/ubuntu] [6] Plugin »bzrtools«: [http://bazaar-vcs.org/BzrTools] [7] Unterschiedliche Workflows mit Bazaar: [http://bazaar-vcs.org/Workflows] [8] Befehls-Aliases: [http://bazaar-vcs.org/CommandAliases] |
|
Die Autoren |
|---|
|
Martin Steigerwald arbeitet gegenwärtig als Systemadministrator bei der Team(ix) GmbH in Nürnberg. Ein Schwerpunkt seiner Tätigkeit besteht im Second Level Support für Linux als Business-Desktop. Er hat Linux schon vor Jahren auf seinem Amiga 4000 installiert und nutzt es auch privat. Reinhard Tartler arbeitet zurzeit als wissenschaftlicher Mitarbeiter der Uni Erlangen am Lehrstuhl für Betriebssysteme. In seiner Freizeit engagiert er sich als Ubuntu- und Debian-Entwickler, was auch eine exakte und effiziente Verwaltung von Distributionspaketen erfordert. Privat setzt er Linux seit 1996 ein. |







