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.

Fortgeschrittenes Zusammenführen

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.

Rosinenpicken

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] 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.

Merge-Syntax: Die vollständige Offenlegung

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:

  1. Einen Startbaum im Projektarchiv (häufig linke Seite des Vergleichs genannt)

  2. Einen Endbaum im Projektarchiv (häufig rechte Seite des Vergleichs genannt)

  3. 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.

Mergen ohne Mergeinfo

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:

Zusammenführen von Quellen ohne Beziehung

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.

Zusammenführen aus fremden Projektarchiven

Obwohl es möglich ist, einen Befehl wie svn merge -r 100:200 http://svn.foreignproject.com/repos/trunk 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 svn:mergeinfo zu repräsentieren.

Verwendung von --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.

Zusammenführen rückgängig machen

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]

Mehr über Konflikte beim Zusammenführen

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 .

Änderungen blockieren

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.

Protokolle und Anmerkungen, die Zusammenführungen anzeigen

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!

Die Abstammung berücksichtigen oder ignorieren

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] Tipp

Die Option --ignore-ancestry unterbindet auch Verfolgung von Zusammenführungen. Das bedeutet, dass weder svn:mergeinfo berücksichtigt wird, wenn svn merge ermittelt, welche Revisionen zusammengeführt werden sollen, noch svn:mergeinfo aufgezeichnet wird, um die Zusammenführung zu beschreiben.

Zusammenführen und Verschieben

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.

Ahnungslose Clients vom Mergen abhalten

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“.

Das abschließende Wort zum Merge-Tracking

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   .