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.
Hier endet die automatische Magie. sobald Sie früher oder später den Dreh beim Verzweigen und Zusammenführen heraus haben, werden Sie Subversion fragen müssen, bestimmte Änderungen von einem Ort zum anderen zusammenzuführen. Um dies tun zu können, werden Sie damit beginnen müssen, kompliziertere Argumente an svn merge zu übergeben. Der nächste Abschnitt beschreibt die vollständig erweiterte Syntax des Befehls und behandelt eine Anzahl verbreiteter Szenarien, die diese erforderlich macht.
Genauso oft wie der Begriff „Änderungsmenge“ wird der Ausdruck Rosinenpicken in Versions-Kontroll-Systemen verwendet. Das bezieht sich darauf, eine bestimmte Änderungsmenge von einem Zweig auszuwählen und sie auf einen anderen anzuwenden. Rosinenpicken kann sich auch darauf beziehen, eine bestimmte Menge von (nicht notwendigerweise angrenzenden) Änderungsmengen von einem auf einen anderen Zweig zu duplizieren. Dieses Vorgehen steht im Gegensatz zu den üblicheren Merge-Szenarien, bei denen der „nächste“ zusammenhängende Bereich von Revisionen automatisch dupliziert wird.
Warum sollte jemand nur eine einzelne Änderung wollen? Das
kommt häufiger vor, als Sie denken. Gehen wir beispielsweise
einmal davon aus, dass Sie einen neuen Arbeitszweig
/calc/branches/my-calc-feature-branch
durch
kopieren von /calc/trunk
erstellt
haben:
$ svn log ^/calc/branches/new-calc-feature-branch -v -r403 ------------------------------------------------------------------------ r403 | user | 2013-02-20 03:26:12 -0500 (Mi, 20. Feb 2013) | 1 Zeile Geänderte Pfade: A /calc/branches/new-calc-feature-branch (from /calc/trunk:402) Einen neuen Zweig calc für Arbeit an 'X' erzeugt. ------------------------------------------------------------------------
In der Kaffeeküche bekommen Sie mit, dass Sally eine
interessante Änderung an main.c
auf
Trunk gemacht hat. Als Sie sich die Geschichte der
Übertragungen auf Trunk ansehen, entdecken Sie, dass sie in
Revision 413 einen kritischen Fehler beseitigt hat, der
direkte Auswirkungen auf die Funktion hat, an der Sie gerade
arbeiten. Es kann sein, dass Sie noch nicht bereit sind, alle
Änderungen vom Stamm zu übernehmen, jedoch benötigen Sie diese
bestimmte Fehlerbehebung, um mit Ihrer Arbeit weitermachen zu
können.
Ebenso wie Sie svn diff im vorigen Beispiel benutzt haben, um sich Revision 355 anzusehen, können Sie die gleiche Option an svn merge übergeben:
$ svn log ^/calc/trunk -r413 -v ------------------------------------------------------------------------ r413 | sally | 2013-02-21 01:57:51 -0500 (Do, 21. Feb 2013) | 3 Zeilen Geänderte Pfade: M /calc/trunk/src/main.c Fehler #22 'Übergabe eines Null-Wertes im Argument foo von bar() sollte erlaubt sein, aber ruft Schutzverletzung hervor'. ------------------------------------------------------------------------ $ svn diff ^/calc/trunk -c413 Index: src/main.c =================================================================== --- src/main.c (Revision 412) +++ src/main.c (Revision 413) @@ -34,6 +34,7 @@ … Details zur Fehlerbehebung …
So wie Sie svn diff im vorangegangenen Beispiel verwendet haben, um Revision 413 zu untersuchen, können Sie die gleiche Option an svn merge übergeben:
$ cd new-calc-feature-branch $ svn merge ^/calc/trunk -c413 --- Zusammenführen von r413 in ».«: U src/main.c -- Aufzeichnung der Informationen für Zusammenführung von r413 in ».«: U . $ svn st M . M src/main.c
Sie können nun Ihre üblichen Tests durchführen, bevor Sie
diese Änderung an den Zweig übertragen. Nach der Übertragung
bringt Subversion das svn:mergeinfo
ihres
Zweigs auf den neuesten Stand, um festzuhalten, dass r413 mit
dem Zweig zusammengeführt wurde. Das verhindert, dass künftige
automatische Synchronisierungs-Merges versuchen, r413 erneut
zusammenzuführen. (Das Mergen derselben Änderung auf denselben
Zweig führt fast immer zu einem Konflikt!) Beachten Sie auch
das Mergeinfo
/calc/branches/my-calc-branch:341-379
, Das wurde bei
unserem in r380 gemachten Reintegrations-Merge nach
/calc/trunk
vom Zweig
/calc/branches/my-calc-branch
aufgezeichnet. Als
wir den Zweig my-calc-branch
in r403
erstellt haben, wurde diese Mergeinfo mit der Kopie
mitgenommen.
$ svn pg svn:mergeinfo -v Eigenschaften von ».«: svn:mergeinfo /calc/branches/my-calc-branch:341-379 /calc/trunk:413
Beachten Sie auch, dass mergeinfo r413 nicht als Kandidaten für einen Merge anzeigt, da sie bereits zusammengeführt wurde:
$ svn mergeinfo ^/calc/trunk --show-revs eligible r404 r405 r406 r407 r409 r410 r411 r412 r414 r415 r416 … r455 r456 r457
Das oben stehende bedeutet, dass Subversion den Merge in
zwei Teile aufspaltet, wenn schließlich die Zeit für einen
automatischen Synchronisierungs-Merge gekommen ist. Zunächst
werden alle in Frage kommenden Merges bis Revision 412
ausgeführt. Dann werden alle in Frage kommenden Revisionen
von Revision 412 bis zur Revision HEAD
zusammengeführt. Da wir uns bereits r413 herausgepickt haben,
wird diese Änderung übersprungen:
$ svn merge ^/calc/trunk --- Zusammenführen von r403 bis r412 in ».«: U doc/INSTALL U src/main.c U src/button.c U src/integer.c U Makefile U README --- Zusammenführen von r414 bis r458 in ».«: G doc/INSTALL G src/main.c G src/integer.c G Makefile -- Aufzeichnung der Informationen für Zusammenführung von r403 bis r458 in ».«: U .
Dieser Anwendungsfall des Abgleichens (oder Nachziehens) von Fehlerbehebungen von einem Zweig zu einem anderen ist vielleicht der gängigste Grund des Rosinenpickens bei Änderungen; es kommt ständig vor, beispielsweise, wenn ein Team einen „Software-Release-Zweig“ verwendet. (Wir erörtern dieses Muster in „Release-Zweige“.)
Warnung | |
---|---|
Haben Sie bemerkt, wie im letzten Beispiel der Aufruf von svn merge zwei unterschiedliche Abgleichsintervalle zusammengeführt hat? Der Befehl führte zwei unabhängige Patches auf Ihrer Arbeitskopie aus, um die Änderungsmenge 413 zu überspringen, die Ihr Zweig bereits beinhaltete. An und für sich ist daran nichts falsch, bis auf die Tatsache, dass die Möglichkeit besteht, eine Konfliktauflösung komplizierter zu machen. Falls das erste Änderungsintervall Konflikte erzeugt, müssen Sie diese interaktiv auflösen, um den Merge fortzusetzen und das zweite Änderungsintervall anzuwenden. Wenn Sie die Konfliktauflösung der ersten Phase aufschieben, wird der komplette Merge-Befehl mit einer Fehlermeldung abbrechen und Sie müssen den Konflikt auflösen, bevor Sie den Merge erneut anwenden, um den Rest der Änderungen zu bekommen. |
Ein Wort zur Warnung: Während svn diff und svn merge vom Konzept her sehr ähnlich sind, haben sie in vielen Fällen eine unterschiedliche Syntax. Stellen Sie sicher, dass Sie Details hierzu in svn Referenz – Subversion-Kommandozeilen-Client nachlesen oder svn help fragen. Zum Beispiel benötigt svn merge einen Pfad in der Arbeitskopie als Ziel, d.h., einen Ort, an dem es den erzeugten Patch anwenden kann. Falls das Ziel nicht angegeben wird, nimmt es an, dass Sie eine der folgenden häufigen Operationen durchführen möchten:
Sie möchten Verzeichnisänderungen auf Ihr aktuelles Arbeitsverzeichnis abgleichen.
Sie möchten die Änderungen in einer bestimmten Datei mit einer Datei gleichen Namens in Ihrem aktuellen Arbeitsverzeichnis zusammenführen.
Falls Sie ein Verzeichnis zusammenführen und keinen Zielpfad angegeben haben, nimmt svn merge den ersten Fall an und versucht, die Änderungen auf Ihr aktuelles Arbeitsverzeichnis anzuwenden. Falls Sie eine Datei zusammenführen und diese Datei (oder eine gleichnamige Datei) in Ihrem aktuellen Arbeitsverzeichnis existiert, nimmt svn merge den zweiten Fall an und wendet die Änderungen auf eine lokale Datei gleichen Namens an.
Sie haben nun einige Beispiele zum Befehl svn merge gesehen und werden bald einige mehr sehen. Falls Sie verwirrt sind, wie das Zusammenführen genau funktioniert, sind Sie nicht allein. Viele Anwender (besonders diejenigen, für die Versionskontrolle etwas Neues ist) sind anfangs verwirrt mit der korrekten Syntax des Befehls und wann das Feature verwendet werden soll. Aber, keine Angst, dieser Befehl ist tatsächlich viel einfacher als Sie denken! Es gibt eine einfache Technik, zum genauen Verstehen des Verhaltens von svn merge.
Die Hauptquelle der Verwirrung ist der Name des Befehls. Der Begriff „merge“ (Zusammenführung, Mischung) deutet irgendwie an, dass Zweige miteinander verschmolzen werden, oder dass irgendeine geheimnisvolle Mischung der Daten erfolgt. Das ist nicht der Fall. Ein besserer Name für den Befehl wäre vielleicht svn ermittele-die-Unterschiede-und-wende-sie-an gewesen, da das alles ist, was passiert: Die Bäume im Projektarchiv werden verglichen und die Unterschiede in eine Arbeitskopie eingearbeitet.
Falls Sie svn merge benutzen, um einfache Kopien von Änderungen zwischen Zweigen vorzunehmen, wird ein automatischer Merge üblicherweise das Richtige machen. Beispielsweise wird ein Befehl wie der folgende:
$ svn merge ^/calc/branches/some-branch
versuchen, alle Änderungen, die auf
some-branch
gemacht worden sind, in Ihr
aktuelles Arbeitsverzeichnis zu kopieren, das vermutlich eine
irgendeine mit dem Zweig historisch verbindene Arbeitskopie
ist. Der Befehl ist intelligent genug, nur die Änderungen zu
kopieren, die noch nicht in Ihrer Arbeitskopie sind. Wenn Sie
diesen Befehl einmal pro Woche wiederholen, wird er nur die
„neuesten“ Änderungen vom Zweig kopieren, die
seit Ihrem letzten Merge stattfanden.
Wenn Sie den Befehl svn merge in seiner ganzen Pracht wählen, indem Sie ihm bestimmte Revisionsintervalle zum Kopieren übergeben, benötigt der Befehl drei Hauptargumente:
Einen Startbaum im Projektarchiv (häufig linke Seite des Vergleichs genannt)
Einen Endbaum im Projektarchiv (häufig rechte Seite des Vergleichs genannt)
Eine Arbeitskopie, die die Unterschiede als lokale Änderungen aufnimmt (häufig Ziel der Zusammenführung genannt)
Sobald diese drei Argumente angegeben sind, werden die zwei Bäume miteinander verglichen und die Unterschiede als lokale Änderungen auf das Ziel angewendet. ist der Befehl abgeschlodssen, sieht das Ergebnis so aus, als hätten Sie die Dateien manuell editiert oder verschiedene svn add- oder svn delete-Befehle ausgeführt. Wenn Ihnen das Ergebnis gefällt, können Sie es übertragen. Falls nicht, können Sie einfach alle Änderungen mit svn revert rückgängig machen.
Die Syntax von svn merge erlaubt Ihnen, die drei notwendigen Argumente auf eine recht flexible Weise anzugeben. Hier sind einige Beispiele:
$ svn merge http://svn.example.com/repos/branch1@150 \ http://svn.example.com/repos/branch2@212 \ my-working-copy $ svn merge -r 100:200 http://svn.example.com/repos/trunk my-working-copy $ svn merge -r 100:200 http://svn.example.com/repos/trunk
Die erste Syntax führt alle drei Argumente explizit auf, indem jeder Baum mit dem Format URL@REV bezeichnet und die Ziel-Arbeitskopie angegeben wird. Die zweite Syntax wird als Kurzform verwendet, wenn Sie zwei unterschiedliche Revisionen desselben URL vergleichen. Die letzte Syntax zeigt, dass das Arbeitskopie-Argument optional ist; entfällt es, wird das aktuelle Verzeichnis genommen.
Obwohl das erste Beispiel die „vollständige“
Syntax von svn merge zeigt, verwenden Sie
sie sehr sorgfältig; es können hierbei Merges entstehen, bei
denen keinerlei svn:mergeinfo
-Metadaten
aufgezeichnet werden. Der nächste Abschnitt geht näher darauf
ein.
Subversion versucht immer wenn es kann, Metadaten über das
Zusammenführen zu erzeugen, um spätere Aufrufe von
svn merge klüger zu machen. Trotzdem
gibt es Situationen, in denen
svn:mergeinfo
-Daten nicht erzeugt oder
geändert werden. Denken Sie daran, vor diesen Szenarien auf
der Hut zu sein:
Falls Sie svn merge dazu auffordern, zwei URLs zu vergleichen, die nicht miteinander in Beziehung stehen, wird trotzdem ein Patch erzeugt und auf die Arbeitskopie angewendet, allerdings werden keine Metadaten erzeugt. Es gibt keine gemeinsame Geschichte der zwei Quellen, und spätere „kluge“ Merges hängen von dieser gemeinsamen Geschichte ab.
Obwohl es möglich ist, einen Befehl wie
svn merge -r 100:200
auszuführen, hat auch dieser resultierende Patch keine
historischen Metadaten über die Zusammenführung.
Zum gegenwärtigen Zeitpunkt hat Subversion keine
Möglichkeit, unterschiedliche Projektarchiv-URLs
mit Eigenschaft http://svn.foreignproject.com/repos/trunk
svn:mergeinfo
zu
repräsentieren.
--ignore-ancestry
Wenn diese Option an svn merge übergeben wird, veranlasst das die Merge-Logik, ohne nachzudenken Unterschiede auf dieselbe Art zu erzeugen, wie es svn diff macht und ignoriert dabei irgendwelche historischen Verbindungen. Wir werden das später in diesem Kapitel in „Die Abstammung berücksichtigen oder ignorieren“ erörtern.
Weiter oben in diesem Kapitel
(„Änderungen rückgängig machen“)
haben wir darüber gesprochen, wie man mit svn
merge einen „Rückwärts-Patch“
verwendet, um Änderungen rückgängig zu machen. Wenn
diese Technik dazu verwendet wird, um eine Änderung in
der Geschichte eines Objektes zurückzunehmen (z.B. r5
an den Stamm übertragen, und dann sofort r5 mit
svn merge . -c -5
rückgängig
machen), hat dies keine Auswirkungen auf die
aufgezeichneten
Mergeinfo.[43]
Wie der Befehl svn update wendet auch svn merge Änderungen auf Ihre Arbeitskopie an. Und deshalb kann er auch Konflikte erzeugen. Die von svn merge hervorgerufenen Konflikte sind jedoch manchmal anders geartet, und dieser Abschnitt erklärt diese Unterschiede.
Zunächst gehen wir davon aus, dass Ihre Arbeitskopie keine lokalen Änderungen enthält. Wenn Sie mit svn update auf eine bestimmte Revision aktualisieren, werden die vom Server gesendeten Änderungen immer „sauber“ auf Ihre Arbeitskopie angewendet. Der Server erzeugt das Delta, indem er zwei Bäume vergleicht: eine virtuelle Momentaufnahme Ihrer Arbeitskopie und der Revisionsbaum, an dem Sie interessiert sind. Da die linke Seite des Vergleichs völlig gleich zu dem ist, was Sie bereits haben, wird das Delta garantiert Ihre Arbeitskopie korrekt in den rechten Baum überführen.
svn merge jedoch kann das nicht gewährleisten und kann viel chaotischer sein: Der fortgeschrittene Benutzer kann den Server auffordern, irgendwelche zwei Bäume miteinander zu vergleichen, sogar solche, die nicht mit der Arbeitskopie in Beziehung stehen! Das bedeutet, dass ein hohes Potenzial für menschliche Fehler besteht. Benutzer werden manchmal die falschen zwei Bäume miteinander vergleichen, so dass ein Delta erzeugt wird, das sich nicht sauber anwenden lässt. Der Unterbefehl svn merge gibt sein Bestes, um soviel wie möglich vom Delta anzuwenden, doch bei einigen Teilen kann das unmöglich sein. Ein häufiges Anzeichen, dass Sie die falschen Unterschiede eingepflegt haben, sind unerwartete Baumkonflikte:
$ svn merge ^/calc/trunk -r104:115 -- Zusammenführen von r105 bis r115 in ».«: C doc C src/button.c C src/integer.c C src/real.c C src/main.c -- Aufzeichnung der Informationen für Zusammenführung von r105 bis r115 in ».«: U . Konfliktübersicht: Baumkonflikte: 3 $ svn st M . ! C doc > lokal Verzeichnis fehlend, empfangen Verzeichnis editiert bei Zusammenführung ! C src/button.c > lokal Datei fehlend, empfangen Verzeichnis editiert bei Zusammenführung ! C src/integer.c > lokal Datei fehlend, empfangen Verzeichnis editiert bei Zusammenführung ! C src/main.c > lokal Datei fehlend, empfangen Verzeichnis editiert bei Zusammenführung ! C src/real.c > lokal Datei fehlend, empfangen Verzeichnis editiert bei Zusammenführung Konfliktübersicht: Baumkonflikte: 5
Im vorangegangenen Beispiel kann es der Fall gewesen sein,
dass doc
und die vier
*.c
-Dateien alle in beiden
Momentaufnahmen des Zweiges vorkommen, die verglichen werden.
Das resultierende Delta will den Inhalt der entsprechenden
Pfade in Ihrer Arbeitskopie verändern, doch sind diese Pfade
in der Arbeitskopie aber nicht vorhanden. Wie auch immer, das
Überwiegen von Baumkonflikten bedeutet höchstwahrscheinlich,
dass der Benutzer die falschen Bäume miteinander verglichen
hat oder Sie machen einen Merge auf das falsche Ziel in der
Arbeitskopie; beides sind klassische Zeichen für einen
Anwenderfehler. Falls dies passiert, ist es einfach, alle
durch das Zusammenführen hervorgerufenen Änderungen rekursiv
rückgängig zu machen (svn revert .
--recursive
), alle unversionierten Dateien oder
Verzeichnisse zu löschen, die nach dem Rückgängigmachen
zurückgeblieben sind und svn merge noch
einmal mit unterschiedlichen Argumenten aufzurufen.
Beachten Sie ebenfalls, dass eine Zusammenführung in eine Arbeitskopie ohne lokale Änderungen trotzdem Textkonflikte erzeugen kann.
$ svn st $ svn merge ^/paint/trunk -r289:291 -- Zusammenführen von r290 bis r291 in ».«: C Makefile -- Aufzeichnung der Informationen für Zusammenführung von r290 bis r291 in ».«: U . Konflikt in Datei »Makefile« entdeckt. Auswahl: (p) später auflösen, (df) Änderungen anzeigen, (e) Dateibearbeiten, (m) Zusammenführung, (mc) eigene Seite des Konflikts, (tc) fremde Seite des Konflikts, (s) alle Optionen anzeigen: p Konfliktübersicht: Textkonflikte: 1 $ svn st M . C Makefile ? Makefile.merge-left.r289 ? Makefile.merge-right.r291 ? Makefile.working Konfliktübersicht: Textkonflikte: 2
Wie kann da ein Konflikt entstehen? Noch einmal: Weil der Benutzer svn merge dazu auffordern kann, ein altes Delta zu definieren und auf die Arbeitskopie anzuwenden, kann es sein, dass dieses alte Delta textuelle Änderungen enthält, die nicht sauber in eine Arbeitsdatei eingearbeitet werden können, selbst dann nicht, wenn die Datei keine lokalen Änderungen vorzuweisen hat.
Ein weiterer kleiner Unterschied zwischen svn
update und svn merge sind die
Namen der erzeugten Textdateien, falls ein Konflikt entsteht.
In „Lösen Sie etwaige Konflikte auf“ sahen wir, dass
bei einer Aktualisierung die Dateien namens
filename.mine
,
filename.rOLDREV
und
filename.rNEWREV
erzeugt werden. Falls
svn merge einen Konflikt hervorruft,
erstellt es jedoch drei Dateien namens
filename.working
,
filename.merge-left.rOLDREV
und
filename.merge-right.rNEWREV
. In diesem
Fall beschreiben die Begriffe „merge-left“ und
„merge-right“ von welcher Seite des Vergleichs
zwischen den beiden Bäumen die Datei hergeleitet wurde,
„rOLDREV“ beschreibt die Revision auf der linken
Seite und „rNEWREV“ die Revision auf der rechten
Seite. Auf alle Fälle werden Ihnen diese unterschiedlichen
Namen dabei helfen, zwischen Konflikten zu unterscheiden, die
durch eine Aktualisierung entstanden, und solchen die durch
eine Zusammenführung hervorgerufen wurden .
Manchmal gibt es eine bestimmte Änderungsmenge, die Sie
nicht automatisch zusammengeführt haben wollen. Beispielsweise
ist vielleicht die Vorgehensweise Ihres Teams dergestalt, dass
Neuentwicklungen auf /trunk
gemacht
werden, aber konservativer, wenn es darum geht, Änderungen auf
einen stabilen Zweig zurück zu portieren, den sie zur
Veröffentlichung benutzen. Auf der einen Seite können Sie
die Rosinen in Form von einzelnen Änderungsmengen manuell aus
dem Stamm herauspicken und in den Zweig einpflegen – nur
die Änderungen, die stabil genug sind, um die Qualitätsprüfung
zu bestehen. Vielleicht ist es ja auch nicht ganz so streng,
und Sie möchten normalerweise, dass svn
merge die meisten Änderungen vom Stamm automatisch
mit dem Zweig zusammenführt. In diesem Fall brauchen Sie ein
Verfahren, dass es Ihnen erlaubt, einige bestimmte
Änderungen auszulassen, d.h. zu vermeiden, dass sie
automatisch in den Zweig eingebracht werden.
Um eine
Änderungsmenge zu blockieren müssen Sie Subversion
vorzugaukeln, dass die Änderung bereits
eingearbeitet wurde. Dazu rufen Sie den Unterbefehl mit der Option
--record-only
auf. Das veranlasst Subversion
dazu, Mergeinfo wie bei einem tatsächlichen Merge anzulegen,
obwohl kein Diff angewendet worden ist:
$ cd my-calc-branch $ svn merge ^/calc/trunk -r386:388 --record-only -- Aufzeichnung der Informationen für Zusammenführung von r387 bis r388 in ».«: U . Nur Mergeinfo wird geändert. $ svn st M . $ svn pg svn:mergeinfo -vR Eigenschaften von ».«: svn:mergeinfo /calc/trunk:341-378,387-388 $ svn commit -m "Das Zusammenführen von r387-388 mit my-calc-branch verhindern." Sende . Revision 461 übertragen.
Seit Subversion 1.7 sind Zusammenführungen mit
--record-only
transitiv. Das bedeutet, dass
zusätzlich zur Aufzeichnung der Mergeinfo die die
blockierte(n) Revision(en) beschreiben, alle Unterschiede der
Eigenschaft svn:mergeinfo
der Quelle
ebenfalls angewendet werden. Sagen wir mal zum Beispiel, dass
wir die Zusammenführung der Funktionalität
"paint-python-wrapper" von ^/paint/trunk
mit unserem ^/paint/branches/paint-1.0.x
Zweig für immer blockieren möchten. Wir wissen, dass die
gesamte Arbeit an dieser Funktionalität auf seinem eigenen
Zweig gemacht wurde, der in Revision 465 wieder in
/paint/trunk
eingegliedert wurde:
$ svn log -v -r465 ^/paint/trunk ------------------------------------------------------------------------ r465 | joe | 2013-02-25 14:05:12 -0500 (Mo, 25. Feb 2013) | 1 Zeile Geänderte Pfade: M /paint/trunk A /paint/trunk/python (von /paint/branches/paint-python-wrapper/python:464) Paint Python Wrapper reintegriert. ------------------------------------------------------------------------
Da Revision 465 eine Zusammenführung zur Wiedereingliederung war, wissen wir, dass beschreibende Informationen aufgezeichnet wurden:
$ svn diff ^/paint/trunk --depth empty -c465 Index: . =================================================================== --- . (revision 464) +++ . (revision 465) Eigenschaftsänderungen: . ___________________________________________________________________ Hinzugefügt: svn:mergeinfo Zusammengeführt /paint/branches/paint-python-wrapper:r463-464
Das einfache Blockieren der Zusammenführungen der Revision
465 von /paint/trunk
ist nicht
narrensicher, da jemand 462:464 direkt von
/paint/branches/paint-python-wrapper
zusammenführen könnte. Glücklicherweise wird das durch die
transitive Natur der Merges mit --record-only
verhindert: die Zusammenführung mit
--record-only
wendet den
svn:mergeinfo
-Diff von Revision 465 an, und
blockiert somit sowohl direkte Merges dieser Änderung von
/paint/trunk
als
auch indirekte von
/paint/branches/paint-python-wrapper
:
$ cd paint/branches/paint-1.0.x $ svn merge ^/paint/trunk --record-only -c465 -- Zusammenführen von r465 in ».«: U . -- Aufzeichnung der Informationen für Zusammenführung von r465 in ».«: G . $ svn diff --depth empty Index: . =================================================================== --- . (Revision 462) +++ . (Arbeitskopie) Eigenschaftsänderungen: . ___________________________________________________________________ Hinzugefügt: svn:mergeinfo Zusammengeführt /paint/branches/paint-python-wrapper:r463-464 Zusammengeführt /paint/trunk:r465 $ svn ci -m "Die Python-Wrapper aus der ersten Release von Paint sperren." Sende . Revision 466 übertragen.
Nun sind alle künftigen Versuche, die Funktionalität mit
/paint/trunk
zusammenzuführen,
inoperativ:
$ svn merge ^/paint/trunk -c465 -- Aufzeichnung der Informationen für Zusammenführung von r456 in ».«: U . $ svn st # keine Änderung $ svn merge ^/paint/branches/paint-python-wrapper -r462:464 -- Aufzeichnung der Informationen für Zusammenführung von r463 bis r464 in ».«: U . $ svn st # keine Änderung $
Falls Sie später feststellen, dass Sie die blockierte
Funktionalität doch nach
/paint/trunk
herüberbringen müssen,
haben Sie die Wahl. Sie können r466 (die Revision, in der die
Funktionalität blockiert wurde) rückwärts patchen wie in
„Änderungen rückgängig machen“ erörtert.
Sobald Sie die Änderung übertragen haben, können Sie r465 die
von /paint/trunk
zusammenführen.
Alternativ können Sie einfach r465 von
/paint/trunk
erneut zusammenführen, indem
Sie die Option --ignore-ancestry
verwenden,
die beim Zusammenführen jegliche Mergeinfo ignoriert und den
erwünschten Diff einfach anwendet; siehe
„Die Abstammung berücksichtigen oder ignorieren“.
$ svn merge ^/paint/trunk -c465 --ignore-ancestry -- Zusammenführen von r465 in ».«: A python A python/paint.py G .
Das Blockieren von Änderungen mit
--record-only
funktioniert zwar, es ist
allerdings auch ein wenig gefährlich. Das Hauptproblem ist,
dass wir nicht klar unterscheiden zwischen „ich habe
diese Änderung bereits“ und „ich habe diese
Änderung nicht, aber ich will sie jetzt nicht“. Wir
belügen das System gewissermaßen, indem wir es glauben lassen,
dass die Änderung schon eingearbeitet sei. Das schiebt die
Verantwortung, sich daran zu erinnern, dass die Änderung
tatsächlich gar nicht übernommen wurde sondern nicht gewünscht
war, auf Sie – den Benutzer. Es gibt keine Möglichkeit,
Subversion nach einer Liste „blockierter
Änderungen“ zu fragen. Wenn Sie sie verfolgen möchten
(so dass Sie eines Tages die Blockierung aufheben können)
müssen Sie sie irgendwo in eine Textdatei schreiben oder in
einer erfundenen Eigenschaft festhalten.
Ein Hauptmerkmal jedes Versions-Kontroll-Systems ist es, darüber Buch zu führen, wer was wann geändert hat. Die Unterbefehle svn log und svn blame sind die geeigneten Werkzeuge hierfür: Wenn sie auf individuelle Dateien angewendet werden, zeigen sie nicht nur die Geschichte der Änderungsmengen, die in diese Datei hineinflossen, sondern auch, welcher Benutzer wann welche Zeile im Quelltext geschrieben hat.
Wenn jedoch Änderungen über Zweige hinweg dupliziert werden, wird es schnell kompliziert. Wenn Sie z.B. svn log nach der Geschichte Ihres Zweigs fragen, wird es Ihnen exakt jede Revision anzeigen, die je in den Zweig hineingeflossen ist:
$ cd my-calc-branch $ svn log -q ------------------------------------------------------------------------ r461 | user | 2013-02-25 05:57:48 -0500 (Mo, 25. Feb 2013) ------------------------------------------------------------------------ r379 | user | 2013-02-18 10:56:35 -0500 (Mo, 18. Feb 2013) ------------------------------------------------------------------------ r378 | user | 2013-02-18 09:48:28 -0500 (Mo, 18. Feb 2013) ------------------------------------------------------------------------ … ------------------------------------------------------------------------ r8 | sally | 2013-01-17 16:55:36 -0500 (Do, 17. Jan 2013) ------------------------------------------------------------------------ r7 | bill | 2013-01-17 16:49:36 -0500 (Do, 17. Jan 2013) ------------------------------------------------------------------------ r3 | bill | 2013-01-17 09:07:04 -0500 (Do, 17. Jan 2013) ------------------------------------------------------------------------
Aber ist das wirklich eine genaue Wiedergabe aller Änderungen, die auf dem Zweig stattgefunden haben? Was hier ausgelassen wird, ist, dass die Revisionen 352, 362, 372 und 379 tatsächlich Ergebnisse des Zusammenführens von Änderungen aus dem Stamm waren. Wenn Sie sich eins dieser Protokolle im Detail anschauen, können Sie die verschiedenen Änderungsmengen vom Stamm, die die Änderungen auf dem Zweig ausmachen, nirgendwo sehen:
$ svn log ^/calc/branches/my-calc-branch -r352 -v ------------------------------------------------------------------------ r352 | user | 2013-02-16 09:35:18 -0500 (Sa, 16. Feb 2013) | 1 Zeile Geänderte Pfade: M /calc/branches/my-calc-branch M /calc/branches/my-calc-branch/Makefile M /calc/branches/my-calc-branch/doc/INSTALL M /calc/branches/my-calc-branch/src/button.c M /calc/branches/my-calc-branch/src/real.c Synchronisierung der letzten Änderungen von trunk mit my-calc-branch.
Wir wissen, dass diese Zusammenführung in den Zweig nichts
anderes war als ein Merge von Änderungen vom Stamm. Wie
können wir zusätzlich diese Änderungen sehen? Die Antwort
lautet, die Option --use-merge-history
(-g
) zu verwenden. Diese Option expandiert
diejenigen „Teil“-Änderungen, aus denen die
Zusammenführung bestand.
$ svn log ^/calc/branches/my-calc-branch -r352 -v -g ------------------------------------------------------------------------ r352 | user | 2013-02-16 09:35:18 -0500 (Sa, 16. Feb 2013) | 1 Zeile Geänderte Pfade: M /calc/branches/my-calc-branch M /calc/branches/my-calc-branch/Makefile M /calc/branches/my-calc-branch/doc/INSTALL M /calc/branches/my-calc-branch/src/button.c M /calc/branches/my-calc-branch/src/real.c Synchronisierung der letzten Änderungen von trunk mit my-calc-branch. ------------------------------------------------------------------------ r351 | sally | 2013-02-16 08:04:22 -0500 (Sa, 16. Feb 2013) | 2 Zeilen Geänderte Pfade: M /calc/trunk/src/real.c Zusammengeführt mittels: r352 Arbeiten auf dem Stamm vom calc-Projekt. ------------------------------------------------------------------------ … ------------------------------------------------------------------------ r345 | sally | 2013-02-15 16:51:17 -0500 (Fr, 15. Feb 2013) | 2 Zeilen Geänderte Pfade: M /calc/trunk/Makefile M /calc/trunk/src/integer.c Zusammengeführt mittels: r352 Arbeiten auf dem Stamm vom calc-Projekt. ------------------------------------------------------------------------ r344 | sally | 2013-02-15 16:44:44 -0500 (Fr, 15. Feb 2013) | 1 Zeile Geänderte Pfade: M /calc/trunk/src/integer.c Zusammengeführt mittels: r352 Die bazzle-Funktionen refaktoriert.
Dadurch, dass wir die Protokoll-Operation aufgefordert haben, die Geschichte der Zusammenführungen zu verwenden, sehen wir nicht nur die Revision, die wir abgefragt haben (r352), sondern auch die anderen Revisionen, die hier mitkamen – die Arbeit von Sally auf dem Stamm. Das ist ein wesentlich vollständigeres Bild der Geschichte!
Auch der svn blame-Befehl versteht die
Option --use-merge-history
(-g
). Falls diese Option vergessen wird,
könnte jemand, der sich die zeilenweisen Anmerkungen von
src/button.c
ansieht, fälschlicherweise davon
ausgehen, dass Sie für die Zeilen einer bestimmten Änderung
verantwortlich sind:
$ svn blame src/button.c … 352 user retval = inverse_func(button, path); 352 user return retval; 352 user } …
Obwohl es zutrifft, dass Sie diese drei Zeilen in Revision 352 übertragen haben, sind zwei davon tatsächlich von Sally in Revision 348 geschrieben worden und sind durch einen Synchronisierungs-Merge in Ihren Zweig geraten:
$ svn blame button.c -g … G 348 sally retval = inverse_func(button, path); G 348 sally return retval; 352 user } …
Nun wissen wir, wer wirklich für die zwei Zeilen Quelltext verantwortlich ist!
Wenn Sie sich mit einem Subversion-Entwickler unterhalten, wird wahrscheinlich auch der Begriff Abstammung erwähnt. Dieses Wort wird verwendet, um die Beziehung zwischen zwei Objekten im Projektarchiv zu beschreiben: Wenn sie in Beziehung zueinander stehen, heißt es, dass ein Objekt vom anderen abstammt.
Nehmen wir an, Sie übertragen Revision 100, die eine
Änderung an der Datei foo.c
beinhaltet.
Dann ist foo.c@99
ein
„Vorfahre“ von foo.c@100
.
Wenn Sie dagegen in Revision 101 die Löschung von
foo.c
übertragen und in Revision 102 eine
neue Datei mit demselben Namen hinzufügen, hat es zwar den
Anschein, dass foo.c@99
und
foo.c@102
in Beziehung zueinander stehen
(sie haben denselben Pfad), es handelt sich allerdings um
völlig unterschiedliche Objekte im Projektarchiv. Sie haben weder
eine gemeinsame Geschichte noch
„Abstammung“.
Wir erwähnen das, um auf einen wichtigen Unterschied
zwischen den Befehlen svn diff und
svn merge hinzuweisen. Der erstere Befehl
ignoriert die Abstammung, wohingegen letzterer diese beachtet.
Wenn Sie beispielsweise mit svn diff die
Revisionen 99 und 102 von foo.c
vergleichen, werden Sie zeilenbasierte Unterschiede sehen; der
Befehl diff vergleicht blind zwei Pfade.
Wenn Sie aber dieselben Objekte mit svn
merge vergleichen, wird es feststellen, dass sie
nicht in Beziehung stehen und versuchen, die alte Datei zu
löschen und dann die neue hinzuzufügen; die Ausgabe wird eine
Löschung gefolgt von einer Hinzufügung anzeigen:
D foo.c A foo.c
Die meisten Zusammenführungen vergleichen Bäume, die von
der Abstammung her miteinander in Beziehung stehen, deshalb
verhält sich svn merge auf diese Weise.
Gelegentlich möchten Sie jedoch mit dem
merge-Befehl zwei Bäume vergleichen, die
nicht miteinander in Beziehung stehen. Es kann z.B. sein, dass
Sie zwei Quelltext-Bäume importiert haben, die unterschiedliche
Lieferantenstände eines Software-Projektes repräsentieren
(siehe „Lieferanten-Zweige“). Falls Sie
svn merge dazu aufforderten, die beiden Bäume
miteinander zu vergleichen, würden Sie sehen, dass der
vollständige erste Baum gelöscht und anschließend der
vollständige zweite Baum hinzugefügt würde! In diesen
Situationen möchten Sie, dass svn merge
lediglich einen pfadbasierten Vergleich vornimmt und
Beziehungen zwischen Dateien und Verzeichnissen außer Acht
lässt. Fügen Sie die Option --ignore-ancestry
dem merge-Befehl hinzu, und er wird sich
verhalten wie svn diff. (Auf der anderen
Seite wird die Option --notice-ancestry
den
Befehl svn diff dazu veranlassen, sich wie
svn merge zu verhalten.
Tipp | |
---|---|
Die Option |
Es ist ein verbreiteter Wunsch, Software zu refaktorieren, besonders in Java-basierten Software-Projekten. Dateien und Verzeichnisse werden hin und her geschoben und umbenannt, was häufig zu erheblichen Beeinträchtigungen für alle Projektmitarbeiter führt. Das hört sich an, als sei das der klassische Fall, um nach einem Zweig zu greifen, nicht wahr? Sie erzeugen einfach einen Zweig, schieben das Zeug herum und führen anschließend den Zweig mit dem Stamm zusammen.
Leider funktioniert dieses Szenario im Augenblick noch nicht so richtig und gilt als einer der Schwachpunkte von Subversion. Das Problem ist, das der Subversion-Befehl svn merge nicht so stabil ist, wie er sein sollte, besonders wenn es um Kopier- und Verschiebeoperationen geht.
Wenn Sie svn copy zum Duplizieren einer Datei verwenden, merkt sich das Projektarchiv, woher die neue Datei kam, versäumt aber, diese Information an den Client zu senden, der svn update oder svn merge ausführt. Statt dem Client mitzuteilen: „Kopiere die Datei, die du bereits hast an diesen neuen Ort“, sendet es eine völlig neue Datei. Das kann zu Problemen führen, im Falle von Umbenennungen besonders zu Baumkonflikten, die nicht nur die neue Kopie betreffen, sondern die Löschung des alten Pfades ^ndash; eine weniger bekannte Tatsache über Subversion ist, dass es keine „echten Umbenennungen“ hat – der Befehl svn move ist weiter nichts als eine Verbindung von svn copy und svn delete.
Nehmen wir beispielsweise an, dass Sie einige Änderungen
an Ihrem privaten Zweig /calc/branch/my-calc-branch
machen möchten. Zunächst führen Sie einen
automatischen Synchronisierungs-Merge mit
/calc/trunk
durch und übertragen das
Ergebnis in r470:
$ cd calc/trunk $ svn merge ^/calc/trunk -- Zusammenführen der Unterschiede zwischen Projektarchiv-URLs in ».«: U doc/INSTALL A FAQ U src/main.c U src/button.c U src/integer.c U Makefile U README U . -- Aufzeichnung der Informationen für Zusammenführung zwischen Projektarchiv-URLs in ».«: U . $ svn ci -m "Synchronisierung aller Änderungen von ^/calc/trunk bis r469." Sende . Sende Makefile Sende README Sende FAQ Sende doc/INSTALL Sende src/main.c Sende src/button.c Sende src/integer.c Übertrage Daten .... Revision 470 übertragen.
Dann benennen Sie in r471 integer.c
in whole.c
um und editieren dieselbe
Datei in r473. Tatsächlich haben Sie eine neue Datei auf Ihrem
Zweig erzeugt (die eine Kopie der ursprünglichen Datei plus
einiger Bearbeitungen ist) und die ursprüngliche Datei
gelöscht. Zwischenzeitlich hat Sally in r472 auf
/calc/trunk
selber einige Verbesserungen
an integer.c
übertragen:
$ svn log -v -r472 ^/calc/trunk ------------------------------------------------------------------------ r472 | sally | 2013-02-26 07:05:18 -0500 (Di, 26. Feb 2013) | 1 Zeile Geänderte Pfade: M /calc/trunk/src/integer.c Arbeit auf dem Stamm von integer.c. ------------------------------------------------------------------------
Nun entscheiden Sie sich, Ihren Zweig auf den Stamm zurückzuführen. Wie wird Subversion Ihre Umbenennung und Bearbeitung mit den Bearbeitungen durch Sally kombinieren?
$ svn merge ^/calc/branches/my-calc-branch -- Zusammenführen der Unterschiede zwischen Projektarchiv-URLs in ».«: C src/integer.c U src/real.c A src/whole.c -- Aufzeichnung der Informationen für Zusammenführung zwischen Projektarchiv-URLs in ».«: U . Konfliktübersicht: Baumkonflikte: 1 $ svn st M . C src/integer.c > lokale Datei geändert, eingehendes Löschen einer Datei bei Zusammenführung M src/real.c A + src/whole.c Konfliktübersicht: Baumkonflikte: 1
Die Antwort ist, dass Subversion diese Änderungen
keineswegs kombiniert, sondern
stattdessen einen Baumkonflikt erzeugt[44], da es Ihre Hilfe benötigt, um
herauszufinden, welche Teile Ihrer Änderungen und welche Teile
von Sallys Änderungen schließlich in
whole.c
landen sollen, oder ob die
Umbenennung überhaupt stattfinden soll!
Vor der Übergabe werden Sie den Baumkonflikt auflösen müssen, was einiger manueller Eingriffe Ihrerseits bedarf, siehe „Umgang mit Strukturkonflikten“. Die Moral der Geschichte ist, dass Sie dabei vorsichtig sein sollten, wenn Sie Kopien und Umbenennungen zwischen Zweigen zusammenführen, und auf manuelle Eingriffe vorbereitet sind, bis sich Subversion verbessert.
Wenn Sie gerade Ihren Server auf Subversion 1.5 oder
größer umgestellt haben, besteht ein Risiko,
dass Subversion-Clients einer älteren Version als 1.5 Probleme
mit
Verfolgung von Zusammenführungen
bereiten können. Das liegt daran, dass Clients vor 1.5 diese
Funktionalität nicht unterstützen; wenn einer dieser älteren
Clients svn merge ausführt, modifiziert er
nicht den Wert der Eigenschaft svn:mergeinfo
.
Obwohl die anschließende Übergabe das Ergebnis einer
Zusammenführung ist, wird dem Projektarchiv nichts über die
duplizierten Änderungen mitgeteilt – diese Information
ist verloren. Wenn später Clients, die
Mergeinfo auswerten, automatische
Merges versuchen, werden Sie wahrscheinlich in alle
möglichen Konflikte laufen, die durch wiederholtes
Mergen hervorgerufen wurden.
Wenn Sie und Ihr Team auf die Merge-Verfolgung von
Subversion angewiesen sind, sollten Sie Ihr Projektarchiv
dergestalt konfigurieren, dass ältere Clients daran gehindert
werden, Änderungen zu übertragen. Die einfache Methode hierfür
ist es, den „Fähigkeiten“-Parameter im
start-commit-Hook-Skript zu untersuchen.
Wenn der Client meldet, dass er mit
mergeinfo
umgehen kann, kann das Skript den
Beginn der Übergabe erlauben. Wenn der Client diese Fähigkeit
nicht meldet, wird die Übergabe abgelehnt.
Beispiel 4.1, „Hook-Skript zum Start der Übertragung als Torwächter für die Merge-Verfolgung“ zeigt ein
Beispiel für ein solches Hook-Skript:
Beispiel 4.1. Hook-Skript zum Start der Übertragung als Torwächter für die Merge-Verfolgung
#!/usr/bin/env python import sys # Dieser Start-Commit-Hook wird aufgerufen, unmittelbar nachdem eine # Subversion-Transaktion im Zuge einer Übergabe begonnen und mit den # initialen Revisions-Eigenschaften versorgt wurde. Subversion führt # diesen Hook aus, indem ein Programm (Skript, ausführbare Datei, # Binärdatei, etc.) namens "start-commit" (für die diese Datei als # Vorlage dient) mit den folgenden geordneten Argumenten aufgerufen # wird: # # [1] REPOS-PATH (der Pfad zu diesem Projektarchiv) # [2] USER (der authentisierte Anwender, der übertragen möchte) # [3] CAPABILITIES (eine vom Client durch Doppelpunkte getrennte # Liste von Leistungsmerkmalen; siehe Anmerkung # unten) # [4] TXN-NAME (der Name der gerade erzeugten # Übertraguns-Transaktion) capabilities = sys.argv[3].split(':') if "mergeinfo" not in capabilities: sys.stderr.write("Übertragungen von Clients, die keine" "Zusammenführungs-Verfolgung unterstützen," "sind nicht erlaubt. Bitte auf Subversion 1.5 " "oder neuer aktualisieren.\n") sys.exit(1) sys.exit(0)
Für weitergehende Informationen zu Hook-Skripten, siehe nächsten Kapitel erfahren; siehe „Erstellen von Projektarchiv-Hooks“.
Unter dem Strich bedeutet das, dass die Fähigkeit von
Subversion zur Merge-Verfolgung eine komplexe interne
Implementierung besitzt und die Eigenschaft
svn:mergeinfo
das einzige Fenster zu diesem
Räderwerk ist.
Wie und wann Mergeinfo von einem Merge festgehalten wird, kann manchmal schwer zu verstehen sein.Darüber hinaus umgibt die Verwaltung der Mergeinfo-Metadaten eine ganze Menge von Systematiken und Verhalten, wie „explizite“ gegenüber „implizite“ Mergeinfo, „operative“ gegenüber „inoperative“ Revisionen, besondere Mechanismen von Mergeinfo-„Auslassung“ und sogar „Vererbung“ von Eltern- zu Kindverzeichnissen.
Wir haben uns entschieden, diese detaillierten Themen aus einer Reihe von Gründen nur kurz anzureißen. Erstens ist der Detaillierungsgrad für einen normalen Benutzer erdrückend. Zweitens, und das ist wichtiger, muss der typische Benutzer diese Konzepte nicht verstehen; sie sollten als Implementierugsdetails im Hintergrund bleiben. Wenn Sie, nachdem dies gesagt ist, diese Dinge mögen, können Sie einen fantastischen Überblick in einer Arbeit nachlesen, die auf der Webseite von CollabNet veröffentlicht ist:http://www.open.collab.net/community/subversion/articles/merge-info.html.
Fürs Erste empfehlen wir, sich an die folgenden bewährten Praktiken zu halten, sofern Sie die Komplexität der Verfolgung von Zusammenführungen umgehen möchten:
Wenden Sie für kurzlebige Arbeitszweige das Verfahren an, das in „Grundlegendes Zusammenführen“ beschrieben wird.
Vermeiden Sie Teilbaum-Merges und Teilbaum-Mergeinfo. Führen Sie Merges nur im Wurzelverzeichnis Ihrer Zweige durch und nicht in Unterverzeichnissen oder auf Dateien (siehe „Teilbaum-Merges und -Mergeinfo“).
Editieren Sie niemals direkt die Eigenschaft
svn:mergeinfo
; verwenden Sie
svn merge mit der Option
--record-only
, um eine gewünschte
Änderung an den Metadaten zu bewirken (wie in „Änderungen blockieren“
gezeigt).
Das Ziel Ihrer Zusammenführung sollte eine Arbeitskopie sein, die einen vollständigen Baum eines einzigen Ortes zu einem einzelnen Zeitpunkt im Projektarchiv repräsentiert:
Aktualisieren Sie vor der Zusammenführung.
Verwenden Sie nicht die Option
--allow-mixed-revisions
, um einen
Merge in Arbeitskopien mit gemischten Revisionen
zu machen.
Führen Sie nicht auf Ziele mit „umgestellten“ Unterverzeichnissen zusammen (wie gleich in „Zweige durchlaufen“ beschrieben wird).
Vermeiden Sie Zusammenführungen in Ziele mit
Teilverzeichnissen. Das Gleiche gilt für
Zusammenführungen mit anderen Tiefen als
--depth=infinity
Stellen Sie sicher, dass Sie vollständigen Lesezugriff auf die Quellen sowie Lese- und Schreibzugriff auf alle Ziele der Zusammenführung haben.
Natürlich müssen Sie manchmal einige dieser bewährten Praktiken verletzen. Machen Sie sich keine Sorgen, wenn das eintritt, verstehen Sie nur, was die Abweichungen nach sich ziehen.
[43] Interessanterweise werden wir
nach dem Zurücknehmen einer Revision auf diese Art nicht
in der Lage sein, diese Revision erneut mit
svn merge . -c 5
anzuwenden, da
aus den Metadaten hervorgeht, dass r5 bereits angewendet
wurde. Wir müssten die Option
--ignore-ancestry
verwenden, damit der
Befehl die bestehenden Metadaten
ignoriert.
[44] Falls
Sally ihre Änderung in r472 nicht gemacht hätte, dann wäre
Subversion aufgefallen, dass integer.c
in
der Ziel-Arbeitskopie identisch zu integer.c
auf der linken Seite des Merge ist, und hätte Ihnen die
Umbenennung ohne Baumkonflikt durchgehen lassen:
$ svn merge ^/calc/branches/my-calc-branch -- Zusammenführen der Unterschiede zwischen Projektarchiv-URLs in ».«: U src/real.c A src/whole.c D src/integer.c -- Aufzeichnung der Informationen für Zusammenführung zwischen Projektarchiv-URLs in ».«: U .