Diese Dokumentation wurde zur Beschreibung der Serie 1.6.x von Subversion erstellt. Falls Sie eine unterschiedliche Version von Subversion einsetzen, sei Ihnen dringend angeraten, bei http://www.svnbook.com/ vorbeizuschauen und stattdessen die zu Ihrer Version von Subversion passende Version dieser Dokumentation heranzzuiehen.

Umgang mit Strukturkonflikten

Bis hierhin haben wir nur über Konflikte auf der Ebene von Dateiinhalten gesprochen. Wenn Sie und Ihre Mitarbeiter überlappende Änderungen innerhalb derselben Datei vornehmen, zwingt Sie Subversion dazu, diese Änderungen zusammenzuführen, bevor Sie sie übergeben können.[9]

Was passiert aber, wenn Ihre Mitarbeiter eine Datei verschieben oder löschen, an der Sie noch arbeiten? Vielleicht gab es ein Verständnisproblem oder die eine Person glaubt, die Datei soll gelöscht werden, während die andere Person noch Änderungen an der Datei übergeben will. Vielleicht haben Ihre Mitarbeiter ja auch etwas Refactoring betrieben und dabei Dateien umbenannt und Verzeichnisse verschoben. Falls Sie noch an diesen Dateien gearbeitet haben, müssten diese Änderungen auf die Dateien am der neuen Stelle angewendet werden. Derartige Konflikte äußern sich auf der Ebene der Verzeichnisstruktur statt des Dateiinhaltes und sind bekannt als Baumkonflikte.

Wie bei textuellen Konflikten verhindern Baumkonflikte eine Übergabe aus dem Konfliktzustand und geben dem Anwender die Gelegenheit, den Zustand der Arbeitskopie auf potenzielle Probleme, die aus dem Baumkonflikt entstehen könnten, zu überprüfen und vor der Übergabe aufzulösen.

Ein Beispiel für einen Baumkonflikt

Gegeben sei folgendes Softwareprojekt, an dem Sie gerade arbeiten:

$ svn list -Rv svn://svn.example.com/trunk/
      4 harry                 Feb 06 14:34 ./
      4 harry              23 Feb 06 14:34 COPYING
      4 harry              41 Feb 06 14:34 Makefile
      4 harry              33 Feb 06 14:34 README
      4 harry                 Feb 06 14:34 code/
      4 harry              51 Feb 06 14:34 code/bar.c
      4 harry             124 Feb 06 14:34 code/foo.c

Ihr Kollege Harry hat die Datei bar.c in baz.c umbenannt. Sie arbeiten immer noch an bar.c in Ihrer Arbeitskopie, doch wissen noch nicht, dass die Datei im Projektarchiv umbenannt wurde.

Die Protokollmeldung für Harrys Übergabe sah so aus:

$ svn log -r5 svn://svn.example.com/trunk
------------------------------------------------------------------------
r5 | harry | 2009-02-06 14:42:59 +0000 (Fri, 06 Feb 2009) | 2 lines
Geänderte Pfade:
   M /trunk/Makefile
   D /trunk/code/bar.c
   A /trunk/code/baz.c (from /trunk/code/bar.c:4)

bar.c nach baz.c umbenannt und Makefile entsprechend angepasst.

Die von Ihnen vorgenommenen Änderungen sehen so aus:

$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c  (revision 4)
+++ code/foo.c  (working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
        printf("I don't like being moved around!\n%s", bar());
-       return 0;
+       return 1;
 }
Index: code/bar.c
===================================================================
--- code/bar.c  (revision 4)
+++ code/bar.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-       return "Me neither!\n";
+       return "Well, I do like being moved around!\n";
 }

Ihre Änderungen bauen alle auf Revision 4 auf. Sie können nicht übergeben werden, da Harry bereits Revision 5 übergeben hat:

$ svn commit -m "Small fixes"
Sende          code/bar.c
Sende          code/foo.c
Übertrage Daten ..
svn: Übertragen schlug fehl (Details folgen):
svn: Datei nicht gefunden: Transaktion »5-5«, Pfad »/trunk/code/bar.c«

An dieser Stelle müssen Sie svn update aufrufen. Außer Ihre Arbeitskopie zu aktualisieren, so dass Sie Harrys Änderungen sehen können, markiert es auch einen Baumkonflikt, so dass Sie die Gelegenheit bekommen, die Situation abzuschätzen und entsprechend aufzulösen.

$ svn update
   C code/bar.c
A    code/baz.c
U    Makefile
Aktualisiert zu Revision 5.
Konfliktübersicht:
  Baumkonflikte: 1

In seiner Ausgabe zeigt svn update Baumkonflikte mit einem großen C in der vierten Spalte an. svn status enthüllt weitere Details zum Konflikt:

$ svn status
M       code/foo.c
A  +  C code/bar.c
      >   lokal editiert, eingehend gelöscht bei Aktualisierung
M       code/baz.c

Beachten Sie, wie bar.c automatisch in Ihrer Arbeitskopie zum erneuten Hinzufügen vorgemerkt wird, was die Sache vereinfacht, sollten sie sich entscheiden, die Datei zu behalten.

Da eine Verschiebung in Subversion als eine Kopie mit anschließender Löschung implementiert ist, und diese beiden Operationen sich bei einer Aktualisierung sich nicht einfach in Beziehung setzen lassen, kann Sie Subversion lediglich über eine hereinkommende Löschung einer lokal modifizierten Datei warnen. Diese Löschung kann Teil einer Verschiebung sein oder eine tatsächliche Löschung. Um herauszufinden, was wirklich passiert ist, empfiehlt es sich, mit Ihren Kollegen Rücksprache zu halten, oder, als letzte Möglichkeit, svn log zu befragen.

Sowohl foo.c als auch baz.c werden in der Ausgabe von svn status als lokal modifiziert angezeigt. Sie selbst haben Änderungen an foo.c vorgenommen, das sollte Sie nicht überraschen. Aber warum wird baz.c als lokal modifiziert angezeigt?

Die Antwort ist, dass, trotz der Einschränkungen bei der Implementierung der Verschiebung, Subversion klug genug war, Ihre lokalen Änderungen an bar.c nach baz.c zu übertragen:

$ svn diff code/baz.c
Index: code/baz.c
===================================================================
--- code/baz.c  (revision 5)
+++ code/baz.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-       return "Me neither!\n";
+       return "Well, I do like being moved around!\n";
 }
[Warnung] Warnung

Lokale Änderungen an der Datei bar.c, die während einer Aktualisierung in baz.c umbenannt wird, werden nur dann auf bar.c angewendet, falls Ihre Arbeitskopie von bar.c auf der Revision aufbaut, in der sie zuletzt modifiziert wurde, bevor sie im Projektarchiv verschoben wurde. Anderenfalls wird Subversion sich damit begnügen, baz.c aus dem Projektarchiv zu holen, und nicht versuchen, Ihre lokalen Änderungen dorthin zu übertragen. Das müssen Sie manuell machen.

svn info zeigt die URLs der am Konflikt beteiligten Objekte. Der linke URL zeigt die Quelle der lokalen Seite des Konfliktes, während die rechte URL die Quelle der hereinkommenden Seite des Konfliktes anzeigt. Diese URLs weisen darauf hin, wo Sie mit der Suche nach der mit Ihrer lokalen Änderung in Konflikt stehenden Änderung in der Vorgeschichte des Projektarchivs beginnen sollten.

$ svn info code/bar.c | tail -n 4 
Baumkonflikt: lokal editiert, eingehend gelöscht bei Aktualisierung
  Quelle  links: (Datei) ^/trunk/code/bar.c@4
  Quelle  rechts: (nichts) ^/trunk/code/bar.c@5

bar.c heißt nun Opfer eines Baumkonfliktes. Sie kann nicht übergeben werden, bevor der Konflikt aufgelöst wird:

$ svn commit -m "Small fixes" 
svn: Übertragen schlug fehl (Details folgen):
svn: Übertragung abgebrochen: »code/bar.c« bleibt im Konflikt

Wie kann denn dieser Konflikt nun aufgelöst werden? Sie können entweder mit Harrys Vorgehen einverstanden sein oder nicht. Falls ja, löschen Sie bar.c und markieren den Baumkonflikt als aufgelöst:

$ svn delete --force code/bar.c
D         code/bar.c
$ svn resolve --accept=working code/bar.c
Konflikt von »code/bar.c« aufgelöst
$ svn status
M       code/foo.c
M       code/baz.c
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c  (revision 5)
+++ code/foo.c  (working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
        printf("I don't like being moved around!\n%s", bar());
-       return 0;
+       return 1;
 }
Index: code/baz.c
===================================================================
--- code/baz.c  (revision 5)
+++ code/baz.c  (working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-       return "Me neither!\n";
+       return "Well, I do like being moved around!\n";
 }

Falls Sie mit dem Vorgehen nicht einverstanden sind, können Sie stattdessen baz.c löschen, nachdem Sie sichergestellt haben, das alle nach der Umbenennung vorgenommenen Änderungen entweder bewahrt worden sind, oder verworfen werden können. Vergessen Sie nicht, die Änderungen zurückzunehmen, die Harry an Makefile gemacht hat. Da bar.c bereits zum neu Hinzufügen vorgemerkt ist, bleibt nichts mehr zu tun, und der Konflikt kann als aufgelöst markiert werden:

$ svn delete --force code/baz.c
D         code/baz.c
$ svn resolve --accept=working code/bar.c
Konflikt von »code/bar.c« aufgelöst
$ svn status
M       code/foo.c
A  +    code/bar.c
D       code/baz.c
M       Makefile
$ svn diff
Index: code/foo.c
===================================================================
--- code/foo.c	(revision 5)
+++ code/foo.c	(working copy)
@@ -3,5 +3,5 @@
 int main(int argc, char *argv[])
 {
 	printf("I don't like being moved around!\n%s", bar());
-	return 0;
+	return 1;
 }
Index: code/bar.c
===================================================================
--- code/bar.c	(revision 5)
+++ code/bar.c	(working copy)
@@ -1,4 +1,4 @@
 const char *bar(void)
 {
-	return "Me neither!\n";
+	return "Well, I do like being moved around!\n";
 }
Index: code/baz.c
===================================================================
--- code/baz.c	(revision 5)
+++ code/baz.c	(working copy)
@@ -1,4 +0,0 @@
-const char *bar(void)
-{
-	return "Me neither!\n";
-}
Index: Makefile
===================================================================
--- Makefile	(revision 5)
+++ Makefile	(working copy)
@@ -1,2 +1,2 @@
 foo: 
-	$(CC) -o $@ code/foo.c code/baz.c
+	$(CC) -o $@ code/foo.c code/bar.c

In jedem Fall haben Sie nun Ihren ersten Baumkonflikt aufgelöst! Sie können Ihre Änderungen übergeben und Harry in der Kaffeepause erzählen, welche Mehrarbeit er Ihnen bereitet hat.



[9] Natürlich könnten Sie Dateien, die Konfliktmarkierungen enthalten, als konfliktfrei erklären und übergeben, wenn Sie es wirklich wollten, doch das wird in der Praxis kaum gemacht.