Diese Dokumentation wurde zur Beschreibung der Serie 1.6.x von Subversion erstellt. Falls Sie eine unterschiedliche Version von Subversion einsetzen, sei Ihnen dringend angeraten, bei http://www.svnbook.com/ vorbeizuschauen und stattdessen die zu Ihrer Version von Subversion passende Version dieser Dokumentation heranzzuiehen.
Es gibt zahlreiche unterschiedliche Anwendungsfälle für das Verzweigen und svn merge; dieser Abschnitt beschreibt die verbreitetesten.
Am häufigsten wird Versionskontrolle in der Softwareentwicklung verwendet, so dass wir an dieser Stelle kurz zwei der gebräuchlichsten Verzweigungs- und Zusammenführungsmuster vorstellen, die von Entwicklerteams benutzt werden. Falls Sie Subversion nicht in der Softwareentwicklung verwenden, können Sie den Abschnitt getrost überspringen. Falls Sie ein Softwareentwickler sind, der Versionskontrolle das erste Mal verwendet, sollten Sie gut aufpassen, da es sich bei diesen Mustern um bewährte Vorgehensweisen handelt, die von erfahrenen Menschen empfohlen werden. Diese Prozesse sind nicht spezifisch für Subversion; sie sind anwendbar auf alle Versionskontrollsysteme. Trotzdem mag es hilfreich sein, wenn sie anhand von Subversion erklärt werden.
Die meiste Software hat einen typischen Lebenszyklus: Erstellung, Test, Freigabe und wieder von vorne. Bei diesem Prozess gibt es zwei Probleme. Erstens müssen Entwickler neue Funktionen schreiben, während das Qualitätssicherungsteam sich Zeit zum Testen der vermeintlich stabilen Software nimmt. Die Arbeit kann allerdings nicht liegenbleiben während die Software getestet wird. Zweitens muss das Team fast immer ältere, bereits an den Kunden herausgegebene Software unterstützen; falls im neuesten Quelltext ein Fehler entdeckt wird, besteht der Fehler wahrscheinlich auch in der herausgegebenen Version. Die Kunden möchten dann eine Fehlerbehebung, ohne auf ein größeres, neues Release zu warten.
Hier kann Versionskontrolle helfen. Die typische Vorgehensweise ist wie folgt:
Entwickler übergeben alles Neue an den
Stamm. Tägliche Änderungen werden an
/trunk
übergeben: neue Funktionen,
Fehlerbehebungen usw.
Der Stamm wird in einen
„Release“-Zweig kopiert. Wenn das
Team der Auffassung ist, dass die Software reif für eine
Freigabe ist (z.B. Release 1.0 ), kann
/trunk
nach
/branches/1.0
kopiert werden.
Die Teams arbeiten parallel. Ein
Team beginnt, den Release-Zweig sorgfältig zu testen,
während ein anderes Team mit der Arbeit (z.B. für Release
2.0) in /trunk
fortfährt. Falls hier
oder dort Fehler entdeckt werden sollten, werden die
Fehlerbehebungen nach Bedarf hin oder her kopiert. Zu
einem gegebenen Zeitpunkt hört jedoch sogar dieser Prozess
auf. Der Zweig wird für die Abschlusstests vor der
Freigabe „eingefroren“.
Der Zweig wird markiert und
freigegeben. Nach dem Abschluss der Tests
wird /branches/1.0
als Momentaufnahme
nach /tags/1.0.0
kopiert. Das Tag
wird paketiert und an den Kunden ausgeliefert.
Der Zweig wird gepflegt. Während
die Arbeit für Version 2.0 in /trunk
weitergeht, werden weiterhin Fehlerbehebungen von
/trunk
nach
/branches/1.0
portiert. Wenn sich
ausreichend Fehlerbehebungen angesammelt haben, könnte
sich das Management entschließen, ein Release 1.0.1
herauszugeben: /branches/1.0
wird
nach /tags/1.0.1
kopiert, und das Tag
wird paketiert und freigegeben.
Der gesamte Prozess wiederholt sich während die Software reift: Wenn die Arbeit an 2.0 fertig ist, wird ein neuer 2.0 Release-Zweig erstellt, getestet, markiert und schließlich freigegeben. Nach einigen Jahren füllt sich das Projektarchiv mit einer Anzahl von Release-Zweigen, die weiterhin „gepflegt“ werden, und einer Zahl von Tags, die den endgültigen, ausgelieferten Versionen entsprechen.
Ein Funktions-Zweig ist die Art von
Zweig, wie er im Hauptbeispiel dieses Kapitels vorkam (der
Zweig, auf dem Sie gearbeitet haben, während Sally auf
/trunk
arbeitete). Es ist ein
vorübergehender Zweig, der angelegt wird, um an einer
komplexen Änderung zu arbeiten, ohne
/trunk
zu stören. Anders als
Release-Zweige (die vielleicht ewig gepflegt werden müssen),
werden Funktions-Zweige erstellt, eine Zeit lang genutzt,
zurück in den Stamm integriert und schließlich gelöscht. Sie
haben einen zeitlich begrenzten Nutzen.
In Projekten gehen die Meinungen oft auseinander, wann der
richtige Zeitpunkt zum Anlegen eines Funktions-Zweiges
gekommen ist. Manche Projekte benutzen nie Funktions-Zweige:
jeder darf Änderungen in /trunk
übergeben. Der Vorteil hier ist, dass es einfach ist –
niemand benötigt eine Schulung im Verzweigen und
Zusammenführen. Der Nachteil ist, dass der Code oft instabil
oder nicht nutzbar ist. Andere Projekte verwenden
ausschließlich Zweige: Eine Änderung darf
niemals direkt in
/trunk
übergeben werden. Selbst die
trivialsten Änderungen werden auf einem kurzlebigen Zweig
durchgeführt, sorgfältig geprüft und in den Stamm
zurückgeführt. Danach wird der Zweig gelöscht. Dieses Vorgehen
garantiert einen außerordentlich stabilen und nutzbaren Stamm,
jedoch zum Preis eines erheblichen Prozessaufwands.
Die meisten Projekte bewegen sich irgendwo dazwischen.
Gewöhnlich bestehen sie darauf, dass
/trunk
stets compilierfähig bleibt und
Regressionstests besteht. Ein Funktions-Zweig wird nur dann
benötigt, falls eine Änderung eine große Anzahl
destabilisierender Übergaben erfordert. Eine gute Faustregel
ist, diese Frage zu stellen: Wäre, falls ein Entwickler nach Tagen
isolierter Entwicklung die große Änderung auf einmal übergäbe
(so dass /trunk
nie instabil würde), die
Änderung zu umfangreich zum Überprüfen? Falls die Antwort auf
diese Frage „ja“ lautet, sollte die Änderung auf
einem Funktions-Zweig durchgeführt werden. Während der
Entwickler schrittweise Änderungen in den Zweig übergibt,
können sie auf einfache Weise von den Kollegen geprüft
werden.
Schließlich stellt sich die Frage, wie ein Funktions-Zweig am besten mit dem Stamm „synchron“ gehalten werden kann während die Arbeit weitergeht. Wie wir vorher bereits bemerkten, besteht ein großes Risiko, wenn wochen- oder monatelang auf dem Zweig gearbeitet wird; währenddessen ändert sich auch der Stamm, so dass ein Punkt erreicht werden kann, an dem sich die beiden Entwicklungslinien so sehr unterscheiden, dass es zu einem Albtraum ausarten kann, den Zweig zurück auf den Stamm zu führen.
Diese Situation wird am besten vermieden, indem regelmäßig Änderungen vom Stamm in den Zweig eingearbeitet werden. Machen Sie es zur Gewohnheit: Arbeiten Sie wöchentlich die Änderungen der vergangenen Woche vom Stamm in den Zweig ein.
Irgendwann werden Sie dann bereit sein, den
„synchronisierten“ Funktions-Zweig zurück in den
Stamm zu führen. Hierzu arbeiten Sie ein letztes Mal die
jüngsten Änderungen vom Stamm in den Zweig ein. Danach werden
die letzten Versionen auf dem Stamm und dem Zweig, bis auf Ihre
Änderungen auf dem Zweig, absolut gleich sein. Dann werden Sie
den Zweig mit der Option --reintegrate
wieder
mit dem Stamm zusammenführen:
$ cd trunk-working-copy $ svn update Revision 1910. $ svn merge --reintegrate http://svn.example.com/repos/calc/branches/mybranch -- Zusammenführen der Unterschiede zwischen Projektarchiv-URLs in ».«: U real.c U integer.c A newdirectory A newdirectory/newfile U . …
Aus einem anderen Winkel betrachtet ist dieser wöchentliche Abgleich vom Stamm auf den Zweig analog zum Ausführen von svn update in einer Arbeitskopie, wobei das finale Zusammenführen svn commit in einer Arbeitskopie entspricht. Ist denn letztendlich eine Arbeitskopie nicht ein sehr flacher privater Zweig? Es ist ein Zweig, der nur eine Änderung gleichzeitig aufnehmen kann.