Dieser Text befindet sich gegenwärtig in Bearbeitung, unterliegt ständigen Änderungen und kann dadurch nicht stets akkurat irgendeine freigegebene Version der Software Apache™ Subversion® beschreiben. Das Speichern dieser Seite als Lesezeichen oder andere auf diese Seite zu verweisen, ist keine so gute Idee. Besuchen Sie http://www.svnbook.com/, um stabile Versionen dieses Buchs zu erhalten.
Nun arbeiten Sie und Sally auf parallelen Zweigen des Projektes: Sie arbeiten auf einem privaten Zweig, und Sally arbeitet auf dem Stamm (Trunk) oder dem Hauptzweig der Entwicklung.
Bei Projekten mit einer großen Zahl von Mitarbeitern besitzen die meisten gewöhnlich Arbeitskopien vom Stamm. Sobald jemand eine langwierige Änderung machen muss, die wahrscheinlich den Stamm stören würde, ist die Vorgehensweise Standard, einen Zweig zu erzeugen und die Änderungen bis zum Abschluss der Arbeiten nach dorthin zu übertragen.
Die gute Nachricht ist also, dass Sie und Sally sich nicht in die Quere kommen. Die schlechte Nachricht ist, dass es sehr leicht ist, zu weit auseinander zu treiben. Erinnern Sie sich, dass eins der Probleme bei der Strategie „sich in ein Loch verkriechen“ darin bestand, dass es zu dem Zeitpunkt, an dem Sie mit dem Zweig fertig sind, fast unmöglich sein kann, Ihre Änderungen ohne eine riesige Zahl an Konflikten auf den Stamm zurückzuführen.
Stattdessen könnten Sie und Sally fortfahren, während der Arbeit Änderungen gemeinsam zu verwenden. Es liegt an Ihnen, zu entscheiden, welche Änderungen teilenswert sind; Subversion bietet Ihnen die Fähigkeit, Änderungen selektiv zwischen Zweigen zu „kopieren“. Und wenn Sie mit Ihrem Zweig vollständig fertig sind, kann die gesamte Menge Ihrer Änderungen vom Zweig auf den Stamm zurück kopiert werden. In der Terminologie von Subversion heißt der allgemeine Vorgang, Änderungen von einem Zweig auf einen anderen zu übertragen Zusammenführung (Merge) und wird durch verschiedene Aufrufe des Unterbefehls svn merge durchgeführt.
In den folgenden Beispielen gehen wir davon aus, dass sowohl auf Ihrem Subversion-Client als auch auf dem Server Subversion 1.8 (oder neuer) läuft. Falls einer von beiden älter als Version 1.5 ist, wird es komplizierter: Das System wird Änderungen nicht automatisch mitverfolgen, so dass Sie schmerzhafte manuelle Methoden anwenden müssen, um ähnliche Resultate zu erzielen. Dass heißt, dass Sie stets die detaillierte Syntax beim Zusammenführen verwenden müssen, um bestimmte Revisionsintervalle zu übertragen (siehe „Merge-Syntax: Die vollständige Offenlegung“ weiter unten in diesem Kapitel), und besonders sorgfältig verfolgen müssen, was bereits zusammengeführt ist und was nicht. Aus diesem Grund empfehlen wir Ihnen dringend, sicherzustellen, dass Ihr Client und Server mindestens die Version 1.5 haben.
Bevor wir weitermachen, sollten wir Sie warnen, dass Sie auf den kommenden Seiten viele Erörterungen zum Thema „Änderungen“ erwarten. Viele mit Versions-Kontroll-Systemen erfahrene Leute benutzen die Begriffe „Änderung“ und „Änderungsmenge“ (Changeset) austauschbar, so dass wir klären sollten, was Subversion unter einer Änderungsmenge versteht.
Jeder scheint eine etwas unterschiedliche Definition für den Begriff Änderungsmenge zu haben oder zumindest eine unterschiedliche Erwartung darüber, was es für ein Versions-Kontroll-System bedeutet, so etwas zu besitzen. Für unsere Zwecke reicht es aus, zu sagen, dass eine Änderungsmenge lediglich eine Sammlung von Änderungen mit einem eindeutigen Namen ist. Die Änderungen können aus der Bearbeitung an Textdateien, Modifizierungen an der Baumstruktur oder Justierungen an Metadaten bestehen. In einfachen Worten ist eine Änderungsmenge einfach ein Patch mit einem Namen, auf den Sie sich beziehen können.
In Subversion bezeichnet eine globale Revisionsnummer
N
einen Baum im Projektarchiv: Sie
beschreibt das Aussehen des Projektarchivs nach der
N
-ten Übertragung. Sie ist auch der
Name einer impliziten Änderungsmenge: Wenn Sie den Baum
N
mit dem Baum
N
-1 vergleichen, können Sie genau
den Patch ableiten, der übertragen wurde. Daher ist es einfach,
sich Revision N
nicht nur als Baum
sondern auch als Änderungsmenge vorzustellen. Falls Sie ein
Fehlerverwaltungssystem verwenden, können Sie die
Revisionsnummern benutzen, um auf bestimmte Patches zu
verweisen, die Fehler beheben – zum Beispiel:
„Dieser Fehler wurde durch r9238 behoben“. Dann
kann jemand svn log -r 9238
aufrufen,
um den Protokolleintrag zu genau der Änderungsmenge zu lesen,
die den Fehler behoben hat, und sich mit svn diff
-c 9238
den eigentlichen Patch ansehen. Und (wie
Sie bald sehen werden) auch der Subversion Befehl svn
merge kann Revisionsnummern verwenden. Sie können
bestimmte Änderungsmengen von einem Zweig mit einem anderen
zusammenführen, indem sie in den Argumenten zum entsprechenden
Kommando benannt werden: Die Übergabe von -c
9238
an svn merge würde das
Änderungsmenge r9238 mit Ihrer Arbeitskopie
zusammenführen.
Machen wir mit unserem Beispiel weiter und nehmen
an, dass eine Woche vergangen ist seitdem Sie mit der Arbeit
auf Ihrem privaten Zweig begonnen haben. Ihre Arbeit ist noch
nicht beendet, jedoch wissen Sie, dass gleichzeitig andere
Leute in Ihrem Team weiterhin wichtige Änderungen in
/trunk
des Projektes machen. Es ist in
Ihrem Interesse, diese Änderungen in Ihren Zweig zu
übernehmen, um sicherzustellen, dass sie sich gut mit Ihren
Änderungen vertragen. Das wird durch einen
Synchronisierungs-Merge erreicht
– ein Merge zu dem Zweck,
Ihren Zweig mit Änderungen zu aktualisieren, die seit der
Erstellung Ihres Zweigs auf dem Ursprungszweig vorgenommen
wurden.
Ein „automatischer“ Merge ist ganz
einfach einer, bei dem Sie das absolute Minimum an benötigten
Informationen für einen Merge angeben (d.h., eine einzelne
Merge-Quelle und ein Arbeitskopie-Ziel) und Subversion
entscheiden lassen, welche Änderungen zusammengeführt werden
müssen – bei einem automatischen Merge werden keine
Änderungsmengen mit -r
oder
-c
an svn merge
übergeben.
Tipp | |
---|---|
Ihren Zweig regelmäßig mit der Hauptentwicklungslinie zu synchronisieren hilft, „überraschende“ Konflikte zu vermeiden, wenn es an der Zeit ist, Ihre Änderungen zurück auf den Stamm zu bringen. |
Subversion kennt die Geschichte Ihres Zweigs und weiß, wann Sie ihn vom Stamm abgezweigt haben. Um eine Synchronisierungs-Zusammenführung zu machen, sollten Sie zunächst sicherstellen, dass die Arbeitskopie des Zweigs „sauber“ ist – dass sie keine lokalen Änderungen hat, die durch svn status angezeigt werden. Dann rufen Sie einfach die folgenden Befehle auf:
$ pwd /home/user/my-calc-branch $ svn merge ^/calc/trunk -- Zusammenführen von r341 bis r351 in ».«: U doc/INSTALL U src/real.c U src/button.c -- Aufzeichnung der Informationen für Zusammenführung von r341 bis r351 in ».«: U . $
Diese einfache Syntax – svn merge
– fordert
Subversion auf, alle Änderungen von dem URL, die vorher noch
nicht zusammengeführt wurden, mit dem aktuellen
Arbeitsverzeichnis (welches typischerweise das
Wurzelverzeichnis Ihrer Arbeitskopie ist) zusammenzuführen.
Beachten Sie auch, dass wir die Syntax mit dem Zirkumflex
(URL
^
) verwenden[35], um nicht den
vollständigen /trunk
-URL tippen zu
müssen. Beachten Sie ebenfalls die Mitteilung
„Aufzeichnung der Informationen für
Zusammenführung…“. Das teilt Ihnen mit, dass
durch den Merge die Eigenschaft
svn:mergeinfo
aktualisiert wird. Wir werden
sowohl diese Eigenschaft als auch diese Mitteilungen später in
diesem Kapitel besprechen, und zwar in
„Mergeinfo und Vorschauen“.
Nach dem Ausführen des vorangegangenen Beispiels enthält Ihre Arbeitskopie nun neue lokale Änderungen, die Nachbildungen all der Änderungen auf dem Stamm seit der Erstellung Ihres Zweiges sind:
$ svn status M . M Makefile M doc/INSTALL M src/button.c M src/real.c
Zu diesem Zeitpunkt ist es weise, sich die Änderungen
mithilfe von svn diff sorgfältig anzusehen,
und anschließend die Software von Ihrem Zweig zu bauen und zu
testen. Beachten Sie, dass auch das aktuelle
Arbeitsverzeichnis („.
“)
verändert wurde; svn diff zeigt an, dass
seine Eigenschaft svn:mergeinfo
angelegt
wurde.
$ svn diff --depth empty . Index: . =================================================================== --- . (Revision 351) +++ . (Arbeitskopie) Eigenschaftsänderungen: . ___________________________________________________________________ Hinzugefügt: svn:mergeinfo Zusammengeführt /calc/trunk:r341-351
Diese neue Eigenschaft ist ein wichtiges Metadatum in Zusammenhang mit Zusammenführungen, das Sie nicht anfassen sollten, da es von künftigen svn merge-Befehlen benötigt wird. (Wir werden später in diesem Kapitel mehr über diese Metadaten erfahren.)
Nach der Übernahme kann es möglich sein, dass Sie noch
einige Konflikte auflösen müssen – wie bei svn
update – oder möglicherweise noch einige kleinere
Bearbeitungen durchzuführen haben, damit alles wieder
funktioniert. (Denken Sie daran, dass die Abwesenheit
syntaktischer Konflikte nicht bedeutet,
dass keine semantischen Konflikte
vorhanden sind!) Falls ernsthafte Probleme auftauchen, können
Sie jederzeit die lokalen Änderungen mit svn revert
. -R
wieder rückgängig machen und eine lange
„was geht hier eigentlich vor“-Unterredung mit
Ihren Mitarbeitern führen. Falls jedoch alles gut aussieht,
können Sie die Änderungen zum Projektarchiv übertragen:
$ svn commit -m "Die letzten Änderungen von trunk mit my-calc-branch synchronisiert." Sende . Sende Makefile Sende doc/INSTALL Sende src/button.c Sende src/real.c Übertrage Daten .. Revision 352 übertragen.
An dieser Stelle ist Ihr Zweig „synchron“ mit dem Stamm, und Sie können sich ruhig zurücklehnen in der Gewissheit, dass Sie sich nicht zu weit von der Arbeit aller anderen entfernen, während Sie isoliert weiterarbeiten.
Nehmen wir an, noch eine Woche sei ins Land gegangen. Sie haben weitere Änderungen an Ihren Zweig übertragen, und Ihre Kollegen haben damit weitergemacht, den Stamm zu verbessern. Nun möchten Sie mal wieder die letzten Änderungen vom Stamm mit Ihrem Zweig abgleichen, damit Sie wieder synchron sind. Starten Sie einfach noch einmal den svn merge-Befehl!
$ svn merge ^/calc/trunk svn: E195020: Kann nicht in eine Arbeitskopie mit verschiedenen Revisionen\ zusammenführen [352:357], versuchen Sie erst zu aktualisieren $
Oh, das war jetzt aber unerwartet! Nachdem Sie während der
letzten Woche Änderungen auf Ihrem Zweig gemacht haben, sehen
Sie sich nun einer Arbeitskopie gegenüber, die eine Mischung
von Revisionen enthält (siehe
„Arbeitskopien mit gemischten Revisionen“). Mit
Subversion 1.7 und neuer verhindert der Unterbefehl
svn merge standardmäßig die Zusammenführung
in Arbeitskopien mit gemischten Revisionen. Ohne auf
Einzelheiten einzugehen, liegt das an Einschränkungen der Art
und Weise, wie Merges durch die Eigenschaft
svn:mergeinfo
verfolgt werden (für Details,
siehe „Mergeinfo und Vorschauen“).
Diese Einschränkungen bedeuten, dass Merges in Arbeitskopien
aus gemischten Revisionen unerwartete Text- und Baumkonflikte
hervorrufen können.[36] Wir möchten keine
unnötigen Konflikte, also aktualisieren wir die Arbeitskopie
und versuchen erneut die Zusammenführung.
$ svn up Aktualisiere ».«: Revision 361. $ svn merge ^/calc/trunk --- Zusammenführen von r352 bis r361 in ».«: U src/real.c U src/main.c -- Aufzeichnung der Informationen für Zusammenführung von r352 bis r361 in ».«: U .
Subversion weiß, welche Änderungen Sie vorher mit Ihrem Zweig abgeglichen haben, so dass es sorgfältig nur die Änderungen berücksichtigt, die Sie noch nicht haben. Einmal mehr müssen Sie bauen, testen und die lokalen Änderungen an Ihren Zweig mit svn commit übertragen.
In den meisten Beispielen dieses Kapitels liegt das Ziel einer Zusammenführung im Wurzelverzeichnis eines Zweigs (siehe „Was ist ein Zweig?“). Obwohl es sich dabei um eine empfohlene Vorgehensweise handelt, kann es vorkommen, dass Sie gelegentlich einen Merge direkt in irgendein Kindverzeichnis der Wurzel des Zweigs vornehmen müssen. Diese Art der Zusammenführung wird Teilbaum-Merge genannt, und die aufgezeichneten Informationen dazu Teilbaum-Mergeinfo. Es gibt weder Besonderheiten bei Teilbaum-Merges noch bei Teilbaum-Mergeinfo. Es gibt hierbei tatsächlich nur einen wichtigen Punkt bei diesen Konzepten zu beachten: die vollständigen Aufzeichnungen über Zusammenführungen auf einen Zweig müssen nicht notwendigerweise in den Informationen der Wurzel des Zweigs vorliegen. Für eine vollständige Übersicht müssen Sie alle Teilbaum-Mergeinfos berücksichtigen. Glücklicherweise erledigt das Subversion für Sie, so dass Sie sich in den seltensten Fällen selbst darum kümmern müssen. Ein kurzes Beispiel hilft bei der Erklärung:
# Wir müssen r958 von trunk und branches/proj-X/doc/INSTALL # zusammenführen, doch beeinflusst diese Revision auch main.c, das # wir jedoch nicht zusammenführen wollen: $ svn log --verbose --quiet -r 958 ^/ ------------------------------------------------------------------------ r958 | bruce | 2011-10-20 13:28:11 -0400 (Do, 20. Okt 2011) Geänderte Pfade: M /trunk/doc/INSTALL M /trunk/src/main.c ------------------------------------------------------------------------ # Kein Problem. Wir führen einen Teilbaum direkt auf der Datei INSTALL # zusammen, doch merken uns zunächst, welche # Mergeinfo für die Wurzel des Zweigs vorhanden # ist: $ cd branches/proj-X $ svn propget svn:mergeinfo --recursive Eigenschaften zu ».«: svn:mergeinfo /trunk:651-652 # Nun führen wir den Teilbaum zusammen; beachten Sie, dass sowohl # Quelle als auch Ziel auf INSTALL zeigen: $ svn merge ^/trunk/doc/INSTALL doc/INSTALL -c 958 -- Zusammenführen von r958 in »doc/INSTALL«: U doc/INSTALL -- Aufzeichnung der Informationen für Zusammenführung von r958 in »doc/INSTALL«: G doc/INSTALL # Sobald die Zusammenführung abgeschlossen ist, gibt es Mergeinfo # an INSTALL: $ svn propget svn:mergeinfo --recursive Eigenschaften zu ».«: svn:mergeinfo /trunk:651-652 Eigenschaften zu »doc/INSTALL«: svn:mergeinfo /trunk/doc/INSTALL:651-652,958 # Was, wenn wir und dann entscheiden, alles von r958 haben zu wollen? # Ganz einfach, alles, was wir tun müssen, ist, die Zusammenführung # dieser Revision zu wiederholen, diesen mal allerdings auf der Wurzel # des Zweigs. Subversion erkennt die Mergeinfo des Teilbaums an # INSTALL und versucht nicht, irgendwelche Änderungen # hineinzubringen, sondern es führt nur die Änderungen an main.c # zusammen: $ svn merge ^/subversion/trunk . -c 958 -- Zusammenführen von r958 in ».«: U src/main.c -- Aufzeichnung der Informationen für Zusammenführung von r958 in ».«: U . -- Entfernung der Zusammenführungsinformationen von »doc/INSTALL«: U doc/INSTALL
Sie haben sich vielleicht gefragt, warum im obigen
Beispiel INSTALL
Mergeinfo für r651-652
besitzt, wenn wir nur r958 zusammengeführt haben. Das liegt
an der Vererbung der Mergeinfo, die wir in
Vererbung von Mergeinfo behandeln. Beachten Sie weiterhin, dass die
Teilbaum-Mergeinfo von doc/INSTALL
„entfernt“ wurde. Das nennt
sich Entfernung von Mergeinfo und
passiert immer dann, wenn Subversion redundante
Teilbaum-Mergeinfo entdeckt.
Tipp | |
---|---|
Vor Subversion 1.7 haben Zusammenführungen bedingungslos die gesamte Teilbaum-Mergeinfo unter dem Ziel aktualisiert, um den Merge zu beschreiben. Für Anwender mit umfangreicher Teilbaum-Mergeinfo bedeutete das, dass auch relativ „einfache“ Zusammenführungen (z.B., bei der ein Diff auf eine einzige Datei angewendet wurde) Änderungen der Mergeinfo in jedem Teilbaum nach sich zog, selbst bei denen, die keine Eltern des betroffenen Pfades waren. Dies führte zu einiger Verwirrung und Frustration. Subversion 1.7 und neuer geht dieses Problem an, indem es nur die Mergeinfo an den Teilbäumen aktualisiert, die Eltern der vom Merge betroffenen Pfade sind (d.h., durch die Anwendung der Differenz geänderte, hinzugefügte oder gelöschte Pfade, siehe „Merge-Syntax: Die vollständige Offenlegung“). Die einzige Ausnahme von diesem Verhalten betrifft das eigentliche Ziel der Zusammenführung; dessen Mergeinfo wird stets aktualisiert, um den Merge zu beschreiben, auch wenn die angewandte Differenz keine Änderung nach sich zog. |
Was passiert jedoch, wenn Sie schließlich Ihre Arbeit abgeschlossen haben? Ihre neue Funktion ist fertig, und Sie sind bereit, die Änderungen von Ihrem Zweig zurück auf den Stamm zu überführen (so dass Ihr Team die Früchte Ihrer Arbeit genießen kann). Die Vorgehensweise ist einfach. Zunächst synchronisieren Sie Ihren Zweig noch einmal mit dem Stamm, wie Sie es bisher gemacht haben:[37]
$ svn up # (sicherstellen, dass die Arbeitskopie aktuell ist) Aktualisiere ».«: Revision 378. $ svn merge ^/calc/trunk --- Zusammenführen von r362 bis r378 in ».«: U src/main.c -- Aufzeichnung der Informationen für Zusammenführung von r381 bis r385 in ».«: U . $ # bauen, testen, ... $ svn commit -m "Endgültiger Merge der trunk-Änderungen nach my-calc-branch." Sende . Sende src/main.c Übertrage Daten . Revision 379 übertragen.
Verwenden Sie den Unterbefehl svn
merge, um Ihre Änderungen automatisch zurück auf
den Stamm zu replizieren. Diese Art von Merge wird
„automatischer Reintegrations“-Merge
genannt. Sie benötigen eine Arbeitskopie von
/calc/trunk
. Sie bekommen sie entweder
durch svn checkout, indem Sie von irgendwo
auf Ihrer Platte eine alte Arbeitskopie vom Stamm
hervorkramen, oder den Befehl svn switch
(siehe „Zweige durchlaufen“)
verwenden.
Tipp | |
---|---|
Der Begriff „Reintegration“ kommt von der
merge-Option
|
Ihre Arbeitskopie darf keine lokalen Änderungen beinhalten oder aus gemischten Revisionen bestehen (siehe „Arbeitskopien mit gemischten Revisionen“). Obwohl es sich dabei normalerweise um die bewährten Vorgehensweisen beim Zusammenführen handelt, sind sie bei automatischen Reintegrations-Merges zwingend notwendig.
Sobald Sie eine saubere Arbeitskopie des Stamms haben, sind Sie bereit, Ihren Zweig damit zusammenzuführen:
$ pwd /home/user/calc-trunk $ svn update Aktualisiere ».«: Revision 390. $ svn merge ^/calc/branches/my-calc-branch -- Zusammenführen der Unterschiede zwischen Projektarchiv-URLs in ».«: U src/real.c U src/main.c U Makefile -- Aufzeichnung der Informationen für Zusammenführung zwischen Projektarchiv-URLs in ».«: U . $ # bauen, testen, überprüfen, ... $ svn commit -m "my-calc-branch mit Stamm zusammenführen!" Sende . Sende Makefile Sende src/main.c Sende src/real.c Übertrage Daten .. Revision 380 übertragen.
Gratulation! Ihre Änderungen vom Zweig sind nun zurück in
die Hauptentwicklungslinie überführt worden. Beachten Sie,
dass der automatische Reintegrations-Merge etwas anderes ist,
als was Sie bisher gemacht haben. Vorher haben wir
svn merge aufgefordert, die „nächste
Änderungsmenge“ von einer Entwicklungslinie (dem Stamm)
zu holen und sie mit einer anderen (Ihrem Zweig) abzugleichen.
Das ist recht überschaubar, und Subversion weiß jedes Mal, wo
es wieder ansetzen soll. Bei unseren vorangehenden Beispielen
können Sie sehen, dass es erst die Intervalle 341:351 von
/calc/trunk
nach
/calc/branches/my-calc-branch
überführte;
später fuhr es mit dem nächsten verfügbaren
aufeinanderfolgenden Intervall 351:361 fort. Wenn Sie die
letzte Synchronisierung machen, wird es das Intervall 361:378
zusammenführen.
Wenn Sie jedoch /calc/branches/my-calc-branch
auf /calc/trunk
zurückführen, sehen die
dem zugrundeliegenden Berechnungen ganz anders aus. Ihr Zweig
ist nun ein Mischmasch aus abgeglichenen Änderungen vom Stamm
und privaten Änderungen auf dem Zweig, so dass es kein
einfaches, aufeinanderfolgendes Intervall mit Revisionen zum
Herüberkopieren gibt. Indem Sie einen automatischen Merge
verwenden, fordern Sie Subversion auf, sorgfältig
nur die Änderungen von Ihrem Zweig zu
replizieren. (Und tatsächlich macht es das so, dass es die
letzte Version auf dem Stamm mit der letzten Version auf dem
Zweig vergleicht: Der Unterschied macht genau die Änderung auf
dem Zweig aus!)
Beachten Sie, dass automatische Reintegrations-Merges nur
die oben beschriebenen Anwendungsfälle unterstützen. Wegen
dieses engen Einsatzgebietes sowie der vorher erwähnten
Voraussetzungen (aktualisierte
Arbeitskopie[38] ohne
gemischte Revisionen, umgeschaltete Pfade oder lokale
Änderungen), wird diese Option nicht mit den meisten anderen
Optionen von svn merge funktionieren. Sie
werden einen Fehler bekommen, falls Sie andere nicht-globale
Optionen verwenden, außer den folgenden:
--accept
, --dry-run
,
--diff3-cmd
, --extensions
oder --quiet
.
Nachdem nun Ihr privater Zweig mit dem Stamm zusammengeführt wurde, können Sie ihn aus dem Projektarchiv löschen:
$ svn delete ^/calc/branches/my-calc-branch \ -m "my-calc-branch entfernt, auf Stamm zurückgeführt in r391." …
Aber halt! Ist die Geschichte des Zweigs nicht wertvoll?
Was, wenn jemand sich eines Tages die Evolution Ihrer Funktion
ansehen möchte und hierfür auf die Änderungen des Zweiges
schauen möchte? Keine Sorge! Denken Sie daran, dass, obwohl
Ihr Zweig nicht mehr im Verzeichnis
/calc/branches
sichtbar ist, seine
Existenz gleichwohl ein unveränderbarer Teil der Geschichte
des Projektarchivs ist. Ein einfacher Befehl svn
log auf dem /calc/branches
URL
wird die gesamte Geschichte des Zweiges anzeigen. Ihr Zweig
kann eines Tages sogar wiederbelebt werden, sollten Sie dieses
wünschen (siehe
„Zurückholen gelöschter Objekte“).
Falls Sie sich entscheiden, den Zweig nach der Reintegration auf den Stamm nicht zu löschen, können Sie mit Synchronisierungs-Merges vom Stamm fortfahren und dann den Zweig erneut Reintegrieren.[39] Falls Sie das machen, werden nur die Änderungen, die Sie nach dem ersten Reintegrieren auf dem Zweig vorgenommen haben, mit dem Stamm zusammengeführt.
Der grundsätzliche Mechanismus, den Subversion verwendet,
um Änderungsmengen zu verfolgen – d.h., welche
Änderungen auf welchen Zweig übertragen worden sind –
besteht aus der Datenspeicherung in versionierten
Eigenschaften. Namentlich werden Daten die das Zusammenführen
betreffen in der Eigenschaft svn:mergeinfo
festgehalten, die mit Dateien und Verzeichnissen verknüpft
ist. (Falls Sie mit Subversion-Eigenschaften nicht vertraut
sind, siehe „Eigenschaften“.)
Sie können sich die mergeinfo-Eigenschaft ansehen, wie jede andere versionierte Eigenschaft:
$ cd my-calc-branch $ svn pg svn:mergeinfo -v Eigenschaften von ».«: svn:mergeinfo /calc/trunk:341-378
Warnung | |
---|---|
Obwohl es möglich ist, |
Tipp | |
---|---|
Der Umfang von |
Die Eigenschaft svn:mergeinfo
wird
automatisch von Subversion gepflegt, sobald Sie den Befehl
svn merge ausführen. Ihr Wert gibt
Aufschluss darüber, welche Änderungen an einem gegebenen Pfad
mit dem in Frage kommenden Verzeichnis abgeglichen wurden. Im
vorangegangenen Beispiel ist /calc/trunk
der
Ursprungspfad der zusammengeführten Änderungen und
/calc/branches/my-calc-branch
das
Zielverzeichnis. Frühere Versionen von Subversion pflegten die
Eigenschaft svn:mergeinfo
im Hintergrund.
Sie konnten die Änderungen nach einem abgeschlossenen
Merge mit svn diff oder svn
status zwar entdecken, doch gab die eigentliche
Zusammenführung keinerlei Hinweis, dass sie die Eigenschaft
svn:mergeinfo
geändert hat. In Subversion
1.7 und später trifft das nicht mehr zu, da es verschiedene
Mitteilungen gibt, um Sie zu benachrichtigen, wenn ein
Merge die Eigenschaft svn:mergeinfo
ändert. Diese Mitteilungen beginnen alle mit
„-- Aufzeichnung der Informationen für
Zusammenführung“ und tauchen am Ende einer
Zusammenführung auf. Im Gegensatz zu anderen Mitteilungen bei
Merges beschreiben diese kein Anwenden eines Diffs auf eine
Arbeitskopie (siehe
„Merge-Syntax: Die vollständige Offenlegung“),
sondern Änderungen zur Buchhaltung, um festzuhalten, was
zusammengeführt wurde.
Subversion stellt auch den Unterbefehl svn
mergeinfo zur Verfügung, der dabei hilfreich ist,
die Zusammenführungen zwischen zwei Zweigen zu zeigen;
insbesondere welche Änderungsmengen in ein Verzeichnis
eingeflossen sind oder welche noch für einen Abgleich bereit
stehen. Letzteres ergibt eine Art Vorschau, welche
Änderungsmengen ein folgender svn
merge-Befehl auf Ihren Zweig replizieren wird.
Standardmäßig zeigt svn mergeinfo eine
graphische Übersicht der Beziehungen zwischen zwei Zweigen an.
Wenn wir auf unser früheres Beispiel zurückkommen, verwenden
wir den Unterbefehl, um die Beziehung zwischen
/calc/trunk
und
/calc/branches/my-calc-branch
zu
untersuchen:
$ cd my-calc-branch $ svn mergeinfo ^/calc/trunk letzter gemeinsamer Vorfahr | letzte vollständige Zusammenführung | | Spitze des Zweigs | | | Projektarchiv-Pfad 340 382 | | -------| |------------ calc/trunk \ / \ / --| |------------ calc/branches/my-calc-branch | | 379 382
Das Diagramm zeigt, dass
/calc/branches/my-calc-branch
von
/calc/trunk@340
herüber kopiert wurde und
der letzte automatische Merge der Reintegrations-Merge war,
den wir vom Zweig zum Stamm in r380 gemacht haben. Beachten
Sie, dass das Diagramm die vier automatischen
Synchronisierungs-Merges nicht zeigt, die
wir in den Revisionen 352, 362, 372 und 379 gemacht haben.
Gezeigt wird lediglich der letzte automatische Merge, egal in
welche Richtung.[40] Diese Standard-Ausgabe
ist als Übersicht über die Merges zwischen zwei Zweigen
brauchbar, jedoch sollten Sie die Option
--show-revs=merged
verwenden, um die
zusammengeführten Versionen genau zu sehen:
$ svn mergeinfo ^/calc/trunk --show-revs merged r344 r345 r346 … r366 r367 r368
Um auf ähnliche Art die Änderungen zu sehen, die für einen
Merge vom Stamm auf den Zweig in Frage kommen, können wir die
Option --show-revs=eligible
verwenden:
$ svn mergeinfo ^/calc/trunk --show-revs eligible r380 r381 r382
Der Befehl svn mergeinfo erwartet einen
„Quell“-URL (woher die Änderungen kommen)
und einen optionalen „Ziel“-URL (wohin die
Änderungen abgeglichen werden). Falls kein Ziel-URL angegeben
ist, wird das aktuelle Arbeitsverzeichnis als Ziel angenommen.
Da wir im vorangegangenen Beispiel unser dem Zweig
entsprechenden Arbeitsverzeichnis abfragen, geht der Befehl
davon aus, dass wir daran interessiert sind, Änderungen vom
angegebenen Stamm-URL für
/calc/branches/my-calc-branch
zu
erhalten.
Seit Subversion 1.7 kann der Unterbefehl svn
mergeinfo auch Teilbaum-Mergeinfo und
nichterbliche Mergeinfo berücksichtigen. Mit den Option
--recursive
oder --depth
wird Teilbaum-Mergeinfo berücksichtigt, während nicht
vererbbare Mergeinfo standardmäßig beachtet wird.
Angenommen, wir haben einen Zweig sowohl mit Teilbaum- als auch nichterblichen Mergeinfo:
$ svn pg svn:mergeinfo -vR # Nichterbliche Mergeinfo Eigenschaften zu ».« svn:mergeinfo /calc/trunk:354,385-388* # Teilbaum-Mergeinfo Eigenschaften zu »doc/INSTALL« svn:mergeinfo /calc/trunk/Makefile:354,380
Aus den obigen Informationen geht hervor, dass r385-388
nur in die Wurzel des Zweigs eingepflegt wurde, aber in keins
der Kindverzeichnisse. Ferner ist erkennbar, dass r380 nur in
die Datei Makefile
eingearbeitet wurde.
Wenn wir svn mergeinfo mit der Option
--recursive
verwenden, um nachzusehen, was
von /calc/trunk
in diesen Zweig
eingepflegt wurde, erkennen wir drei Revisionen, die mit der
Markierung *
versehen sind:
$ svn mergeinfo -R --show-revs=merged ^/calc/trunk . r354 r380* r385 r386 r387* r388*
*
markiert Revisionen, die nur
teilweise in das in Frage kommende Ziel
eingepflegt worden sind (die Bedeutung ist die gleiche wie bei
der Überprüfung nach in Frage kommenden Revisionen). In diesem
Beispiel bedeutet das, dass beim Versuch r380, r387 oder r388
von ^/trunk
einzupflegen, mehr Änderungen
angefallen wären. Ebenso wissen wir, da r354, r385 und r386
nicht mit *
markiert
ist, dass der Versuch, sie erneut einzupflegen, keine
Auswirkung hätte.[41]
Eine andere Methode, eine genauere Vorschau auf einen
Abgleich zu bekommen, ist die Verwendung der Option
--dry-run
:
$ svn merge ^/paint/trunk paint-feature-branch --dry-run -- Zusammenführen von r290 bis r383 in »paint-feature-branch«: U paint-feature-branch/src/palettes.c U paint-feature-branch/src/brushes.c U paint-feature-branch/Makefile $ svn status # es wird nichts ausgegeben, die Arbeitskopie ist unverändert
Die Option --dry-run
macht tatsächlich
überhaupt keine lokalen Änderungen an der Arbeitskopie. Sie
zeigt nur Status-Codes, die ausgegeben
würden, wenn ein echter Abgleich
stattfände. Sie ist nützlich, um eine Vorschau für einen
möglichen Abgleich auf „hoher Ebene“ zu erhalten,
falls svn diff zu detailliert wäre.
Tipp | |
---|---|
Nach dem Merge, aber vor der Übergabe des Ergebnisses,
können Sie |
Natürlich ist die beste Methode, eine Vorschau eines
Merges zu erhalten, ihn zu machen! Denken Sie daran, dass
der Aufruf von svn merge an sich nichts
Riskantes ist (es sei denn, sie haben lokale Änderungen an
Ihrer Arbeitskopie gemacht – aber wir haben bereits
betont, dass Sie in eine derartige Umgebung nicht abgleichen
sollten). Falls Ihnen das Ergebnis des Abgleichs nicht
gefallen sollte, rufen Sie einfach svn revert
. -R
auf, um die Änderungen an Ihrer Arbeitskopie
rückgängig zu machen, und versuchen Sie den Befehl erneut mit
unterschiedlichen Optionen. Der Abgleich ist solange nicht
endgültig, bis Sie mit svn commit das
Ergebnis übertragen.
Sehr häufig wird svn merge verwendet,
um eine Änderung rückgängig zu machen, die bereits an das
Projektarchiv übertragen worden war. Nehmen wir einmal an, Sie
arbeiten fröhlich in einer Arbeitskopie von
/calc/trunk
und entdecken, dass die
damaligen Änderungen an verschiedenen Quelltext-Dateien in
Revision 392 völlig falsch waren. Sie hätten nie übertragen
werden sollen. Sie können svn merge
verwenden, um die Änderung in Ihrer Arbeitskopie
„zurückzunehmen“, und dann die lokale Änderung an
das Projektarchiv übertragen. Sie müssen hierfür nur eine
umgekehrte Differenz angeben. (Sie machen
das durch die Angabe von --revision 303:302
oder durch das äquivalente --change -303
.)
$ svn merge ^/calc/trunk . -c-392 -- Rückwärtiges Zusammenführen von r392 in ».«: U src/real.c U src/main.c U src/button.c U src/integer.c -- Aufzeichnung der Informationen für rückwärtiges Zusammenführen von r392 in ».«: U . $ svn st M src/button.c M src/integer.c M src/main.c M src/real.c $ svn diff … # überprüfen, ob die Änderung entfernt wurde … $ svn commit -m "Fehlerhafte Änderung aus r392 rückgängig machen." Sende src/button.c Sende src/integer.c Sende src/main.c Sende src/real.c Sende integer.c Übertrage Daten .... Revision 399 übertragen.
Wie wir früher bereits erwähnten, kann man eine
Projektarchiv-Version als eine bestimmte Änderungsmenge
betrachten. Bei Verwendung der Option -r
wird
svn merge aufgefordert, eine Änderungsmenge
oder ein ganzes Intervall von Änderungsmengen auf Ihre
Arbeitskopie anzuwenden. In unserem Fall, bei dem wir eine
Änderung zurücknehmen, fordern wir svn
merge auf, die Änderungsmenge r392
rückwärts auf unsere Arbeitskopie
anzuwenden.
Merken Sie sich, dass ein solches Rückgängigmachen wie
jeder andere svn merge-Vorgang ist, so dass
Sie svn status und svn
diff benutzen sollten, um sicherzustellen, dass Ihre
Arbeit in dem Zustand ist, den Sie haben möchten, und
verwenden Sie anschließend svn commit, um
die endgültige Version in das Projektarchiv zu bringen. Nach der
Übergabe wird sich diese bestimmte Änderungsmenge nicht mehr
in der HEAD
-Revision wiederfinden.
Nun denken Sie vielleicht: Gut, aber das hat doch nicht
wirklich die Übergabe rückgängig gemacht, oder? Die Änderung
besteht immer noch in Revision 392. Falls jemand eine Version
des Projektes calc
zwischen den
Revisionen 392 und 398 auscheckt, wird doch trotzdem die
fehlerhafte Änderung sichtbar, oder nicht?
Ja, das stimmt. Wenn wir davon sprechen, eine Änderung zu
„entfernen“, sprechen wir eigentlich darüber, sie
aus der HEAD
-Revision zu entfernen. Die
ursprüngliche Änderung besteht immer noch in der Geschichte
des Projektarchivs. Für die meisten Situationen ist das
ausreichend. Die meisten Leute sind sowieso nur am
HEAD
eines Projektes interessiert. Es gibt
jedoch Spezialfälle, in denen Sie wirklich alle Beweise der
Übergabe vernichten möchten. (Vielleicht hat jemand ein
vertrauliches Dokument in das Projektarchiv übertragen.) Das ist
leider nicht so einfach, da Subversion absichtlich so
konstruiert wurde, dass es niemals Informationen
verliert. Revisionen sind unveränderliche Bäume, die
aufeinander aufbauen. Die Beseitigung einer Revision aus der
Geschichte würde einen Dominoeffekt auslösen, Chaos in allen
nachfolgenden Revisionen anrichten und möglicherweise alle
Arbeitskopien ungültig machen.[42]
Das Tolle an Versions-Kontroll-Systemen ist, dass
Informationen nie verlorengehen. Selbst wenn Sie eine Datei
oder ein Verzeichnis löschen, ist es zwar nicht mehr in der
HEAD
-Revision vorhanden, jedoch noch in
früheren Revisionen. Eine der häufigsten Fragen neuer Benutzer
ist: „Wie bekomme ich meine alte Datei oder mein altes
Verzeichnis zurück?“
Der erste Schritt ist es, genau zu definieren welches Objekt Sie zurückholen möchten. Hier ist eine nützliche Metapher: Sie können sich vorstellen, dass jedes Objekt im Projektarchiv in einem zweidimensionalen Koordinatensystem befindet. Die erste Koordinate ist ein bestimmter Revisionsbaum und die zweite Koordinate ist ein Pfad innerhalb dieses Baumes. So wird jede Version Ihrer Datei oder Ihres Verzeichnisses durch ein bestimmtes Koordinatenpaar definiert werden. (Erinnern Sie sich an die Syntax einer „Peg-Revision“ – foo.c@224 – die in „Peg- und operative Revisionen“ erwähnt wurde.)
Zunächst sollten Sie svn log benutzen,
um das exakte Koordinatenpaar zu ermitteln, das Sie
zurückholen wollen. Eine gute Strategie ist es, svn
log --verbose
in einem Verzeichnis aufzurufen, in
dem das gelöschte Objekt einmal enthalten war. Die Option
--verbose
(-v
) gibt eine
Liste aller geänderten Objekte in jeder Revision aus; Sie
müssen nur noch die Revision finden, in der Sie die Datei oder
das Verzeichnis gelöscht haben. Sie können das visuell tun
oder ein Werkzeug zur Untersuchung der Protokollausgaben
einsetzen (mit grep oder vielleicht durch
eine inkrementelle Suche in einem Editor). Falls Sie wissen,
dass das fragliche Objekt kürzlich gelöscht wurde, können Sie
auch die Option --limit
verwenden, um die
Protokollausgabe für eine manuelle Untersuchung knapp genug zu
halten.
$ cd calc/trunk $ svn log -v --limit 3 ------------------------------------------------------------------------ r401 | sally | 2013-02-18 23:15:44 -0500 (Di, 19. Feb 2013) | 1 Zeile Geänderte Pfade: M /calc/trunk/src/main.c Nachtrag zu r400: Tippfehler im Hifetext. ------------------------------------------------------------------------ r400 | bill | 2013-02-19 20:55:08 -0500 (Di, 19. Feb 2013) | 4 Zeilen Geänderte Pfade: M /calc/trunk/src/main.c D /calc/trunk/src/real.c * calc/trunk/src/main.c: Hilfetext aktualisiert. * calc/trunk/src/real.c: Datei entfernt, keine der hier implementierten APIs werden noch irgendwo verwendet. ------------------------------------------------------------------------ r399 | sally | 2013-02-19 20:05:14 -0500 (Di, 19. Feb 2013) | 1 Zeile Geänderte Pfade: M /calc/trunk/src/button.c M /calc/trunk/src/integer.c M /calc/trunk/src/main.c M /calc/trunk/src/real.c Fehlerhafte Änderung aus r392 rückgängig gemeacht. ------------------------------------------------------------------------
In diesem Beispiel nehmen wir an, dass Sie nach der
gelöschten Datei real.c
suchen. Beim
Durchsehen der Protokolle des Elternverzeichnisses haben Sie
entdeckt, dass diese Datei in Revision 400 gelöscht
wurde. Daher war die letzte Revision in der die Datei noch
vorhanden war die unmittelbare Vorgänger-Revision. Die
Schlussfolgerung: Sie möchten den Pfad
/calc/trunk/real.c
aus Revision 399
zurückholen.
Das war der schwierige Teil – die Nachforschung. Nun, da Sie wissen, was Sie wiederherstellen wollen, haben Sie die Wahl zwischen zwei verschiedenen Methoden.
Die eine Option ist, svn merge zu
verwenden, um Revision 400 „rückwärts“
anzuwenden. (Wir haben bereits in
„Änderungen rückgängig machen“
besprochen, wie Änderungen rückgängig gemacht werden.) Das
hätte den Effekt, real.c
als lokale
Änderung erneut hinzuzufügen. Die Datei würde zum Hinzufügen
ins Projektarchiv markiert, und nach der Übergabe wäre die Datei
wieder in HEAD
vorhanden.
In diesem besonderen Beispiel ist das aber wahrscheinlich
nicht die beste Strategie. Die Rückwärts-Anwendung von
Revision 400 würde nicht nur real.c
zum
Hinzufügen markieren, sondern, wie aus den Protokollmeldungen
hervorgeht, dass ebenso bestimmte Änderungen an
main.c
zurücknehmen, was Sie aber
nicht wollen. Sie können sicherlich Revision 400 rückwärts
anwenden und dann mit svn revert die
lokalen Änderungen an main.c
zurücknehmen; allerdings ist diese Technik nicht sehr
effektiv. Was wäre, wenn 90 Dateien in Revision 400 geändert
worden wären?
Eine zweite, zielorientiertere, Strategie ist es, den Befehl svn merge überhaupt nicht zu verwenden, sondern stattdessen svn copy. Kopieren Sie einfach das exakte „Koordinatenpaar“ aus Revision und Pfad vom Projektarchiv in Ihre Arbeitskopie:
$ svn copy ^/calc/trunk/src/real.c@399 ./real.c A real.c $ svn st A + real.c # Übertragung der Wiederbelebung …
Das Plus-Zeichen in der Statusausgabe zeigt an, dass das
Objekt nicht bloß zu Hinzufügen vorgemerkt ist, sondern zum
Hinzufügen „mit Geschichte“. Subversion merkt
sich, woher es kopiert wurde. Künftig wird beim Anwenden von
svn log auf diese Datei die gesamte
Geschichte, über das Zurückholen hinweg, inklusive der
Geschichte vor Revision 399 durchlaufen. In anderen Worten,
dieses neue real.c
ist nicht wirklich
neu; es ist ein direkter Nachfahre der ursprünglichen,
gelöschten Datei. Dies ist normalerweise eine gute und
nützliche Sache. Falls Sie jedoch die Datei
ohne geschichtliche Verbindung zur alten
Datei zurückholen wollen, funktioniert diese Technik
ebenso gut:
$ svn cat ^/calc/trunk/src/real.c@399 > ./real.c $ svn add real.c A real.c # Übertragung der Wiederbelebung …
Obwohl unser Beispiel zeigt, wie eine Datei zurückgeholt wird, sollten sie beachten, dass dieselben Techniken auch beim Wiederherstellen von gelöschten Verzeichnissen funktionieren. Beachten Sie auch, dass die Wiederherstellung nicht unbedingt in Ihrer Arbeitskopie passieren muss – sie kann auch vollständig im Projektarchiv ausgeführt werden:
$ svn copy ^/calc/trunk/src/real.c@399 ^/calc/trunk/src/real.c \ -m "real.c aus Revision 399 wiederhergestellt." Revision 402 übertragen. $ svn up Aktualisiere ».«: A real.c Aktualisiert zu Revision 402.
[35] Diese wurde in svn 1.6 eingeführt,
[36] Die Option
--allow-mixed-revisions
des Unterbefehls
svn merge erlaubt Ihnen, diese
Einschränkung zu umgehen, jedoch sollten Sie das nur dann
machen, wenn Sie die Auswirkungen verstehen und einen guten
Grund dafür haben.
[37] Seit Subversion 1.7 brauchen Sie nicht unbedingt alle Ihre Synchronisierungs-Merges in die Wurzel Ihres Zweigs zu bringen wie in diesem Beispiel. Falls Ihr Zweig effektiv durch eine Reihe von Teilbaum-Merges synchronisiert ist, wird die Reintegration funktionieren, doch fragen Sie sich einmal, warum Sie Teilbäume zusammenführen, wenn doch der Zweig effektiv synchronisiert wird. Diese Vorgehensweise ist oft unnötig kompliziert.
[38] Automatische Reintegrations-Merges sind erlaubt, falls das Ziel ein flacher Checkout ist (siehe „Verzeichnis-Teilbäume“), doch sämtliche vom Diff betroffene, durch die Beschränkung der Arbeitskopie auf einen Teilbaum „fehlende“ Pfade werden übersprungen, was wahrscheinlich nicht von Ihnen beabsichtigt ist!
[39] Diese Wiederverwendung eines Arbeitszweigs wird nur von Subversion 1.8 unterstützt. Frühere Versionen erfordern einige besondere Schritte, bevor ein Arbeitszweig mehr als einmal reintegriert werden kann. Siehe eine frühere Version dieses Kapitels für weitere Informationen: http://svnbook.red-bean.com/de/1.7/svn.branchmerge.basicmerging.html#svn.branchemerge.basicmerging.reintegrate
[40] Unter „Richtung“ verstehen wir entweder Stamm-Zweig- (automatische Synchronisierung) oder Zweig-Stamm-Merges (automatische Reintegration).
[41] Das ist ein gutes Beispiel für „inoperative“ Merge-Revisionen.
[42] Allerdings gibt es im Subversion-Projekt Pläne, eines Tages einen Befehl zu implementieren, der die Aufgabe erledigen würde, Informationen dauerhaft zu löschen. Bis dahin, siehe „svndumpfilter“ für einen möglichen Notbehelf.