weidner/computer/rcs/monotone/

Versionsverwaltung mit Monotone - In Gang kommen

Monotone ist ein Programm für verteilte Versionsverwaltung. Dieser Artikel beschreibt, für jemand, der noch nicht damit gearbeitet hat, wie man das Programm so schnell wie möglich für sich verwenden kann.

Um mit Monotone zu arbeiten benötige ich mindestens ein lokales Repository, einen Schlüssel um die abgespeicherten Daten zu signieren und einen Arbeitsbereich, dessen Inhalt von Monotone verfolgt wird.

Ein lokales Repository anlegen

Um Dateien mit Monotone zu verwalten muß ich ein lokales Repository anlegen. Prinzipiell kann ich ein Repository für mehrere oder alle Projekte verwenden, ziehe in den meisten Fällen jedoch ein Repository für ein Projekt vor. Das lokale Repository lege ich mit folgendem Befehl an:

 $ mtn --db projekt.mtn db init

Persönliche Schlüssel erzeugen

Mit meinen persönlichen Schlüsseln signiere ich alle Daten, die ich im Repository einspeichere sowie alle Tags die ich vergebe. Über diesen Schlüssel werden auch die Zugriffsrechte auf entfernte Repositories eingestellt:
 $ mtn genkey meine@email.adresse
Um das Kennwort für den Schlüssel nicht jedesmal eingeben zu müssen kann ich (unter UNIX, mit installiertem ssh_agent) den Schlüssel zur Verwaltung an ssh_agent übergeben:
 $ mtn ssh_agent_export ~/.ssh/id_monotone
 $ chmod 600 ~/.ssh/id_monotone
 $ ssh-agent /bin/bash
 $ ssh-add ~/.ssh/id_monotone

Anschließend brauche ich den Monotone-Schlüssel nur noch einmal während der Sitzung eingeben.

Alternativ (und weniger sicher) kann ich das Kennwort in einen Hook in der Datei .monotonerc eintragen:

 $ mkdir ~/.monotone
 $ cat >> ~/.monotone/.monotonerc
 function get_passphrase(keypair_id)
     return "meinPasswort"
 end

Einen Arbeitsbereich anlegen

Einen Arbeitsbereich (workspace) kann ich anlegen indem ich einen vorhandenen Zweig aus einem lokalen Repository auschecke (mtn checkout) oder indem ich einen neuen Arbeitsbereich aufsetze (mtn setup). So lege ich einen neuen Arbeitsbereich an:

 $ mkdir -p ~/P/projekt
 $ cd ~/P/projekt
 $ mtn --db ~/A/monotone/projekt.mtn \
       setup --branch projekt.branch

Monotone kann nun im lokalen Repository ~/A/monotone/projekt.mtn Dateien aus dem Verzeichnis ~/P/projekt/ im Zweig projekt.branch verwalten. Von sich aus macht es das jedoch nicht. Damit Monotone den aktuellen Stand einer Datei im lokalen Repository verwaltet, muss ich ihm die Datei vorher bekannt machen.

Dateien hinzufügen / umbenennen / entfernen

Dateien im Arbeitsbereich, die von Monotone verwaltet werden sollen, kann ich ihm mit mtn add bekannt machen. Mit mtn drop schließe ich eine Datei von der weiteren Verwaltung durch Monotone aus (ältere Versionen bleiben im Repository erhalten und zugänglich). Wenn ich eine Datei umbenennen oder in ein anderes Verzeichnis verschieben und dabei ihre Versionsgeschichte erhalten möchte, verwende ich mtn rename.

Welche Dateien Monotone verwaltet (kennt), zeigt mir das Kommando mtn list known im Arbeitsbereich. Dem entsprechend zeigt mtn list unknown die Dateien im Arbeitsbereich, die Monotone nicht kennt (nicht verwaltet). Schließlich zeigt mtn list ignored die Dateien, die Monotone gar nicht kennen soll. Diese letzte Liste kann ich mit einer Datei namens .mtn-ignore im Arbeitsbereich beeinflussen. Damit kann ich die Dateien, deren Änderungen ich nicht verfolgen will, ausschließen und schließlich mit mtn add --unknown alle anderen Dateien mit einem Mal unter Versionsverwaltung stellen.

Änderungen bestätigen

Monotone merkt sich nahezu beliebig viele Zwischenstände der von ihm verwalteten Dateien, aber nur auf Aufforderung mit mtn commit. Dieser Befehl verlangt eine Notiz, die die damit erzeugte Revision beschreibt. Die Notiz kann ich mit der Option --message auf der Kommandozeile mitgeben. Ansonsten öffnet Monotone einen Dateieditor mit dem ich die Notiz erstellen kann. Erst dann wird der momentane Stand aller verwalteten Dateien im lokalen Repository zwischengespeichert.

Zweige

Zu Beginn der Arbeit an einem Projekt bilden die verschiedenen Versionen meiner Dateien einen geraden unverzweigten gerichteten Graphen, der jeweils vom Vorgänger zum Nachfolger in einer Kette geht.

Wenn ich bereits einen oder mehrere Stände des Projekts veröffentlicht habe, wird es früher oder später passieren, das ich einen Fehler in einer schon veröffentlichten Version bereinigen muss, die weit hinten in der Versionskette liegt. Das ist ein guter Moment um einen neuen Zweig im Repository zu starten, der genau bei der veröffentlichten Version vom Stamm abzweigt. Monotone pflegt für mich diesen alternativen Entwicklungszweig im selben Repository und bezieht unabhängig von den Änderungen im Hauptstamm alle Änderungen in diesem Zweig auf die Version mit der er gestartet wurde.

Ein anderer Grund, einen neuen Zweig einzurichten, wäre z.B. um ein neues Feature auszuprobieren, für das bei der Entwicklung im Hauptstamm keine Zeit ist.

Der einfachste Weg, einen neuen Zweig anzulegen, ist den Namen des neuen Zweiges beim Commit anzugeben:

 $ mtn --branch trunk.neuerzweig commit
Alternativ kann ich den neuen Zweig schon vor dem nächsten Commit anlegen:
 $ mtn cert h: branch trunk.neuerzweig
 $ mtn update --branch trunk.neuerzweig

Obwohl das etwas aufwendiger ist, hat es doch den Vorteil, das ich später beim Commit nicht mehr daran denken muss, den Zweig anzugeben, da die Dateien in meinem Arbeitsverzeichnis nun bereits zum neuen Zweig gehören und mtn commit automatisch in diesem aktualisiert.

Änderungen zusammenführen

Wenn in einem Zweig verschiedene Änderungen von einem oder mehreren Entwicklern bestätigt wurden, kann es passieren, dass es mehrere letzte Stände gibt. Diese führe ich mit mtn merge zusammen. Nach der nächsten Synchronistation der Repositories haben alle wieder den gleichen Stand.

Möchte ich hingegen die Änderungen von einem Zweiges auf einen anderen Zweig anwenden, verwende ich mtn propagate.

Versionen kennzeichnen

Ein Problem bei Monotone ist für uns Menschen einen bestimmten Revisionsstand zu identifizieren, da bei Monotone jede Revision nach dem kryptographischen Schlüssel (SHA1) der Datei benannt ist, die den Stand ausmacht.

Wenn ich weiss, das ich einen bestimmten Revisionsstand später wieder erkennen will, z.B. weil ich diese Revision veröffentliche, dann markiere ich diese Revision mit einem version tag.

Um einen Stand zu markieren, bestätige ich die letzten Änderungen mit mtn commit, informiere mich über die aktuelle Version mit mtn head und markiere diesen Stand mit mtn tag revision tagname.

Posted 2011-03-16
Tags: