Wir gehen davon aus, dass qsmith für einige Zeit an einer abgezweigten
Version arbeiten möchte, damit er nicht die Hauptversion
destabilisiert, die er mit jrandom teilt. Der erste Schritt liegt
darin, die Verzweigung zu erzeugen. Beachten Sie, wie qsmith zunächst
eine normale Marke (nicht verzweigend) am Punkt der Verzweigung
erzeugt und erst dann die abgezweigte Version erstellt:
user@linux ~$
pwd
/home/qsmith/myproj
user@linux ~$
cvs tag Root-of-Exotic_Greetings
cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c
user@linux ~$
cvs tag -b Exotic_Greetings-branch
cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c
|
Der Grund, zuerst die Hauptversion zu markieren, liegt darin, dass es
eines Tages notwendig sein kann, die Hauptversion so abzurufen, wie
sie zum Zeitpunkt der Erstellung der Verzweigung war. Wenn das jemals
nötig ist, so hat man die Möglichkeit, eine Momentaufnahme der
Hauptversion zu referenzieren, die vor der Verzweigung entstanden
ist. Offensichtlich kann nicht die Marke der Verzweigung benutzt
werden, da dann die abgezweigte Version abgerufen werden würde und
nicht die Revisionen der Hauptversion, welche die Wurzel der
Verzweigung bildet. Die einzige Möglichkeit ist die, eine normale
Marke an der Revision anzubringen, an der die Verzweigung wurzelt.
(Mancher hält sich so strikt an diese Regel, dass ich überlegt habe,
sie als Verzweigungsregel Nummer 4 aufzuführen: Erstelle immer eine
nichtverzweigende Marke zum Zeitpunkt der Verzweigung. Wie auch
immer, auf manchen Servern wird dies nicht getan, und sie scheinen
auch ohne auszukommen, sodass es letztlich einfach eine
Geschmacksfrage bleibt.) Von nun an werde ich diese nichtverzweigende
Marke als Verzweigungspunktmarkierung (Branch Point Tag) bezeichnen.
Beachten Sie auch, dass ein Namensschema eingehalten wird: Die
Verzweigungspunktmarkierung fängt mit Root-of- an, gefolgt vom
eigentlichen Namen der Verzweigung, wobei Unterstriche statt
Bindestriche zur Worttrennung verwendet werden. Wenn die eigentliche
Verzweigung angelegt wird, endet ihre Marke mit -branch, sodass Sie
sie schon anhand ihres Namens als Marke eines Zweiges erkennen können.
(Die Verzweigungspunktmarkierung Root-of-Exotic_Greetings erhält kein
-branch, da sie ja keine Marke eines Zweiges ist.) Sie müssen sich
natürlich nicht an dieses spezielle Namensschema halten, solange Sie
nur irgendeines verwenden.
Ich bin hier natürlich besonders pedantisch. In kleineren Projekten,
bei denen jeder weiß, was von wem getan wird, und bei denen man sich
leicht von einer kurzen Phase der Verwirrung erholt, muss man sich
nicht unbedingt an diese Regeln halten. Ob Sie nun
Verzweigungspunktmarkierungen verwenden oder ein striktes Namensschema
für die Marken haben, hängt von der Komplexität des Projektes und vom
Verzweigungsschema ab. (Vergessen Sie außerdem nicht, dass Sie sich
jederzeit umentscheiden können und alte Marken für eine neues
Namensschema aktualisieren können, indem Sie die nach altem Schema
markierte Version abrufen, eine neue Marke anbringen und dann die
alte Marke löschen.)
Jetzt ist qsmith bereit, an der abgezweigten Version zu arbeiten:
user@linux ~$
cvs update -r Exotic_Greetings-branch
cvs update: Updating . cvs update: Updating a-subdir cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir
|
Er nimmt einige Änderungen an ein paar Dateien vor und führt einen
Commit aus, der die Änderungen in den Zweig hineinbringt:
user@linux ~$
emacs README.txt a-subdir/whatever.c b-subdir/random.c
...
user@linux ~$
cvs ci -m "print greeting backwards, etc"
cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.14.2.1; previous revision: 1.14 done Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.3.2.1; previous revision: 1.3 done Checking in b-subdir/random.c; /usr/local/newrepos/myproj/b-subdir/random.c,v <-- random.c new revision: 1.1.1.1.2.1; previous revision: 1.1.1.1 done
|
In der Zwischenzeit setzt jrandom ihre Arbeit an der Hauptversion
fort. Sie ändert auch zwei der drei Dateien, die qsmith geändert hat.
Aus reiner Bosheit lassen wir sie einige Änderungen machen, die im
Widerspruch zur Arbeit von qsmith stehen:
user@linux ~$
emacs README.txt whatever.c
...
user@linux ~$
cvs ci -m "some very stable changes indeed"
cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.15; previous revision: 1.14 done Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.4; previous revision: 1.3 done
|
Der Konflikt zeigt sich natürlich noch nicht, denn keiner der
Entwickler hat bisher versucht, den Zweig und die Hauptversion wieder
zusammenzuführen. Jetzt nimmt jrandom die Zusammenführung vor:
user@linux ~$
cvs update -j Exotic_Greetings-branch
cvs update: Updating . RCS file: /usr/local/newrepos/myproj/README.txt,v retrieving revision 1.14 retrieving revision 1.14.2.1 Merging differences between 1.14 and 1.14.2.1 into README.txt rcsmerge: warning: conflicts during merge cvs update: Updating a-subdir RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v retrieving revision 1.3 retrieving revision 1.3.2.1 Merging differences between 1.3 and 1.3.2.1 into whatever.c rcsmerge: warning: conflicts during merge cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v retrieving revision 1.1.1.1 retrieving revision 1.1.1.1.2.1 Merging differences between 1.1.1.1 and 1.1.1.1.2.1 into random.c
user@linux ~$
cvs update
cvs update: Updating . C README.txt cvs update: Updating a-subdir C a-subdir/whatever.c cvs update: Updating a-subdir/subsubdir cvs update: Updating b-subdir M b-subdir/random.c
|
Zwei der Dateien haben Konflikte. Keine große Sache, denn mit ihrem
üblichen Savoir-faire löst jrandom die Konflikte auf, führt den Commit
aus und markiert die Hauptversion als erfolgreich wieder vereinigt:
user@linux ~$
emacs README.txt a-subdir/whatever.c
...
user@linux ~$
cvs ci -m "merged from Exotic_Greetings-branch (conflicts resolved)"
cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.16; previous revision: 1.15 done Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.5; previous revision: 1.4 done Checking in b-subdir/random.c; /usr/local/newrepos/myproj/b-subdir/random.c,v <-- random.c new revision: 1.2; previous revision: 1.1 done
user@linux ~$
cvs tag merged-Exotic_Greetings
cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c
|
Währenddessen braucht qsmith aber nicht abzuwarten, bis die
Zusammenführung abgeschlossen ist, bevor er mit seiner
Programmierarbeit fortfährt, vorausgesetzt, er setzt eine Marke für
die Änderungen, von denen aus jrandom die Zusammenführung durchführt.
(Später wird jrandom den Namen dieser Marke benötigen, generell kommt
es bei der Verwendung von Verzweigungen darauf an, dass die
Entwickler häufig und ausführlich miteinander kommunizieren):
user@linux ~$
cvs tag Exotic_Greetings-1
cvs tag: Tagging . T README.txt T foo.gif T hello.c cvs tag: Tagging a-subdir T a-subdir/whatever.c cvs tag: Tagging a-subdir/subsubdir T a-subdir/subsubdir/fish.c cvs tag: Tagging b-subdir T b-subdir/random.c
user@linux ~$
paste$ emacs a-subdir/whatever.c
...
user@linux ~$
paste$ cvs ci -m "print a randomly capitalized greeting"
cvs commit: Examining . cvs commit: Examining a-subdir cvs commit: Examining a-subdir/subsubdir cvs commit: Examining b-subdir Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.3.2.2; previous revision: 1.3.2.1 done
|
Natürlich sollte qsmith diese Änderungen durch eine Marke
kennzeichnen, sobald er fertig ist:
user@linux ~$
paste$ cvs -q tag Exotic_Greetings-2
T README.txt T foo.gif T hello.c T a-subdir/whatever.c T a-subdir/subsubdir/fish.c T b-subdir/random.c
|
Während all das geschieht, nimmt jrandom an einer anderen Datei, die
qsmith bei seinen jüngsten Arbeiten nicht angefasst hat, Veränderungen
vor:
user@linux ~$
floss$ emacs README.txt
...
user@linux ~$
floss$ cvs ci -m "Mention new Exotic Greeting features" README.txt
Checking in README.txt; /usr/local/newrepos/myproj/README.txt,v <-- README.txt new revision: 1.17; previous revision: 1.16 done
|
Jetzt hat qsmith eine weitere Änderung an der Zweigversion
vorgenommen, und jrandom hat eine konfliktfreie Änderung an der
Hauptversion vorgenommen. Folgendes geschieht, wenn jrandom erneut
versucht, beide zusammenzuführen:
user@linux ~$
floss$ cvs -q update -j Exotic_Greetings-branch
RCS file: /usr/local/newrepos/myproj/README.txt,v retrieving revision 1.14 retrieving revision 1.14.2.1 Merging differences between 1.14 and 1.14.2.1 into README.txt rcsmerge: warning: conflicts during merge RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v retrieving revision 1.3 retrieving revision 1.3.2.2 Merging differences between 1.3 and 1.3.2.2 into whatever.c rcsmerge: warning: conflicts during merge RCS file: /usr/local/newrepos/myproj/b-subdir/random.c,v retrieving revision 1.1 retrieving revision 1.1.1.1.2.1 Merging differences between 1.1 and 1.1.1.1.2.1 into random.c
user@linux ~$
floss$ cvs -q update
C README.txt C a-subdir/whatever.c
|
Es gibt Konflikte! Haben Sie es erwartet?
Das Problem liegt in der Semantik der Zusammenführung. In Kapitel 2
habe ich gezeigt, dass, wenn Sie
user@linux ~$
floss$ cvs update -j Zweig
|
in einer Arbeitskopie ausführen, CVS die Unterschiede zwischen der
Wurzel von ZWEIG und seinem derzeitigen Endpunkt in die Arbeitskopie
einbringt. Das Problem mit diesem Verhalten, in dieser Situation,
ist, dass die meisten dieser Änderungen schon beim ersten
Zusammenführen, das jrandom durchgeführt hat, in die Hauptversion
eingeflossen sind. Als CVS versucht hat, diese erneut einzubringen
(über sie selbst), hat es natürlich den Konflikt bemerkt.
Was jrandom eigentlich tun wollte, war, die Änderungen zwischen dem
letzten Zusammenführen mit dem Zweig und seinem aktuellen Endpunkt in
ihrer Arbeitsgruppe zu vereinen. Sie können das, wie Sie sich
vielleicht aus Kapitel 2 erinnern, mit zwei -j-Optionen für update
bewerkstelligen, vorausgesetzt Sie wissen, welche Revision bei jeder
Option anzugeben ist. Glücklicherweise hat jrandom exakt am Punkt der
letzten Zusammenführung eine Marke gesetzt (Extralob für
Vorausplanung!), sodass das kein Problem ist. Lassen Sie uns zuerst
jrandom ihre Arbeitskopie in einem sauberen Zustand wiederherstellen,
von wo aus sie dann die Zusammenführung erneut versuchen kann:
user@linux ~$
rm README.txt a-subdir/whatever.c
user@linux ~$
cvs -q update
cvs update: warning: README.txt was lost U README.txt cvs update: warning: a-subdir/whatever.c was lost U a-subdir/whatever.c
|
Nun ist sie bereit, die Zusammenführung durchzuführen, diesmal mit der
von qsmith praktischerweise gesetzten Marke:
user@linux ~$
cvs -q update -j Exotic_Greetings-1 -j Exotic_Greetings-branch
RCS file: /usr/local/newrepos/myproj/a-subdir/whatever.c,v retrieving revision 1.3.2.1 retrieving revision 1.3.2.2 Merging differences between 1.3.2.1 and 1.3.2.2 into whatever.c
user@linux ~$
cvs -q update
M a-subdir/whatever.c
|
Schon viel besser. Die Änderung von qsmith wurde in whatever.c
eingearbeitet; jrandom kann nun den Commit ausführen und eine Marke
setzen:
user@linux ~$
cvs -q ci -m "merged again from Exotic_Greetings (1)"
Checking in a-subdir/whatever.c; /usr/local/newrepos/myproj/a-subdir/whatever.c,v <-- whatever.c new revision: 1.6; previous revision: 1.5 done
user@linux ~$
cvs -q tag merged-Exotic_Greetings-1
T README.txt T foo.gif T hello.c T a-subdir/whatever.c T a-subdir/subsubdir/fish.c T b-subdir/random.c
|
Selbst wenn qsmith vergessen hätte, eine Marke beim Zusammenführen
anzubringen, wäre noch nicht alles verloren gewesen. Wenn jrandom
ungefähr wüsste, wann qsmiths erste Änderungen stattgefunden haben,
könnte sie mittels Datum filtern:
user@linux ~$
cvs update -j Exotic_Greetings-branch:3pm -j Exotic_Greetings_branch
|
Obgleich nützlich als letzter Ausweg, ist das Filtern nach Datum ein
weniger geeignetes Mittel, da die Änderungen auf Grund von
persönlichen Erinnerungen anstelle von verlässlichen Vorgaben der
Entwickler ausgewählt werden. Wenn der erste Satz Änderungen von
qsmith über mehrere Commits anstelle von einem einzigen verteilt
gewesen wäre, hätte jrandom leicht ein Datum oder eine Uhrzeit wählen
können, das zwar einige der Änderungen auffängt, aber
fälschlicherweise nicht alle.
Bemerkung
Es gibt keinen Grund, warum markierbare Punkte in jrandoms Änderungen
als ein einziger Commit an das Archiv gesendet werden müssen - es hat
sich in diesen Beispielen einfach so ergeben. Im wirklichen Leben
könnte qsmith mehrere Commits zwischen den Markierungen vornehmen. Er
kann auch völlig isoliert an dem Zweig arbeiten, wenn es ihm so
gefällt. Der Sinn der Marken ist, aufeinander folgende Punkte
anzuzeigen, zu denen er die Änderungen im Zweig für mit der
Hauptversion verschmelzbar hält. Solange jrandom die Verschmelzung
immer mit zwei -j-Optionen vornimmt und darauf achtet, die
Zusammenführungsmarkierungen von qsmith in der richtigen Reihenfolge
und jeweils nur einmal zu verwenden, sollte die Hauptversion niemals
das Problem mit der mehrfach versuchten Verschmelzung erfahren.
Konflikte können immer noch auftreten, es werden aber unvermeidbare
sein, solche, bei denen sowohl in der Hauptversion als auch im Zweig
Änderungen an denselben Stellen im Quelltext vorgenommen wurden. Diese
müssen immer manuell aufgelöst werden.
|
|