Inter-File Branching
Ein praktisches Verfahren zur Darstellung von Varianten
Christopher Seiwald
Perforce Software
Kurzfassung
Marktübliche Systeme für das Software-Konfigurationsmanagement (SCM) bezeichnen Varianten im selben Namensbereich (namespace) wie Revisionen. Die Varianten - d.h. die alternativen Implementierungen eines Konfigurationsobjekts, welche parallel existieren müssen - und Revisionen - d.h. die fortlaufenden Verbesserungen der einzelnen Varianten im Laufe der Zeit - bilden eine zweidimensionale Versionsstruktur eines Konfigurationsobjekts, den so genannten Versionsbaum. In der Regel hat ein Konfigurationsobjekt also zwei Namen: einen für das Objekt und einen für die Version.In dieser Arbeit wird ein alternativer Ansatz vorgestellt: nämlich die Variante durch den Namen des Konfigurationsobjekts zu identifizieren, sodass für den Versions-Namensbereich nur ein linearer Satz von Revisionen verbleibt. Da dieses Verfahren in einem Arbeitssystem verwirklicht wurde, wo die Konfigurationsobjekte Software-Quelldateien sind, heißt es Inter-File Branching. Branching (Verzweigung) bezeichnet das Erstellen von Varianten, files (Dateien) sind die Konfigurationsobjekte, und inter-file besagt, dass es sich bei den Varianten um eigene Dateien handelt.
1. Einführung
Die vorliegende Arbeit beschreibt einen neuen Mechanismus zum Umgang mit Dateivarianten. Zunächst wird auf die beiden grundlegenden Aspekte des aktuellen Verfahrens eingegangen - das Benennen und Erstellen der Varianten - und die praktischen Einschränkungen dieser Aspekte werden erläutert. Anschließend wird ein neuer Ansatz namens Inter-File Branching vorgestellt, der ohne diese Schwächen auskommt. Es folgt eine detaillierte Beschreibung dieses Mechanismus. Abschließend werden einige empirische Beobachtungen zur Verwendung von Inter-File Branching dargelegt.
2. Verzweigung des Versionsbaums
2.1. Die Version benennt die Variante
Eine Datei wird in der Regel durch zwei Namen bezeichnet: den Namen der Datei selbst und den Namen der Dateiversion. Die Version wiederum besteht aus zwei Informationen: dem Namen der Variante und dem Namen der Revision der Variante. Die Variante entspricht einer der alternativen Implementierungen, die parallel existieren, während die Revision eine der Implementierungen einer Variante ist, die im Laufe der Zeit weiterentwickelt wurde [4]. Die erste Revision einer neuen Variante ist genau genommen meist eine Revision einer anderen Variante - man spricht von einer Verzweigungsstelle. Die Varianten und ihre Revisionen sind über Verzweigungsstellen miteinander verbunden und bilden so den Versionsbaum. Jede Variante ist ein Zweig des Baumes und jede Revision ein Knotenpunkt auf dem Zweig.
In SCCS [5] und RCS [8] (und den vielen Dutzend Systemen, die auf diesen Tools basieren) werden die Varianten (als "branches", also "Zweige" bezeichnet) mit Zahlenpaaren benannt, und die Revision mit einem weiteren Zahlenpaar. Der Name des "Stammzweigs" ("trunk branch") ist leer. Beispielsweise ist 1.2.2.1.1.3 die Revision 1.3 von Variante 1.2.2.1, die wiederum Revision 2.1 von Variante 1.2 ist, die wiederum Revision 1.2 des Stammes ist. Verständlicherweise kann es für Benutzer abschreckend sein, sich die Bedeutung dieser Zahlen merken zu müssen, sodass für wichtige Versionen häufig symbolische Namen gewählt werden.
Das Produkt ClearCase von Atria [1] verzichtet ganz auf Revionsnummern und zeigt dem Benutzer einen hierarchischen Versionsnamen. Beispielsweise ist main/release2/bugfix/3 Revision 3 des Zweiges "bugfix", der zuvor aus dem Zweig "release2" entstanden ist, der wiederum aus dem Hauptstamm entstanden ist. Diese Benennung lässt sich wesentlich leichter im Gedächtnis behalten als das Nummerierungssystem von SCCS. Allerdings lässt sich bemängeln, dass die Verzweigungsstelle nicht explizit bezeichnet ist.
Der Ansatz, Varianten im Versions-Namensbereich darzustellen, ist mit mehreren Nachteilen behaftet:
Zwei Hierarchien. Jede Dateivariante wird mit dem Produkt zweier hierarchischer Namen bezeichnet - dem Namen der Datei und dem Namen der Variante. Ein zugegebenermaßen subjektiver Kritikpunkt dieses Verfahrens ist, dass es den Benutzern unter Umständen nicht gelingt, sich die Konfigurationen visuell zu veranschaulichen. Theoretisch macht die Funktionalität von SCM-Systemen dies zwar überflüssig, doch in der Praxis müssen Ingenieure, die mit mehreren Releases komplexer Softwareprodukte arbeiten, häufig in der Lage sein, sich die "Form" des Dateibaumes vorzustellen.
Besonders undurchsichtig kann die Struktur werden, wenn man nach Bedarf Varianten erstellt. Ein solcher Mechanismus speichert ein Update einer Version nicht als neue Revision derselben Variante, sondern als erste Revision einer neu erstellten Variante. Das Ergebnis ist, dass nach einiger Zeit zahlreiche Dateien viele identische Varianten aufweisen. Außerdem können wichtige Konfigurationen unterschiedlich benannte Varianten für verschiedene Dateien enthalten.
Unterschiedliche Semantik. Die Nutzung eines Namensbereichs für Dateien und eines anderen für die Varianten dieser Dateien birgt ein Dilemma für Benutzer marktüblicher SCM-Systeme, da diese beiden Namensbereiche von unterschiedlicher Semantik unterstützt werden. Speziell die Unterstützung für die automatische Integration des Deltas ist in der Regel dem Versions-Namensbereich zugeordnet: Nur Deltas zwischen zwei Varianten können integriert werden. (Unter "Delta" versteht man die Änderungen zwischen zwei aufeinander folgenden Revisionen.) Andererseits kann jeweils nur eine Variante einer Datei dem Benutzer gezeigt werden.
Damit man also das Delta zwischen zwei Varianten integrieren kann, muss es sich um Varianten derselben Datei handeln. Umgekehrt kann der Benutzer nur dann auf zwei Varianten gleichzeitig zugreifen, wenn es sich um unterschiedliche Dateien handelt. Es gibt mehrere Situationen aus der Praxis, in denen diese nicht unterstützte Kombination wünschenswert wäre: in Client-Server-Systemen, wo die Client- und Server-Implementierungen einer Protokollmaschine ähnlich, aber nicht identisch sind; in Systemen mit mehreren Plattformen, wo betriebssystemspezifische Dateien ähnlich, aber nicht identisch sind; in Systemen, die zu einer anderen Programmiersprache migriert werden, wo z.B. Implementierungen in C und C++ vorläufig synchron bleiben müssen. In allen diesen Fällen sind die Dateien zwar Varianten voneinander, doch in praktischer Hinsicht handelt es sich um getrennte Dateien.
Starke Gewichtung der Hauptlinie. Der Versions-Namensbereich wird nach dem Prinzip dargestellt, dass eine der Varianten die Hauptlinie ist, von der alle anderen abgeleitet sind. Diese starke Gewichtung der Hauptlinie ist im Anfangsstadium eines einzelnen Softwareprojektes durchaus sinnvoll, wird aber nur selten der Struktur vorhandener, ausgereifter Produkte gerecht (besonders wenn diese mit unzureichendem SCM begonnen wurden). Meistens haben solche Produkte mehrere "Hauptlinien" derselben Quelldateien, die sich jeweils getrennt aktiv entwickeln.
Die Komplexität der Entwicklung mit mehreren Hauptvarianten kann die Benutzer zwingen, getrennte Repositorien für Dateien anzulegen, die ansonsten Varianten voneinander im selben Repositorium wären. In der Regel muss dadurch auf die gesamte automatische Zusammenführung und Erfassung durch das SCM-System verzichtet werden.
2.2. Erstellen von Varianten
Das gängige Verfahren zur Darstellung von Varianten geht mit dem verbreiteten Verfahren zu ihrer Erstellung einher: Für jede Datei wählt man eine vorhandene Version aus, die als Ausgangspunkt für eine neue Variante markiert wird. Gewöhnlich kennzeichnet der Benutzer die vorhandene Version mit einem symbolischen Namen, um nicht die Variante und Revision jeder Datei einzeln auflisten zu müssen. Auf ähnliche Weise erhält auch die neue Variante einen symbolischen Namen, auf den man in Zukunft leicht Bezug nehmen kann.
Benutzer reden oft von "einem Zweig" und meinen damit alle Dateien mit einem gemeinsamen Variantennamen. Doch bei der Erstellung der Varianten wird die Semantik eines Kollektivs nicht unterstützt: Es sind nur Varianten vorhandener Dateien vorgesehen, nicht von Dateien, die möglicherweise in Zukunft erstellt werden. Sollen die Änderungen eines Zweiges in einen anderen überführt werden, so ist ein zusätzlicher Schritt erforderlich, um neue Varianten neuer Dateien anzulegen. Wichtiger noch: Da die Varianten aus Informationen erstellt wurden, die nur eine markierte Version der jeweiligen Datei waren, kann man aus externer Sicht gar nicht feststellen, ob eine neue Datei auch eine entsprechende Variante aufweisen sollte.
Einige SCM-Systeme begegnen diesem Problem, indem sie Container als Konfigurationsobjekte behandeln und davon ebenfalls Varianten erstellen. Dieses Verfahren kann allerdings die Komplexität deutlich steigern und einige Verwirrung stiften: Abgesehen von der Erstellung zusätzlicher Namensbereiche, die sich auf die Bezeichnung einzelner Versionen auswirken, ist die Erstellung einer Variante beim Erstellen einer neuen Datei auch weiterhin nicht automatisch.
3. Inter-File Branching
Das Inter-File Branching ist ein alternativer Ansatz, der potenzielle Vorteile gegenüber der Verzweigung des Versionsbaumes (Version-Tree Branching) bietet. Das Grundkonzept ist, dass das Erstellen einer Variante der Prozessvervielfältigung (fork) in UNIX vergleichbar sein sollte: Eine neue Datei wird erstellt, die zum Original im Hinblick auf die anfänglichen Inhalte und den bisherigen Verlauf in Bezug steht, jedoch eine völlig offene Zukunft hat.
Dieses Modell ähnelt der Art, wie Benutzer ohne jede SCM-Unterstützung typischerweise ihre Software verzweigen müssen: Sie kopieren die Dateien und sorgen sich vorerst nicht um eine spätere Zusammenführung. Der Unterschied zwischen diesem primitiven Verfahren und dem Inter-File Branching besteht darin, dass bei Letzterem sowohl das anfängliche Kopieren als auch das spätere Zusammenführen automatisiert sind. Im Kern geht es beim Inter-File Branching vorwiegend darum, die praktische Unterstützung für Varianten - Deltas zusammenzuführen und den Verlauf der Zusammenführung zu erfassen - auf Einzeldateien auszuweiten.
Beim Inter-File Branching sind Varianten unterschiedlich benannte Dateien. Der Name dieser Dateien umfasst sowohl den herkömmlichen Dateinamen als auch den Variantennamen. Die genaue Benennung bleibt jedoch dem Benutzer überlassen. Beispielsweise kann eine Datei /release2.1/database/src/btree.c eine Variante von /patch2.1.5/database/src/btree.c sein oder /x/y/z eine Variante von /a/b/c/d.
Das Inter-File Branching basiert auf einem vertrauten Verfahren: dem Kopieren von Objekten, um Varianten davon zu erstellen. Dadurch lässt sich auf natürliche Weise die Beziehung einer neuen Variante zum Original ausdrücken: indem man ihr einen ähnlichen Namen gibt. Beispielsweise kann eine Datei foo.c einfach in foo.c.bak kopiert werden. Ein noch besseres Beispiel ist das Kopieren von mainline/src/* in bob/src/*. Die Dateien von Bob sind Varianten der Hauptlinie, und ihre Namen spiegeln diese Beziehung wider.
Erfolgt das Kopieren nicht im privaten Arbeitsbereich des Benutzers, sondern im SCM-Repositorium, so ist das Ergebnis ein Repositorium-Namensbereich, den sich der Benutzer leicht visuell veranschaulichen kann. Beim Inter-File Branching hat der Benutzer einen einzigen Zugriffsweg, um die Variante einer Datei zu identifizieren, was die "Form" der Konfiguration sehr transparent macht. Im obigen Beispiel kann sich Bob ganz einfach merken, dass sich die Konfiguration, die seine Arbeit beschreibt, in src/bob/* im Repositorium befindet.
Da ein SCM-System, das Inter-File Branching unterstützt, Varianten als getrennte Dateien behandelt, ermöglicht es eine automatische Zusammenführung und Erfassung zwischen beliebigen Paaren von Dateien. Die Semantik für Varianten kann sogar im Nachhinein auf Dateien angewendet werden, die ursprünglich nicht zueinander in Bezug standen. Somit kann man zwei beliebige Dateien auswählen (etwa Dateien, die bisher nicht mit SCM verwaltet wurden), und beginnen, sie als Varianten voneinander zu behandeln.
Beim Inter-File Branching haben Varianten unterschiedliche Namen, zwischen denen keinerlei Ähnlichkeit bestehen muss. Somit kann man eine Variante einer ganzen Konfiguration erstellen (d.h. Varianten aller Dateien der Konfiguration) und den Namensbereich dabei komplett umstrukturieren, indem man die neu erstellten Varianten nach dem gewünschten Schema benennt. Dies kann sich in verschiedenen Situationen als nützlich erweisen, insbesondere wenn aus einer Software ein neues Projekt abgezweigt werden soll, das den gleichen Code verwendet: Es ist gut denkbar, dass das neue Projekt die Kopie der Software mit entsprechenden Anpassungen benötigt.
Das Inter-File Branching verknüpft Varianten über den Namensbereich der Dateien. Ganze Konfigurationen können einander zugeordnet werden, indem man die Beziehung zwischen den Namen ihrer Dateien ausdrückt. Wenn dieser Ausdruck der Beziehung sich auf eine natürliche Struktur der Software stützt, kann er recht kompakt sein. Ist beispielsweise Bobs Code eine Variante des Codes der Hauptlinie, so ist bob/src/* eine Variante von mainline/src/*. Durch diesen Ausdruck werden nicht nur vorhandene Dateien verknüpft, sondern auch zukünftige Dateien im selben Namensbereich.
Da der Versions-Namensbereich nicht mehr den Namen der Variante enthält, kann er pro Datei auf einen linearen Satz von Revisionsnummern (beginnend mit 1) beschränkt werden. Wichtige Konfigurationen sind daher häufig die Tip-Revisionen (neueste Revision mit der höchsten Nummer) der Dateien in einem bestimmten Teil des Namensbereichs. Beispielsweise besteht Bobs neueste Arbeit aus den Tip-Revisionen der Dateien mit dem Namen bob/src/*.
3.1. Algorithmus des Inter-File Branching
Die Semantik der automatisierten Zusammenführung stützt sich auf die Prämisse, dass jedes beliebige Delta oder alle Deltas einer Quelldatei ("Quelle") sinnvollerweise mit den Inhalten einer Zieldatei ("Ziel") zusammengeführt werden können. Dazu zählt auch das erste Delta zwischen der leeren Datei und ihrer ersten Revision. Der wesentliche Unterschied zwischen der Quell- und Zieldatei ist der Name. Der Benutzer wählt eine Quelle, eine Teilmenge ihrer Deltas und ein Ziel. Anschließend wird folgende Logik angewendet:
- Grenzen die Deltas nicht fortlaufend aneinander an, so werden sie in einzelne fortlaufende Bereiche aufgeteilt. Die verbleibende Logik wird getrennt auf diese Bereiche angewendet.
- Wenn das Ziel nicht existiert, wird es aus den Inhalten der Quelle in der höchsten ausgewählten Revision erstellt. Diesen Vorgang bezeichnet man als "Verzweigung" ("Branching") - das Erstellen einer neuen Variante identischen Inhalts.
- Ist das Ziel vorhanden, so führt der Benutzer die aktuellen Inhalte des Ziels mit den Inhalten der Quelle in der höchsten ausgewählten Revision zusammen. Das Ergebnis dieser Zusammenführung ist die nächste fortlaufende Revision des Zieles. Wenn man eine geeignete Grundrevision findet, lässt sich die Zusammenführung mit einem gewöhnlichen diff/merge-Algorithmus automatisieren. Die Basis für automatisierte Zusammenführungen ist die Revision der Quelle, die sich eine Stufe unter der niedrigsten ausgewählten Revision befindet. Ist die niedrigste ausgewählte Revision die erste Revision der Quelle, so gibt es keine Basis, und der Benutzer muss sich entscheiden, die Inhalte des Zieles durch die der Quelle zu ersetzen, das Ziel unverändert zu lassen oder Quelle und Ziel manuell zusammenzuführen.
- In jedem Fall wird dauerhaft festgehalten, dass das Ziel (in seiner neuen Revision) jetzt die ausgewählten Deltas der Quelle enthält. Die Quell- und Zieldatei können nun als Varianten voneinander betrachtet werden.
3.2. Integrationsverlauf
Unter dem Integrationsverlauf eines strukturierten Dateipaares versteht man die Geschichte der Überführung von Deltas von einer Datei in die andere. Ein solcher Verlauf erfüllt zwei äußerst wichtige Funktionen: Erstens weist er (wenn er zeigt, dass Deltas überführt wurden) darauf hin, dass das Ziel eine Variante der Quelle ist. Zweitens kann aus dem Integrationsverlauf errechnet werden, welche Deltas noch überführt werden müssen. Das erspart es dem Benutzer, für jede Zusammenführung die Quelldeltas auswählen zu müssen.
Überdies kann der Integrationsverlauf zur Dokumentation und betrieblichen Kontrolle verwendet werden. Durch transitiven Abschluss lässt sich für jede Revision jeder Datei berechnen, welche Deltas anderer Dateien sie aufgrund von Zusammenführungen der ersten, zweiten, dritten usw. Generation enthält.
3.3. Zweigansichten
Wenn Variantendateien über ihre Namen verknüpft werden sollen, muss diese Beziehung auf eine bestimmte Weise ausgedrückt werden. Dazu dienen Zweigansichten (branch views). Eine Zweigansicht ist eine benannte Eins-zu-eins-Zuordnung zwischen den Namen zweier Dateisätze: der Quelle und dem Ziel des geplanten Zweiges. Beim Anwenden der Zweigansicht wird der Name jeder bekannten Datei durch die Ansicht als mögliche Quelle zugeordnet. Die so entstandenen Paare aus Quelle und Ziel bestimmen die zu verzweigenden oder zusammenzuführenden Dateien.
Bei diesem Mechanismus sind zwei wichtige Aspekte zu beachten. Erstens: Zwar ermöglicht jede Zweigansicht nur Eins-zu-eins-Zuordnungen zwischen ihren Quellen und Zielen, doch kann es mehrere Zweigansichten mit identischen Quellen und/oder Zielen geben. Somit lassen sich aus einer Quelle viele verschiedene Ziele abzweigen, und dasselbe Ziel kann (vielleicht weniger intuitiv verständlich) die Variante mehrerer Quellen sein. Zweitens: Die Zuordnung wird nur auf Anforderung des Benutzers ausgeführt, nicht etwa durch Erstellen oder Aktualisieren potenzieller Quellen. Nur wenn der Benutzer explizit Zieldateien erstellt oder zusammenführt, wird die Zweigansicht angewendet.
Zweigansichten dokumentieren lediglich die Absicht eines Benutzers, in einem Satz von Zielen einen Satz von Quellen widerzuspiegeln. Die eigentliche Zusammenführung erfolgt durch die Anwendung der Zweigansicht. Auf Anforderung des Benutzers werden die Namen aller vorhandenen Dateien durch die Ansicht projiziert, um eine Liste von Paaren aus Quelle und Ziel zu erstellen. Bei jedem Paar wird der Integrationsverlauf berücksichtigt, und dem Benutzer werden ergänzende Integrationsvorgänge vorgeschlagen. Ziel dieser Änderungsvorschläge - Erstellen der ersten Revision neuer Varianten, Erstellen neuer Revisionen vorhandener Varianten, Löschen von Varianten, deren Quellen gelöscht wurden - ist es, den Zielsatz mit den Deltas des Quellsatzes in Einklang zu bringen. Ob die Änderungen ganz übernommen, etwas modifiziert oder einfach ignoriert werden, bleibt selbstverständlich dem Benutzer überlassen. Nur in seltenen Fällen ist es wünschenswert, zwei Konfigurationen absolut identisch zu halten.
3.4. Berechnen der Basis für die Zusammenführung
Es wurde bereits erwähnt, dass sich aus dem Integrationsverlauf, der die Überführung von Deltas einer Quelldatei in eine Zieldatei im Einzelnen festhält, genau berechnen lässt, welche Deltas noch zu überführen sind. Ein Produkt dieser Berechnung ist nützlich als Ausgangsversion für einen Dreiweg-diff/merge-Vorgang. Es handelt sich um die Revision der Quelle vor der ersten zu überführenden Revision.
Das übliche Verfahren zum Abgleich von Änderungen einer Datei besteht darin, eine gemeinsame Vorgängerversion zu finden und als Basis für einen diff/merge-Prozess zu verwenden. Bei einem solchen Prozess werden die textlichen Unterschiede zwischen der Basis und allen Revisionen der Variante berechnet und anschließend überführt. Er wurde in einer Vielzahl von Tools implementiert, vom einfachen rcsmerge-Programm von RCS bis hin zu raffinierten GUIs, die farbig veranschaulichen, welche Textzeilen sich in den einzelnen Versionen geändert haben.
In den meisten Systemen dient die ursprüngliche Verzweigungsstelle als gemeinsame Vorgängerversion. Je weiter sich jedoch der Text der beiden Varianten von der Vorgängerversion wegentwickelt, desto häufiger kommt es leider dazu, dass Änderungen der Varianten in Konflikt zu stehen oder sich zu überlappen scheinen. Bei jeder Zusammenführung der Varianten wird der Benutzer daher wieder mit textlichen Konflikten konfrontiert, die bereits bei den vorherigen Zusammenführungen gelöst wurden. Ein weiterer Ansatz ist, das höchste Delta der Quelle zu protokollieren, das bereits überführt wurde, wie das ClearCase mit Hyperlinks tut. Dabei geht man jedoch davon aus, dass Deltas immer der Reihe nach integriert werden. Es gibt jedoch Fälle, wo ein bestimmtes Delta mit einer Fehlerkorrektur Vorrang hat, die vorherigen und folgenden Deltas aber noch zurückgestellt werden.
Durch die Protokollierung der einzelnen überführten Deltas verfügt man immer über die optimale Basis für die Zusammenführung, nämlich die Revision der Quelle vor der ersten zu überführenden Revision. Der Unterschied zwischen der Spitze der Quelle und der Basis ist damit so gering wie möglich, sodass die Zusammenführung entsprechend unkomplizierter ist.
3.5. "Reine" Integrationen
Da der Integrationsverlauf Deltas, die in eine andere Variante überführt wurden, einzeln protokolliert, kann es einen speziellen Vorteil bringen, reine Integrationen zu erkennen. Als rein wird eine Integration bezeichnet, wenn die neue Revision des Zieles nur Deltas einer einzigen Quelle enthält. Diese Unterscheidung ist wichtig, da ein Delta, das aus einer reinen Integration entstanden ist, nicht wieder in die Quelle überführt werden muss.
Ohne Integrationsverlauf geht die Information verloren, dass das neue Delta einer Zielvariante nur durch die Zusammenführung von Deltas einer anderen Variante entstanden ist. Bei einer späteren automatischen Zusammenführung wird das neue Delta wieder gefunden, und es wird versucht, es in die Quelle zu überführen. Wurde das Delta zuvor unverändert übernommen, so dürfte die Zusammenführung ohne Bewandtnis sein und den Benutzer kaum betreffen. Wenn aber bei der Überführung des Deltas ins Ziel Konflikte gelöst oder andere Änderungen vorgenommen wurden, wird der Benutzer damit bei der Rücküberführung wieder konfrontiert.
Werden im Integrationsverlauf reine Integrationen protokolliert, so lässt sich bei der automatischen Zusammenführung ausschließen, dass jemals Deltas wieder in die Quelle überführt werden. In der Praxis muss der Benutzer dazu explizit angeben, dass es sich um eine reine Integration handelt: Während der Konfliktlösung kann er andere Änderungen vornehmen, die möglicherweise wieder in die Quelle überführt werden müssen. Ist die Revision rein geblieben, so bestätigt er dies abschließend. Diese Information wird im Integrationsverlauf festgehalten. In Zukunft lässt sich so verhindern, dass das Delta automatisch wieder in die Quelle überführt wird.
3.6. Verwalten des Namensbereichs
Wenn der hierarchische Namensbereich von Dateien gleichzeitig auch als Variantenname dienen soll, so muss im Dateinamen ausreichend Platz für den Variantennamen verbleiben. Dies mag zwar weitgehend subjektiv sein, doch in einfachen Fällen haben wir festgestellt, dass das Voranstellen des Variantennamens zu Beginn des Dateinamens die gesamte Dateistruktur klar erkennen lässt. Beispielsweise ist für Benutzer recht leicht nachvollziehbar, dass sich die Hauptlinie der Entwicklung unter /main/src/... befindet, während das neueste Release in /release2.1/src/... usw. abgezweigt wurde.
3.7. Client-Ansichten
Es ist zu beachten, dass der Name einer Datei im SCM-Repositorium nicht mit ihrem Namen im Dateisystem des Benutzers übereinstimmen muss. Muss die Variante im Namen codiert sein, so ist es wünschenswert, diese Information vom Dateinamen trennen zu können, wenn die Datei an die Benutzer übergeben wird. Dazu dient die Client-Ansicht: Jeder Client-Arbeitsbereich besitzt eine Ansicht (ähnlich einer Zweigansicht), die die Dateinamen im Repositorium auf das lokale Dateisystem des Benutzers projiziert. In einem einzigen System (der Client-Ansicht) sind damit nicht nur die Dateien, sondern auch die vom Benutzer gewünschten Varianten definiert. Um zwei unterschiedliche Varianten auf den Client zu projizieren, müssen diese nur auf dem Client unterschiedliche Namen erhalten.
3.8. Varianten als virtuelle Kopien
Wenn das Verzweigen einer Datei gleichbedeutend mit dem Kopieren im Repositorium ist, ist auf ausreichenden Speicherplatz zu achten. Eine einfache Abhilfe besteht darin, eine virtuelle Kopie zu erstellen, wobei die gerade abgezweigte Datei die Inhalte der Originaldatei nutzt. Dafür ist eine Stufe der Indirektion zwischen dem Namensbereich des Repositoriums und dem eigentlichen, zugrunde liegenden Objektspeicher nötig. Wird der Zweig um eine neue Revision ergänzt, so kann die abgezweigte Datei eine eigene Einheit im Objektspeicher erlangen.
Durch die Arbeit mit virtuellen Kopien kann man den Speicherbedarf für Varianten reduzieren. Es ist nur noch ein Datensatz für die neue Variante vorhanden, der auf die Originaldatei verweist. Der Aufwand dafür entspricht mehr oder weniger dem für herkömmliche Varianten.
Virtuelle Kopien sind auch geeignet, um eine Variante explizit mit einer anderen zu synchronisieren. Möchte ein Benutzer einen Zweig wieder in den Stamm integrieren, sodass beide identisch sind, können Zweig und Stamm an der betreffenden Stelle auf denselben Inhalt verweisen.
4. Erörterung
4.1. Vergleich mit vorhandener Technologie
In der vorliegenden Arbeit wurde das Inter-File Branching direkt dem Versionsbaum-Modell gängiger Systeme wie RCS und ClearCase gegenübergestellt. Für die Unterstützung von Varianten gibt es noch zwei weitere Ansätze, die eine Erwähnung lohnen.
4.1.1. Baseline-Modell
Das Baseline-Modell [2] kann als stark vereinfachter Versuch des Inter-File Branching verstanden werden. Streng genommen ist eine Baseline (Referenzkonfiguration) einfach eine Konfiguration, die als Grundlage für zukünftige Änderungen dient. Üblicherweise kopiert man die Inhalte der Konfiguration jedoch und macht die kopierten Dateien zur Baseline. In dieser Hinsicht ist das Modell dem Kopieren beim Inter-File Branching vergleichbar, zumal die neue Baseline einen Namen erhält, der sie von der Originalkonfiguration unterscheidet.
Im Vergleich zum Inter-File Branching ist das Baseline-Modell mit drei Nachteilen behaftet: Erstens ist die Beziehung zwischen den Namen unveränderlich. In der Regel sind die Baselines benannt, während die Namen ihrer Dateien über die Baselines hinaus festgelegt sind. Zweitens ist eine Baseline ein vordefinierter Satz von Dateien, in der Regel ein "Projekt" oder "Produkt". Es können keine Varianten von nur einer oder zwei Dateien erstellt werden. Drittens ist der Integrationsverlauf, sofern überhaupt vorhanden, im Baseline-Modell von vergleichsweise geringem Nutzen. So werden etwa keine einzelnen Deltas erfasst, die von einer Variante in eine andere überführt wurden.
4.1.2. Modell der Änderungsmengen/ICE-Modell der Versionsmengen
Das Modell der Änderungsmengen [7] und das Modell der Versionsmengen in ICE [10] sind gewissermaßen die Antithese des Inter-File Branching. In keinem dieser Modelle bilden Varianten und Revisionen einen Baum benannter Versionen der einzelnen Dateien. Vielmehr verfügt jede Datei über einen Fundus an Deltas, die willkürlich angewendet werden können, um eine (möglicherweise sinnlose) Version zu produzieren. Im Modell der Änderungsmengen bezeichnet man die anzuwendende Kombination aus Deltas als "Änderungsmenge". Eine Änderungsmenge selbst kann als Teil einer benannten Konfiguration protokolliert werden. Im Modell der Versionsmengen in ICE besitzen die Deltas Attribute (als "Features" bezeichnet). Zur Auswahl sucht man nach den Deltas mit der gewünschten Kombination aus Attributen.
Während beide Modelle, Änderungsmengen und Versionsmengen in ICE, im Vergleich zum Versionsbaum-Modell wohl recht gut abschneiden, unterscheiden sie sich deutlich vom Inter-File Branching. Das Inter-File Branching behandelt die Varianten im Repositoriums-Namensbereich als getrennt, sodass die Benutzer sie als unabhängige Dateien einsehen und bearbeiten können. Bei Änderungs- und Versionsmengen dagegen werden alle Varianten einer Datei einer einzigen Einheit zugeordnet. Die Benutzer müssen bei jeder Interaktion die gewünschte Version auswählen (oder erstellen). Um die Unterschiede anhand eines Kontinuums zu beschreiben: Beim Inter-File Branching lassen sich wichtige Konfigurationen nur durch die Namen der zugehörigen Dateien beschreiben; bei Versionsbäumen müssen Varianten explizit benannt werden, da sich wichtige Konfigurationen möglicherweise nicht im Stamm befinden; bei Änderungs- und Versionsmengen muss bei wichtigen Konfigurationen die Änderungsmenge bzw. Featureliste explizit festgelegt werden.
4.2. Empirische Bewertung
Eine frühere Version des Inter-File Branching-Modells wurde bei der Firma Ingres Corporation als Teil eines internen SCM-Systems namens Piccolo [6] implementiert. Die Zweigansichten und der detaillierte Integrationsverlauf des aktuellen Modells waren damals noch nicht vorhanden. Das Erstellen der Varianten war daher aufwändig: Der Benutzer musste die einzelnen zu verzweigenden Dateien auflisten, und manchmal beharrte das System (wiederholt) darauf, Deltas, die in eine andere Datei überführt worden waren, wieder in die ursprüngliche Datei zu überführen.
Dennoch erwies sich das Inter-File Branching als solide Grundlage für parallele Entwicklungsarbeiten und Releases. Mehrere Hundert Entwickler und andere Ingenieure auf drei Kontinenten unterstützten mit dem Verzweigungsmechanismus des Piccolo-Systems etwa ein Dutzend Produkte mit insgesamt rund 12.000 Dateien. Zu jedem beliebigen Zeitpunkt wurden ein Dutzend Releases gleichzeitig bearbeitet.
Zur Verzweigung wurde meist die erste Komponente des Namens der einzelnen Dateien im Repositorium modifiziert. Die Hauptlinie diente der Entwicklung und wurde als "main" bezeichnet. Aus ihr wurden zahlreiche Zweige für einzelne Entwickler oder Gruppen abgeleitet, die jeweils nach dem Entwickler oder Projekt benannt waren. Auch bei jedem wichtigen Release wurde die Hauptlinie verzweigt, wobei man den Zweig nach dem Release benannte. Diese wichtigen Releases wurden anschließend ihrerseits zu untergeordneten Hauptlinien, aus denen Zweige für Patches abgeleitet wurden.
Einer der unerhofften Vorteile des Inter-File Branching war es, dass die Entwickler Zweige mit anderer Baumstruktur als die Hauptentwicklungslinie erstellen konnten, da die Zweige als Beziehung zwischen den Namen zweier beliebiger Dateien ausgedrückt wurden. So konnten die Entwickler ihre Produkte in einer Umgebung produzieren und verwalten, die auf ihre Anforderungen abgestimmt war. War zum Beispiel eine Gruppe für Verzeichnisse verantwortlich, die im Namensbereich der Hauptlinie "weit auseinander" lagen, so konnte sie diese im Zweig der Gruppe vereinigen.
Das aktuelle Modell des Inter-File Branching, wie in dieser Arbeit beschrieben, wurde in einem System implementiert, das auf dem Markt erhältlich ist: Perforce. Perforce wurde in dem Bemühen entwickelt, auf der Semantik des Inter-File Branching aufzubauen und dabei die Mängel der Piccolo-Implementierung zu überwinden. Perforce ist ein neues System, doch bisher hat sich sein Modell als flexibel, einsatzfähig und recht vollständig erwiesen. Es ist zu erwarten, dass sich der protokollierte Integrationsverlauf als wahrer Schatz von Informationen für große, ausgereifte Softwareprodukte erweisen wird. Bisher liegen allerdings noch keine Erfahrungswerte zu einem solchen Produkt vor.
5. Schlussfolgerung
Die große Verbreitung des herkömmlichen Umgangs mit Varianten täuscht über ein im Wesentlichen unnatürliches Modell hinweg. Erfahrene Benutzer gängiger SCM-Systeme sind zwar mit der Verwendung eines gemeinsamen Namensbereichs für Variante und Revision durchaus vertraut. Doch die grundlegende Schwäche dieses Ansatzes hat nach und nach dazu geführt, dass in seiner Funktionalität insgesamt Lücken entstanden sind. Das Inter-File Branching dagegen basiert auf einem natürlichen Modell - dem Kopieren und Umbenennen von Softwaredateien - das durch eine Reihe praktischer Verfahren einsatzfähig wird. Erhält es die Möglichkeit, sich zu bewähren, so könnte das Inter-File Branching der Funktionalität des herkömmlichen Umgangs mit Varianten Konkurrenz machen.
6. Bibliografie
[1] Atria Corporation, ClearCase Concepts Manual Natick Massachusetts, 1994
[2] Bersoff, Henderson, Siegel, Software Configuration Management. Prentice-Hall, 1980.
[3] Susan Dart, The Past, Present, and Future of Configuration Management. Technical Report CMU/SEI-92-TR-8, Software Engineering Institute, Carnegie Mellon University, 1992.
[4] Stephen MacKay, The State of the Art in Concurrent, Distributed Configuration Management. Proceedings of the 5th International Workshop on Software Configuration Management, Seattle, WA, 1995.
[5] Rochkind, The Source Code Control System. IEEE Transactions on Software Engineering, Band SE-1, Dezember 1975.
[6] Roger Rohrbach und Christopher Seiwald, Galileo: A Software Maintenance Environment. Proceedings of the International Workshop on Software Version and Configuration Control, Grassau, 1988.
[7] Software Maintenance and Development Systems (SMDS). Aide-de-Camp Users Manual, Concord Mass, 1993.
[8] Walter Tichy, RCS -- a system for version control. Software -- Practice and Experience, Juli 1985.
[9] Walter Tichy, Tools for Software Configuration Management. Proceedings of the International Workshop on Software Version and Configuration Control, Grassau, 1988.
[10] Andreas Zeller, Smooth Operations with Square Operators -- The Version Set Model in ICE. Informatik-Bericht Nr. 95-08, Technische Universität Braunschweig, 1995.