» SelfLinux » Programmierung » CVS » Übersicht CVS » Abschnitt 1 SelfLinux-0.10.0
zurück   Startseite Kapitelanfang Inhaltsverzeichnis GPL   weiter

SelfLinux-Logo
Dokument Übersicht CVS - Abschnitt 1 Revision: 1.1.2.16
Autor:  Karl Fogel
Formatierung:  Matthias Hagedorn
Lizenz:  GPL
 

1 CVS-Grundlagen

Dieses Kapitel führt in die grundlegenden Konzepte von CVS ein und gibt dann eine tiefer gehende Erläuterung des täglichen CVS-Einsatzes. Nach dessen Lektüre sind Sie auf dem besten Wege, ein CVS-Guru zu werden.

Wenn Sie noch nie CVS (oder ein anderes Versionsverwaltungssystem) benutzt haben, kann es leicht sein, dass Sie durch einige der zu Grunde liegenden Annahmen ins Stolpern geraten. Was anfänglich anscheinend für die meiste Verwirrung sorgt ist, dass CVS für zwei scheinbar unabhängige Aufgaben eingesetzt wird: Historienverwaltung und Zusammenarbeit. Es zeigt sich jedoch, dass diese beiden Funktionen eng miteinander verbunden sind.

Die Historienverwaltung wurde notwendig, weil Benutzer den momentanen Zustand eines Programmes mit dem an einem bestimmten Zeitpunkt der Vergangenheit vergleichen wollten. Zum Beispiel bringt ein Programmierer während der Implementation einer neuen Funktion das Programm in einen ziemlich fehlerhaften Zustand, in dem das Programm auch wahrscheinlich erst einmal bleiben wird, bis diese neue Funktion endgültig fertig implementiert ist. Unglücklicherweise ist genau dies meist der Zeitpunkt, zu dem ein Benutzer die Beschreibung eines Fehlers in der letzten veröffentlichten Version einschickt. Um diesen Fehler zu finden (der auch in der aktuellen Entwicklerversion enthalten sein kann), muss das Programm zuerst wieder in einen benutzbaren Zustand gebracht werden.

Diesen Zustand wieder herzustellen stellt dann kein Problem dar, wenn die Historie zu den Quelltexten mit CVS verwaltet wird. Ein Entwickler kann einfach sagen: »Gib mir den Quelltext, wie er vor drei Wochen war«, oder vielleicht: »Gib mir den Quelltext so, wie er war, als wir die letzte öffentliche Version freigegeben haben.« Wenn Sie bisher noch nie einen so praktischen Zugriff auf frühere Versionen hatten, werden Sie überrascht sein, wie schnell man davon abhängig werden kann. Persönlich verwende ich eine Revisionskontrolle bei allen meinen Programmierprojekten - dies hat mich schon oft gerettet.

Um zu verstehen, was dies mit der Unterstützung der Zusammenarbeit zu tun hat, müssen wir zunächst die Mechanismen etwas näher betrachten, mit denen CVS es ermöglicht, dass mehrere Personen zusammen an einem Projekt arbeiten. Doch zuvor sehen wir uns einen Mechanismus an, den CVS nicht bietet (oder der zumindest nicht zu empfehlen ist): Dateisperren. Wenn Sie bereits andere Versionsverwaltungssysteme benutzt haben, werden Sie schon mit dem Entwicklungsmodell Sperren-Ändern-Freigeben vertraut sein, bei dem ein Entwickler zuerst den exklusiven Schreibzugriff auf die zu bearbeitende Datei (eine Sperre) bekommen muss, die Veränderungen vornimmt und dann die Sperre wieder freigibt, damit andere Entwickler auf diese Datei zugreifen können. Wenn jemand anderes bereits eine Sperre für diese Datei gesetzt hat, so muss er diese zuerst wieder freigeben, bevor man selbst eine Sperre setzen und Veränderungen anbringen kann. (In manchen Implementationen kann man diese Sperre auch stehlen, was aber für den anderen eine böse Überraschung und außerdem kein guter Stil ist!)

Dieses System ist dann brauchbar, wenn sich die Entwickler kennen, wissen, wer was zu einem bestimmten Zeitpunkt machen möchte, und, im Falle von Zugriffskonflikten, schnell miteinander kommunizieren können. Wenn jedoch die Entwicklergruppe zu groß wird oder zu weiträumig verstreut ist, knabbert die Verwaltung der Sperren an der eigentlichen Arbeitszeit; dies wird zu einem ständigen Problem und entmutigt viele, wirkliche Arbeit zu leisten.

CVS verfolgt einen ausgereifteren Ansatz. Anstatt von den Entwicklern zu verlangen, sich gegenseitig zu koordinieren, erlaubt CVS den Entwicklern gleichzeitiges Arbeiten, übernimmt die Integration der Veränderungen und behält mögliche Konflikte im Auge. Dieser Prozess benutzt das Kopieren-Modifizieren-Zusammenfassen-Modell, das wie folgt funktioniert:

Entwickler A fordert eine Arbeitskopie von CVS an (ein Verzeichnisbaum, der alle Dateien eines Projektes enthält). Dies wird auch Checking out einer Arbeitskopie genannt, wie das Ausleihen eines Buches aus einer Bibliothek.

Entwickler A arbeitet frei an seiner Arbeitskopie. Zum gleichen Zeitpunkt können auch andere Entwickler an ihren eigenen Arbeitskopien fleißig sein. Weil alle Kopien unabhängig voneinander sind, gibt es auch keine Konflikte - es ist so, als hätten alle Entwickler ihre eigene Kopie des gleichen Buches aus der Bibliothek, und sie alle schreiben, unabhängig voneinander, Kommentare an die Ränder oder bestimmte Seiten vollständig neu.

Entwickler A beendet seine Veränderungen und sendet diese mit einer Log-Nachricht, also einem Kommentar, der beschreibt, was der Zweck der Veränderungen war, an den CVS-Server (commit). Dies ist damit vergleichbar, die Bibliothek darüber zu informieren, welche Veränderungen gemacht wurden und warum. Die Bibliothek lässt diese wiederum in eine Hauptkopie einfließen, wo sie damit für alle Zeit aufgezeichnet werden.

In der Zwischenzeit können andere Entwickler CVS dazu veranlassen, die Bibliothek abzufragen, um herauszufinden, ob die Hauptkopie in jüngster Zeit verändert wurde. Ist dem so, aktualisiert CVS automatisch deren Arbeitskopie. (Dieser Teil grenzt an Magie und ist einfach wunderbar, ich hoffe, Sie wissen dies zu schätzen. Stellen Sie sich vor, wie die Welt wäre, wenn echte Bücher so funktionieren würden!)

Soweit es CVS betrifft, sind alle Entwickler eines Projektes gleich. Zu entscheiden, wann ein Commit oder eine Aktualisierung durchgeführt wird, ist eine Sache der persönlichen Einschätzung oder der Projektregeln. Eine übliche Strategie bei Programmierprojekten ist es, immer eine Aktualisierung zu machen, bevor die Arbeit an größeren Veränderungen begonnen wird, und einen Commit erst dann zu machen, wenn die Veränderungen vollständig und getestet sind, sodass die Hauptkopie immer in einem funktionsfähigen Zustand ist.

Vielleicht fragen Sie sich, was passiert, wenn die Entwickler A und B in ihren Arbeitskopien unterschiedliche Veränderungen an dem gleichen Stück (Quell-)Text vornehmen und beide ihre Veränderungen mittels Commit abschicken? Dies wird Konflikt genannt und von CVS entdeckt, sobald Entwickler B, versucht seine Veränderungen abzuschicken. Anstatt Entwickler B zu erlauben fortzufahren, gibt CVS bekannt, dass es einen Konflikt gefunden hat, und setzt Konfliktmarkierungen (leicht zu erkennende Marken im Text) an die in Konflikt stehenden Stellen im Text seiner Kopie. Diese Stellen beinhalten beide Veränderungen und sind derart angeordnet, dass sie leicht verglichen werden können. Entwickler B muss sich nun alles noch einmal ansehen und eine neue Version abschicken, die den Konflikt auflöst. Vielleicht müssen die beiden Entwickler miteinander reden, um die Sache zu klären. CVS alarmiert nur die Entwickler über die Konflikte; es ist an den Menschen, diese tatsächlich zu lösen.

Was ist nun mit der Hauptkopie? In der offiziellen CVS-Terminologie wird diese das Archiv (Repository) eines Projektes genannt. Das Archiv ist schlicht nur ein Datei-/Verzeichnisbaum, der auf einem Server gespeichert ist. Ohne zu stark in die Tiefe der Struktur zu gehen (siehe jedoch  Kapitel 4), werfen wir einen Blick darauf, was das Archiv leisten muss, um den Anforderungen des Checkout-Commit-Aktualisieren-Zyklus gerecht zu werden.

Stellen Sie sich folgendes Szenario vor:

Zwei Entwickler, A und B, führen gleichzeitig einen Checkout des gleichen Projektes aus. Das Projekt befindet sich noch am Ausgangspunkt - es wurden noch von niemandem Veränderungen per Commit an das Archiv geschickt, sodass sich noch alle Dateien in ihrem ursprünglichen Zustand befinden.

Entwickler A beginnt sofort mit seiner Arbeit und führt schon bald den ersten Commit seiner Änderungen aus.

In der Zwischenzeit sieht Entwickler B fern.

Entwickler A arbeitet, als ob es kein Morgen gäbe, und führt einen zweiten Commit für einen weiteren Satz von Veränderungen aus. Das Archiv enthält nun die Originaldateien, gefolgt von As erstem Satz von Veränderungen, gefolgt von diesem Satz an Veränderungen.

In der Zwischenzeit spielt Entwickler B Videospiele.

Plötzlich schließt sich Entwickler C dem Projekt an und macht einen Checkout einer Arbeitskopie aus dem Archiv. Die Kopie von Entwickler C enthält As erste zwei Sätze von Veränderungen, weil diese schon im Archiv enthalten waren, als C für seine Arbeitskopie einen Checkout gemacht hat.

Entwickler A arbeitet weiter wie von Geistern besessen, vollendet seinen dritten Satz an Veränderungen und führt abermals einen Commit aus.

Zu guter Letzt, nichts ahnend von der jüngsten rasanten Aktivität, entscheidet Entwickler B, dass es Zeit wird, an die Arbeit zu gehen. Er kümmert sich nicht darum, eine Aktualisierung seiner Arbeitskopie durchzuführen; er fängt an, Dateien zu bearbeiten, von denen einige jene Dateien sein könnten, an denen A gearbeitet hat. Kurz darauf führt Entwickler B seinen ersten Commit dieser Veränderungen aus.

An diesem Punkt können nun zwei Dinge passieren. Wenn keine der von Entwickler B bearbeiteten Dateien von A bearbeitet wurde, dann ist der Commit erfolgreich. Wenn CVS jedoch merkt, dass einige der Dateien von B verglichen mit den aktuellen Dateien des Archivs veraltet sind und diese auch von B in seiner Arbeitskopie verändert wurden, informiert CVS B darüber, dass er eine Aktualisierung durchführen muss, bevor ein Commit durchgeführt werden kann.

Wenn Entwickler B die Aktualisierung durchführt, fügt CVS alle Veränderungen von A in Bs lokale Kopien der Dateien ein. Einige von As Veränderungen können mit Bs noch nicht abgeschickten Veränderungen in Konflikt geraten, manche nicht. Die Teile, welche nicht in Konflikt stehen, werden einfach ohne weitere Komplikationen in Bs Kopie eingefügt; die in Konflikt stehenden müssen zuerst von B bereinigt werden, bevor der Commit durchgeführt werden kann.

Wenn Entwickler C nun eine Aktualisierung durchführt, bekommt er mehrere Sätze an Veränderungen aus dem Archiv: den dritten Commit von A, den ersten von B und vielleicht den zweiten von B (wenn B die Konflikte aufgelöst hatte).

Damit CVS Veränderungen in der richtigen Reihenfolge an die Entwickler verteilen kann, deren Arbeitskopien unter Umständen unterschiedlich stark veraltet sind, muss das Archiv alle Commits seit Projektbeginn aufzeichnen. In der Praxis speichert das CVS-Archiv diese als aufeinander folgende Diffs. Daher kann CVS auch noch für sehr alte Arbeitskopien den Unterschied zwischen den Dateien der Arbeitskopien und dem aktuellen Stand des Archivs bestimmen und dadurch die Arbeitskopie effizient wieder auf den aktuellen Stand bringen. Für Entwickler ist es dadurch einfach, die Historie des Projektes einzusehen und zu jedem Zeitpunkt sogar sehr alte Arbeitskopien wieder zum Leben zu erwecken.

Obwohl das Archiv genau genommen das gleiche Resultat mit anderen Methoden erreichen könnte, ist das Abspeichern der Diffs eine einfache und intuitive Methode, die notwendige Funktionalität zu implementieren. Dieser Prozess hat den zusätzlichen Vorteil, dass CVS durch die korrekte Anwendung von patch jeden vorangegangenen Zustand des Verzeichnisbaumes wiederherstellen und damit jede Arbeitskopie von einem Zustand in einen anderen überführen kann. Es erlaubt jedem, einen Checkout. Daher des Projektes in einem womöglich vergangenen Zustand zu machen. Es kann ebenso die Unterschiede im diff-Format zwischen zwei Zuständen des Projektes aufzeigen, ohne dabei irgendeine Arbeitskopie zu beeinflussen.

Daher sind genau diese Funktionen, die den vernünftigen Zugriff auf die Historie eines Projektes zulassen, auch dafür nützlich, es einer dezentralen, unkoordinierten Entwicklergruppe zu ermöglichen, an einem Projekt zusammenzuarbeiten.

Die Details, wie ein Archiv angelegt wird, Benutzerzugriffe administriert werden und CVS-spezifische Dateiformate gehandhabt werden (diese werden in  Kapitel 4 beschrieben), können Sie erst einmal außer Acht lassen. Im Augenblick konzentrieren wir uns darauf, wie Veränderungen an einer Arbeitskopie durchgeführt werden können.

Doch zuerst noch eine kurze Übersicht der Terminologie:

Revision - Eine Veränderung an einer Datei oder Menge von Dateien, die durch einen Commit abgeschlossen wurde. Eine Revision ist eine Momentaufnahme eines sich ständig verändernden Projektes.
Archiv - Die Hauptkopie, in der CVS die vollständige Revisionshistorie eines Projektes speichert. Jedes Projekt hat genau ein Archiv.
Arbeitskopie - Die Kopie, mit der gearbeitet wird und die tatsächlich verändert wird. Es kann mehrere Arbeitskopien eines bestimmten Projektes geben; im Allgemeinen hat jeder Entwickler seine eigene Kopie.
Checkout - Eine Arbeitskopie von dem Archiv anfordern. Die angeforderte Kopie stellt den Zustand des Projektes zu dem Zeitpunkt dar, zu dem die Kopie angefordert wurde; wenn Sie oder andere Entwickler Veränderungen vornehmen, müssen commit und update durchgeführt werden, um die eigenen Veränderungen zu »veröffentlichen« und die der anderen Mitentwickler sehen zu können.
Commit - Senden der eigenen Veränderungen zum zentralen Archiv. Auch Check-in genannt.
Log-Nachricht - Ein Kommentar der bei einem Commit einer Revision angehängt wird und die vorgenommenen Veränderungen beschreibt. Andere Entwickler können durch die Log-Nachrichten blättern und erhalten so die Antwort auf die Frage, was in dem Projekt passiert ist.
Aktualisierung (update) - Veränderungen von anderen Entwicklern vom Archiv in die eigene Arbeitskopie aufnehmen und aufzeigen, ob die eigene Arbeitskopie noch nicht durch commit abgeschickte Veränderungen enthält.
Konflikt - Situation, in der zwei Entwickler Veränderungen im gleichen Teil der gleichen Datei per commit abzuschicken versuchen. CVS bemerkt solche Konflikte und benachrichtigt die Entwickler, aber die Entwickler müssen diese selbst auflösen.


zurück   Seitenanfang Startseite Kapitelanfang Inhaltsverzeichnis GPL   weiter