Versionsverwaltung mit Bazaar

Dies ist der zweite Teil der Artikelreihe über die Verwendung von Bazaar. Im letzten Teil ging um die Vorteile von Bazaar als Versionsverwaltungssystem, wie man einen Branch aufzusetzt und auf den Server lädt.

Bazaar ist im Alltagsgebrauch ein sehr einfach zu verwendendes System, mit dem selbst Entwickler, die bisher keine Erfahrung mit RCS hatten, zurechtkommen sollten. Es wurde versucht möglichst viele Prozesse zu vereinfachen und zu automatisieren, wie beispielsweise das Verbinden (mergen) von zwei Zweigen.

 

Branch herunterladen

Im letzten Teil hatte ich den Branch auf den Server myftpserver.com ins Verzeichnis /bzr/mycode geladen. Wenn nun ein anderer Entwickler auf den Code zugreifen will, bspw. um Korrekturen vorzunehmen, kann er sich den Branch mit dem Befehl

bzr branch http://myftpserver.com/bzr/mycode

herunterladen. Der Code landet im gleichen Verzeichnis im Ordner "mycode“. Man kann alternativ auch einen Ordnernamen als Parameter übergeben, bspw.

bzr branch http://myftpserver.com/bzr/mycode mycode-patch

Dann landet der Code im Verzeichnis "mycode-patch“. Das ist besonders für externe Entwickler ohne Schreibzugriff auf den Server nützlich, die den Branch patchen und dann auf dem eigenen Server hochladen.

 

Hinweis: Es ist auch möglich den Branch mit bzr checkout herunterzuladen. Hierbei verhält sich Bazaar wie CVS/SVN: Jeder Commit wird sofort in den Branch auf den Server geschrieben. Ein bzr push ist hierbei nicht notwendig. Allerdings muss man Verbindung zum Server haben und entsprechende Zugriffsrechte besitzen. Als externer Entwickler, der keinen Zugriff auf den Server hat, empfiehlt es sich deshalb nicht bzr checkout zu verwenden.

Nun kann man, wie schon im letzten Teil beschrieben, am Code arbeiten und Änderungen mit bzr commit hinzufügen.

Einen abgeleiteten Branch erstellen

Während man an seinem Projekt arbeitet, könnte man eine Kopie seines Branches benötigen. Vorstellbar wäre eine Situation, in der man einen Branch "trunk“ hat, der die stabile Linie des Projektes darstellt. Man will ein paar experimentelle Ideen in den Code des Projekts einbauen. Dafür nimmt man allerdings nicht den trunk-Branch, da dieser ja nur stabilen und getesteten Code enthalten soll. Also erstellt man einen abgeleiteten Branch. Der Befehl ist der ähnlich wie beim Herunterladen eines Branch:

bzr branch trunk experimental

Nun hat man einen weiteren Branch 'experimental', der sich von trunk ableitet. Die beiden Zweige 'trunk' und 'experimental' sind zu diesem Zeitpunkt absolut gleich.

Branch aktualisieren

Wenn man mit mehreren Leuten an einem Projekt arbeitet, wird es zwangsläufig vorkommen, dass eine neue Revision auf den Server geladen wird, während man noch an seinem lokalen Branch mit der vorherigen Revision arbeitet. Oder man hat, wie im obigen Beispiel, zwei Branches und hat in 'trunk' ein paar Korrekturen vorgenommen, die auch 'experimental' betreffen. Man könnte nun jede Änderung von Hand von Branch A in Branch B einfügen, aber es geht viel einfacher.

Im ersten Beispiel würde ein einfaches

bzr merge

ausreichen. Bazaar holt sich die Änderungen auf dem Server und fügt sie vollautomatisch in unseren Zweig ein, wenn es keine Konflikte geben sollte (s. u.). Für das zweite Beispiel geht man in das Verzeichnis 'experimental' und macht ein merge von 'trunk':

cd experimental
bzr merge ../trunk

Wenn man die Änderungen von 'experimental' in 'trunk' einfügen möchte, macht man das ganze genau umgekehrt. Ist das nicht wirklich einfach?

Hinweis: Wenn man an seinem Branch seit dem letzten Herunterladen nichts mehr geändert hat und nur auf die aktuelle Version aktualisieren will, verwendet man bzr pull.

Änderungen ansehen mit diff und status

An dieser Stelle möchte ich auf zwei Befehle eingehen, die ich vorher noch nicht erwähnt hatte. Mit bzr diff bzw. bzr status lassen sich, bevor man bzr commit ausführt, die Änderungen ansehen, die man am Code durchgeführt hat. Dabei zeigt bzr status eine Übersicht welche Dateien hinzugefügt, geändert oder gelöscht wurden, während bzr diff die genauen Änderungen in den jeweiligen Dateien anzeigt. Dies funktioniert auch bei den obigen Beispielen, wo wir die Änderungen von einem Branch in einen anderen übertragen haben. Nach dem bzr merge kann mit mit den beiden Befehlen herausfinden was geändert wurde.

In beiden Fällen muss nach bzr merge ein bzr commit ausgeführt werden, damit die Änderungen übernommen werden.

Änderungen rückgängig machen

Es kommt immer wieder einmal vor, dass man in seinem Branch Mist macht und dann seine Änderungen rückgängig machen möchte oder sogar eine frühere Revision wiederherstellen will. Dafür gibt es den Befehl bzr revert. Hat man Änderungen an seinem Projekt durchgeführt und noch keinen Commit gemacht, reicht es aus bzr revert auszuführen. Hat man den Commit schon ausgeführt oder möchte auf eine bestimmte Revision zurücksetzen, muss man den Parameter -r mit der Nummer der Revision angeben. Die Revisionsnummer sieht man beispielsweise im Log (bzr log) des Branches hinter „revno:“. Möchte man also z. B. auf Revision 15 zurücksetzen, gibt man folgendes ein:

bzr revert -r 15

Danach folgt ein bzr commit, damit sich die Änderungen im Branch befinden.

Konflikte auflösen

Bazaar versucht bei Merges möglichst gut die beiden Branches zusammen zu führen, doch manchmal kann es zu Konflikten kommen. Dies kommt beispielsweise vor, wenn zwei Entwickler in der gleichen Datei an der selben Stelle verschiedene Änderungen durchführen. Dieses Problem kann die Software nicht beheben und löst deshalb einen Konflikt aus, den ein Entwickler auflösen muss.

Ein Beispiel. Eine Datei hat folgenden Inhalt (die Farben werden weiter unten wichtig):

def myfunction():
    print 'Ein Beispielsatz.'

Entwickler A ändert die Datei folgenderweise ab:

def myfunction():
    print 'Ein Beispielsatz mit einer Änderung von A.'

Entwickler B macht in seinem Zweig diese Änderungen:

def myfunction():
    print 'Ein Beispielsatz mit der Änderung von B.'

Versucht man die Änderungen des Zweigs von Entwickler B in den Zweig von A zu mergen, entsteht ein Konflikt.

M file.py
Text conflict in file.py
1 conflicts encountered.

In diesem Fall befindet sich der Konflikt in der Datei file.py. Bevor man einen Commit ausführen kann, müssen alle Konflikte im Branch aufgelöst sein. Mit dem Befehl

bzr conflicts

kann man sich alle Dateien mit Konflikten anzeigen lassen. In meinem Beispiel muss der Konflikt in der Datei file.py aufgelöst werden. Wenn man die Datei öffnet, sieht man, dass Bazaar die Stelle mit dem Konflikt markiert hat:

def myfunction():
<<<<<<< TREE
print 'Ein Beispielsatz mit einer Änderung von A.'
=======
print 'Ein Beispielsatz mit der Änderung von B.'
>>>>>>> MERGE-SOURCE

Zusätzlich legt Bazaar noch drei Dateien im Projektverzeichnis an mit den Endungen .BASE, .THIS und .OTHER. Sie enthalten die jeweiligen Versionen der Datei. file.py.BASE enthält die letzte gemeinsame Version der beiden Entwickler (blau, siehe oben), file.py.THIS enthält die Dateiversion von Zweig A (gelb) und file.py.OTHER enthält die Version von Zweig B (grün).

Zur Lösung des Konflikts soll die Änderung von Entwickler A übernommen werden. Die Datei wird deshalb folgendermaßen verändert:

def myfunction():
print 'Ein Beispielsatz mit einer Änderung von A.'

Nun muss der Konflikt als gelöst markiert werden. Dazu wird der Befehl

bzr resolve file.py

verwendet. Da hier der einzige Konflikt in dieser Datei war, ist das schon ausreichend. Wenn in mehreren Dateien Konflikte waren, müssen diese aufgelöst und ebenfalls als gelöst markiert werden. Nicht vergessen jeweils die drei Dateien mit den Endungen .BASE, .THIS und .OTHER löschen.

Nun können die Änderungen mit einem Commit zum Branch hinzugefügt werden.

Im nächsten Teil geht es um Bazaar im Zusammenspiel mit Launchpad . Launchpad bietet für freie Softwareprojekte eine interessante Plattform zur Verwaltung des Teams, der Bugs und – mit Bazaar – des Quellcodes.

 

Teil 1: Wie Bazaar das Leben von Entwicklern vereinfacht
Teil 2: Versionsverwaltung mit Bazaar

Trackback URL für diesen Eintrag:

http://www.seqfault.de/de/trackback/16

Ich wollte einfach mal danke sagen! Eine wirklich gute Eileitung.