Inhalt
Inhaltsverzeichnis
-
CVS benutzen -- eine Einführung
- Vorbereitungen
-
Erste Schritte
- Ein Projekt auschecken (checkout)
- Zugriff auf fremde Quellen (login und checkout)
- Was habe ich bloß getan?? (update und diff)
- Änderungen verwerfen (update)
- Änderungen in das Repository übertragen (checkin)
- Eine neue Datei hinzufügen (add)
- Eine Datei entfernen (rm)
- Das ist doch alles viel zu umständlich, oder?
-
Weiterlaufen
- In Geschichtsbüchern schmökern (log)
- "Früher war alles anders!" Herausfinden, was sich wirklich verändert hat. (diff -r)
- "Weißt du noch, damals... !" Alte Versionen betrachten (up -p -r)
- "Früher war es viel schöner!" Eine erste Zeitreise (up -r)
- Eine klebrige Angelegenheit: Sticky Tags (status)
- Hände waschen! (cvs up -A)
- Wettrennen
- Stolperfallen
- Nachtrag
- Weiterführende Dokumentation
1. CVS benutzen -- eine Einführung
Dies ist das Skript zu einem Vortrag, den ich (KaiMoritz) neulich bei der LugEssen hielt.
1.1. Vorbereitungen
Die Befehle in diesem Abschnitt sollte man sich nicht merken. Man benutzt sie in der Regel so selten, daß man sie sowieso jedes mal wieder nachschlagen muß.
1.1.1. Installation
Nicht nötig! Es muß lediglich das Binary auf dem System vorhanden sein.
Ausnahme: cvspserver
1.1.2. Einen CVS-Repository anlegen (init)
Ein Repository wird mit dem folgenden Befehl erzeugt:
fREUNd:/home/kai# cvs -d /var/lib/cvs init fREUNd:/home/kai#
Oder auch mit:
kai@fREUNd:~$ cvs -d /home/kai/cvsroot init kai@fREUNd:~$
Danach ist das Repository sofort einsatzbereit. Für die einfache Benutzung ist keine weitere Konfiguration nötig.
Es gibt keine Vorschrift, wo das Repository im Dateisystem abgelegt wird. Da CVS zudem keine zentrale Konfigurationsdatei benutzt, sondern die Konfigurationseinstellungen im Repository speichert, kann man auch als normaler Benutzer auf einem beliebigen System, auf dem man über einen Benutzer-Shell-Account verfügt, sein CVS betreiben und auf diesen auch von anderen Rechnern zugreifen.
1.1.3. Ein Projekt erzeugen (import)
Ein neues Projekt wird mit dem Befehl import erzeugt. Dabei kann ein leeres Verzeichnis importiert werden, oder ein gesamter Verzeichnisbaum eines bestehenden Projektes.
Mit dem folgendem Befehl wird das Verzeichnis xpenguins-1.2 in das eben angelegten Repository /home/kai/cvsroot importiert und dort unter dem Namen xpenguins abgelegt. Mit -m wird eine Log-Meldung erzeugt (wird -m weggelassen, holt sich CVS die Log-Meldung, indem es einen Editor öffnet). foo ist ein vendor-tag (dessen Nutzen mir schleierhaft ist). frisch_importiert ist ein release-tag, über das man später auf diese Version der Quellen zugreifen kann.
kai@fREUNd:~/xpenguins-1.2$ cvs -d /home/kai/cvsroot/ import -m "xpenguins-Quellcode importiert" xpenguins foo frisch_importiert N xpenguins/toon.c N xpenguins/toon.h N xpenguins/xpenguins.c N xpenguins/AUTHORS N xpenguins/vroot.h N xpenguins/COPYING N xpenguins/INSTALL N xpenguins/Makefile N xpenguins/README N xpenguins/xpenguins.1 N xpenguins/ChangeLog I xpenguins/xpenguins.o I xpenguins/toon.o N xpenguins/xpenguins N xpenguins/penguins/bomber.xpm N xpenguins/penguins/climber.xpm N xpenguins/penguins/def.h N xpenguins/penguins/explosion.xpm N xpenguins/penguins/faller.xpm N xpenguins/penguins/floater.xpm N xpenguins/penguins/tumbler.xpm N xpenguins/penguins/walker.xpm No conflicts created by this import kai@fREUNd:~/xpenguins-1.2$
Wie man sieht ist CVS sogar schlau genug *.o -Dateien nicht mitzuimportieren.
Wichtig: Durch den import -Befehl wird an dem Verzeichnis nichts geändert!
1.2. Erste Schritte
1.2.1. Ein Projekt auschecken (checkout)
Bevor an einem CVS-Projekt gearbeitet werden kann, muß es ausgecheckt werden. Eine Bearbeitung direkt im Repository ist nicht möglich (bzw. sinnvoll).
Ein Projekt wird mit dem Befehl checkout oder kurz co ausgecheckt. Dabei muß mit dem Schalter -d angegeben werden, welches CVS-Repository benutzt werden soll.
kai@fREUNd:~$ cvs -d /home/kai/cvsroot/ co xpenguins cvs checkout: Updating xpenguins U xpenguins/AUTHORS U xpenguins/COPYING U xpenguins/ChangeLog U xpenguins/INSTALL U xpenguins/Makefile U xpenguins/README U xpenguins/toon.c U xpenguins/toon.h U xpenguins/vroot.h U xpenguins/xpenguins U xpenguins/xpenguins.1 U xpenguins/xpenguins.c cvs checkout: Updating xpenguins/penguins U xpenguins/penguins/bomber.xpm U xpenguins/penguins/climber.xpm U xpenguins/penguins/def.h U xpenguins/penguins/explosion.xpm U xpenguins/penguins/faller.xpm U xpenguins/penguins/floater.xpm U xpenguins/penguins/tumbler.xpm U xpenguins/penguins/walker.xpm
Anstelle von -d /home/kai/cvsroot kann auch die Umgebungsvariable CVSROOT gesetzt werden. Dies ist jedoch nicht unbedingt nötig, da CVS in dem ausgecheckten Verzeichnisbaum speichert, welches Repository genutzt wird. D.h. wenn man sich in einem ausgecheckten Verzeichnis befindet ist die Angabe von -d /home/kai/cvsroot sowieso nicht mehr nötig.
Zu beachten: CVS beachtet Dateirechte, Benutzer und Gruppen nicht!
Die Dateien in einem ausgecheckten CVS-Projekt gehören immer dem Benutzer, der das checkout -Kommando durchgeführt hat.
- Die Dateirechte in dem ausgecheckten Projekt stehen in keinem Zusammenhang mit den Dateirechten in dem Verzeichnis, das importiert wurde (Ausnahme: in dem importierten Verzeichnis ausführbare Dateien werden auch in der später ausgecheckten Kopie ausführbar sein.)
1.2.2. Zugriff auf fremde Quellen (login und checkout)
Wenn man anstatt auf ein lokales auf ein entferntes Repository zugreifen will, ändert sich eigentlich fast nichts. Lediglich beim checkout der Arbeitskopie müssen ein paar andere Schalter betätigt werden. Danach speichert CVS die Zugriffsmethode in der Arbeitskopie. D.h. wenn man sich in dem Dateibaum der Arbeitskopie befindet, muß man den Schalter -d nicht mehr angeben.
1.2.2.1. Zugriff per SSH
Um per ssh auf ein entferntes Repository zuzugreifen, muß zunächst in der Umgebungsvariable CVS_RSH gespeichert werden, welches Remote-Shell Programm benutzt werden soll.
kai@fREUNd:~$ export CVS_RSH=ssh kai@fREUNd:~$
Danach muß beim checkout wieder der Schalter -d betätigt werden.
kai@fREUNd:~$ cvs -d :ext:kai@bRUDEr:/var/lib/cvs co cvs cvs server: Updating cvs U cvs/background.png U cvs/ersteschritte.html U cvs/fortsetzung.html U cvs/index.html U cvs/muster.html U cvs/quellen.html U cvs/stolperfallen.html U cvs/timemachine-klein.png U cvs/timemachine.png U cvs/vorbereitungen.html U cvs/vortrag.css U cvs/weiterlaufen.html U cvs/wettrennen.html kai@fREUNd:~$
Die allgemeine Syntax von -d ist: :ZUGRIFFSMETHODE:BENUTZER@RECHNER:PFAD_ZUM_CVSVERZEICHNIS . ext steht hier dafür, daß ein externes Programm für die Verbindung benutzt werden soll. Welches ist in CVS_RSH gespeichert. Weiter sieht man: ich greife als Benutzer kai auf den Rechner bRUDEr auf das Repository /var/lib/cvs zu.
Um diese Zugriffsmethode zu aktivieren, sind keine Root-Rechte notwendig. Die einzige Voraussetzung ist, dass sich das CVS-Binary im Pfad des Remote-Shell-Accounts befindet. D.h. man kann auf einem beliebigen Rechner, auf dem man einen Account besitzt, in seinem Home-Verzeichnis ein CVS-Repository anlegen und auf dieses Repository von anderen Rechnern aus zugreifen.
Wie die Authentifizierung abläuft, bestimmt dabei das Programm, das in CVS_RSH angegeben wurde. (In meinem Fall war keine Passworteingabe nötig, da ich für diesen Rechner einen SSH-Schlüssel ohne Mantra benutze... bequem, aber eine gewisse Sicherheitslücke.)
1.2.2.2. Zugriff per pserver
Bei dem Zugriff über einen pserver, der natürlich auf dem Remote-Rechner entsprechend eingerichtet worden sein muß, ist zunächst eine Authentifizierung per login notwendig. Danach kann die Arbeitskopie ausgecheckt werden. CVS legt die Zugriffsmethode (und in diesem Fall auch das Passwort) wieder in der Arbeitskopie ab, so daß nach dem checkout die Zugriffsmethode wiederum nicht mehr angegeben werden muß. Als ZUGRIFFSMETHODE muß dieses mal pserver gewählt werden.
kai@fREUNd:~$ cvs -d :pserver:anonymous@anoncvs.kde.org:/home/kde login Logging in to :pserver:anonymous@anoncvs.kde.org:2401/home/kde CVS password: kai@fREUNd:~$ cvs -d :pserver:anonymous@anoncvs.kde.org:/home/kde co kdepim/kpilot cvs server: Updating kdepim/kpilot U kdepim/kpilot/.cvsignore U kdepim/kpilot/AUTHORS U kdepim/kpilot/COPYING U kdepim/kpilot/ChangeLog U kdepim/kpilot/INSTALL [...] U kdepim/kpilot/lib/syncAction.cc U kdepim/kpilot/lib/syncAction.h U kdepim/kpilot/lib/uiDialog.cc U kdepim/kpilot/lib/uiDialog.h cvs server: Updating kdepim/kpilot/po cvs server: Updating kdepim/kpilot/po/en cvs server: Updating kdepim/kpilot/po/nl kai@fREUNd:~$
Das Passwort ist hier natürlich von dem pserver abhängig, den man benutzt. Bei anonymem Zugriff ist es aber in der Regel leer ( RETURN ). Im zweiten Schritt muß hier noch mal -d ... mit angegeben werden, da zu diesem Zeitpunkt noch nichts ausgecheckt wurde, also noch keine Arbeitskopie existiert, in der CVS die Zugriffsmethode abgespeichert haben könnte.
1.2.3. Was habe ich bloß getan?? (update und diff)
Nachdem man eine Weile an dem Code herumgefummelt hat, fragt man sich meistens, was man überhaupt alles gemacht hat. Dies erfährt man von CVS mit dem Kommando update (wie der Name ahnen läßt, macht dieses Komando noch mehr).
Das Komando arbeitet - wie alle CVS-Komandos - auf allen Dateien im aktuellen Verzeichnis und steigt auch in untergeordnete Verzeichnisse ab.
kai@fREUNd:~$ cd xpenguins/ kai@fREUNd:~/xpenguins$ echo "Ich war hier..." >> README kai@fREUNd:~/xpenguins$ echo "/* Sinnloser Text */" >> xpenguins.c kai@fREUNd:~/xpenguins$ echo "/* Sinnloser Text */" >> penguins/def.h kai@fREUNd:~/xpenguins$ cvs up cvs update: Updating . M README M xpenguins.c cvs update: Updating penguins M penguins/def.h kai@fREUNd:~/xpenguins$
Wie man sieht ist der Schalter -p nicht mehr nötig, da wir uns nun in einem ausgecheckten Verzeichnis befinden.
Genauere Informationen kann man sich mit dem Komando diff anzeigen lassen. Auch dieses Komando arbeitet ohne weitere Angaben auf allen Dateien im aktuellen Verzeichnis und den Verzeichnissen, die diesem untergeordnet sind. Wenn man nur über eine Datei (oder mehrere bestimmte Dateien) genau wissen will, was man verändert hat, gibt man diese einfach an. Hier ein Aufruf für ein diff der Änderungen an der Datei README :
kai@fREUNd:~/xpenguins$ cvs diff README Index: README =================================================================== RCS file: /home/kai/cvsroot/xpenguins/README,v retrieving revision 1.1.1.1 diff -r1.1.1.1 README 62a63 > Ich war hier... kai@fREUNd:~/xpenguins$
Das CVS- diff versteht die üblichen diff-Schalter. Hier ein Aufruf mit -c ohne Angabe eines bestimmten Files. Es werden also die diffs gegen alle veränderten Dateien angezeigt:
kai@fREUNd:~/xpenguins$ cvs diff -c cvs diff: Diffing . Index: README =================================================================== RCS file: /home/kai/cvsroot/xpenguins/README,v retrieving revision 1.1.1.1 diff -c -c -r1.1.1.1 README *** README 9 May 2003 17:34:47 -0000 1.1.1.1 --- README 9 May 2003 21:20:31 -0000 *************** *** 60,62 **** --- 60,63 ---- Microsoft Windows and called it `WinPenguins' - visit: http://neomueller.org/~isamu/winpenguins/ + Ich war hier... Index: xpenguins.c =================================================================== RCS file: /home/kai/cvsroot/xpenguins/xpenguins.c,v retrieving revision 1.1.1.1 diff -c -c -r1.1.1.1 xpenguins.c *** xpenguins.c 9 May 2003 17:34:47 -0000 1.1.1.1 --- xpenguins.c 9 May 2003 21:20:40 -0000 *************** *** 423,425 **** --- 423,426 ---- exit(0); } + /* Sinnloser Text */ cvs diff: Diffing penguins Index: penguins/def.h =================================================================== RCS file: /home/kai/cvsroot/xpenguins/penguins/def.h,v retrieving revision 1.1.1.1 diff -c -c -r1.1.1.1 def.h *** penguins/def.h 9 May 2003 17:34:47 -0000 1.1.1.1 --- penguins/def.h 9 May 2003 21:20:44 -0000 *************** *** 50,52 **** --- 50,53 ---- { bomber_xpm, 16, 1, 32, 32, TOON_NOCYCLE }, { explosion_xpm, 1, 1, 64, 64, TOON_NOCYCLE } }; + /* Sinnloser Text */ kai@fREUNd:~/xpenguins$
1.2.4. Änderungen verwerfen (update)
Stellt man nun fest, dass die Änderungen an der Datei README eigentlich doch überflüssig sind, so kann man diese einfach verwerfen, indem man die Datei löscht und sich nachher per cvs up die alte Version wiederholt:
kai@fREUNd:~/xpenguins$ rm README kai@fREUNd:~/xpenguins$ cvs up cvs update: Updating . cvs update: warning: README was lost U README M xpenguins.c cvs update: Updating penguins M penguins/def.h kai@fREUNd:~/xpenguins$
Das U vor der Datei README zeigt an, daß diese neu aus dem Repository geholt wurde. Das M vor xpenguins/def.h zeigt an, daß hier weiterhin Änderungen in unserer Arbeitskopie des Projektes vorhanden sind, die noch nicht in das Repository übertragen wurden.
1.2.5. Änderungen in das Repository übertragen (checkin)
Nachdem wir uns nun versichert haben, daß alle vorgenommenen Änderungen sinnvoll sind, sollen diese in das Repository übertragen werden. Dies leistet das Komando commit oder kurz ci . Auch dieses Kommando kann ohne weitere Angaben aufgerufen werden, um alle Änderungen in das Repository zu übertragen, oder mit einer Liste von Dateien, wenn nur bestimmte Änderungen übertragen werden sollen.
kai@fREUNd:~/xpenguins$ cvs ci -m "Mehr oder weniger sinnige Änderungen" cvs commit: Examining . cvs commit: Examining penguins Checking in xpenguins.c; /home/kai/cvsroot/xpenguins/xpenguins.c,v <-- xpenguins.c new revision: 1.2; previous revision: 1.1 done Checking in penguins/def.h; /home/kai/cvsroot/xpenguins/penguins/def.h,v <-- def.h new revision: 1.2; previous revision: 1.1 done kai@fREUNd:~/xpenguins$
CVS teilt mit, daß nun in dem Repository neben der vorhergehenden (initialen) Version 1.1 für die beiden Dateien eine neue Version 1.2 erzeugt wurde.
Ohne Angabe von -m "Mehr oder weniger sinnige Änderungen" würde der Standard-Editor geöffnet, um eine Checkin-Lognachricht zu erfragen. Dies sieht dann z.B. so aus:
CVS: ------------------------------------------------------------------ CVS: Enter Log. Lines beginning with `CVS:' are removed automatically CVS: CVS: Committing in . CVS: CVS: Modified Files: CVS: README toon.h CVS: Added Files: CVS: LIESMICH CVS: ------------------------------------------------------------------ ~ ~ ~ ~ 1,0-1 All
CVS listet in einem auskommentierten Bereich die Dateien auf, die durch den Checkin geändert, hinzugefügt oder gelöscht werden. Es lohnt sich, nicht einfach alle Dateien einzuchecken, sondern immer die Dateien gemeinsam, deren Änderungen inhaltlich zusammenhängen. Dann kann man bequem die Kommentarzeichen ( CVS: ) vor den Zeilen entfernen, die die Änderungen auflisten, und braucht nur noch eine Textnachricht zu ergänzen.
Achtung: Gute Checkin-Logs zu schreiben macht zwar Arbeit, aber auch unheimlich viel Sinn. Sie können später bei der gewissenhaften Vorbereitung einer Zeitreise von unschätzbarem Wert sein!
1.2.6. Eine neue Datei hinzufügen (add)
Wie fügt man nun eine neue Datei zu einem Projekt hinzu? Erzeugen wir zunächst die Datei und fragen CVS mit dem Kommando update , was es von dieser Datei weiß:
kai@fREUNd:~/xpenguins$ echo "Dies ist der Inhalt" > neu.txt kai@fREUNd:~/xpenguins$ cvs up cvs update: Updating . ? neu.txt cvs update: Updating penguins kai@fREUNd:~/xpenguins$
Wie man sieht, weiß CVS konsequenterweise nichts mit unserer neuen Datei anzufangen. Wir müssen CVS also mitteilen, daß wir eine neue Datei erzeugt haben. Dies geschieht mit dem Kommando add :
kai@fREUNd:~/xpenguins$ cvs add neu.txt cvs add: scheduling file `neu.txt' for addition cvs add: use 'cvs commit' to add this file permanently kai@fREUNd:~/xpenguins$
CVS weist uns darauf hin, daß wir das Kommando commit benutzen müssen, um unsere neue Datei wirklich in das Repository aufzunehmen. Was hat das zu bedeuten?
Das add -Kommando arbeitet nur auf der Arbeitskopie des Projektes. D.h. es vermerkt in einer der Dateien, die in dem Verzeichnis CVS zu finden sind, daß unsere neue Datei beim nächsten Aufruf von commit in das Repository übertragen werden soll. An dem Repository verändert unser Aufruf von cvs add also nichts! Wenn wir die neue Datei löschen, bevor wir cvs ci aufrufen, ist sie unwiederbringlich verloren!
kai@fREUNd:~/xpenguins$ cvs ci -m "Neue Datei hinzugefügt" cvs commit: Examining . cvs commit: Examining penguins RCS file: /home/kai/cvsroot/xpenguins/neu.txt,v done Checking in neu.txt; /home/kai/cvsroot/xpenguins/neu.txt,v <-- neu.txt initial revision: 1.1 done kai@fREUNd:~/xpenguins$
Jetzt erst wurde die Datei in das Repository übertragen und erhält die initiale Version 1.1.
1.2.7. Eine Datei entfernen (rm)
Oben haben wir bereits gesehen, daß eine gelöschte Datei durch den nächsten Aufruf von cvs up wiederhergestellt wird. Auch um Dateien aus einem Projekt zu löschen sind also mehrere Schritte nötig:
- Datei löschen
- CVS mitteilen, daß die Datei gelöscht wurde
- Änderungen an das Repository übertragen
Um die Datei neu.txt wieder zu löschen müssen also folgende Schritte durchgeführt werden:
kai@fREUNd:~/xpenguins$ rm neu.txt kai@fREUNd:~/xpenguins$ cvs rm neu.txt cvs remove: scheduling `neu.txt' for removal cvs remove: use 'cvs commit' to remove this file permanently kai@fREUNd:~/xpenguins$ cvs ci -m "Datei neu.txt wieder gelöscht." cvs commit: Examining . cvs commit: Examining penguins Removing neu.txt; /home/kai/cvsroot/xpenguins/neu.txt,v <-- neu.txt new revision: delete; previous revision: 1.1 done kai@fREUNd:~/xpenguins$
1.2.8. Das ist doch alles viel zu umständlich, oder?
NEIN!
Auf den ersten Blick mag z.B. das Löschen oder Hinzufügen von Dateien zu einem CVS-Projekt etwas umständlich erscheinen. Ein paar Worte zum Konzept von CVS sollen daher klarstellen, daß es sich hier nicht um einen Design-Fehler handelt, sondern um eine konsequente Implementation der gewünschten Funktion.
CVS trennt scharf zwischen dem Repository und der Arbeitskopie, die sich ein Benutzer aus diesem Repository besorgt hat. Für den Benutzer ist immer nur seine Arbeitskopie zugänglich. Änderungen die er hier vornimmt, bleiben lokal, bis er sie explizit per checkin an das Repository überträgt. Dies hat mehrere entscheidende Vorteile:
- Ein Benutzer kann sich eine Arbeitskopie von einem Server besorgen und kann dann ohne Kontakt zu Server an dieser arbeiten. Ein Kontakt zum Server ist erst dann wieder nötig, wenn er seine Ergebnisse in das Repository übertragen will.
- Der Benutzer hat absolute Kontrolle darüber, welche Änderungen er letztendlich in das Repository überträgt. Sprich: er kann in seiner Arbeitskopie herumeditieren, wie er will, ohne Angst haben zu müssen, unsinnige Änderungen in das Repository zu übertragen.
- Als Folge aus dem letzten Punkt, kann sich der Benutzer jederzeit eine klare Übersicht darüber verschaffen, welche Änderungen er in seiner Arbeitskopie gegenüber dem aktuellen Stand des Repository (oder natürlich jedem beliebigen Stand des Repositorys) vorgenommen hat.
Um diese Vorteile zu erreichen kann CVS natürlich nicht einfach irgendwelche Dateien im Repository löschen oder erzeugen, wenn der Benutzer dies in seiner Arbeitskopie tut. CVS kann ja nicht unterscheiden, ob diese Änderungen aus der Sicht des Benutzers sinnvoll und dauerhaft sind, oder bloß experimentellen Charakter haben.
1.3. Weiterlaufen
1.3.1. In Geschichtsbüchern schmökern (log)
Wie gezeigt wurde (vgl. Was habe ich bloß getan??) kann man mit cvs diff die Änderungen seit dem letzten commit anzeigen. Doch es sind nicht immer nur die Änderungen interessant, die man gerade gemacht hat. Eventuell möchte man mal alle Änderungen angezeigt bekommen, die man in mehreren Schritten gemacht hat, seit man sich z.B. zu einer grundlegenden Änderung an einem Projekt entschlossen hat.
Zu diesem Zweck muß man zunächst herausfinden, auf welchen Punkt in der Vergangenheit man sich beziehen möchte. Man kann seine Zeitmaschine ja nicht einfach so anschmeißen, wer weiß, wo man dann landen würde! Hier hilft das CVS-Kommando log . Es zeigt die Log-Nachrichten an, die beim Checkin der Änderungen angegeben wurden, zusammen mit dem Datum des Checkins und den Namen des Benutzers, der die Änderungen übertragen hat.
kai@fREUNd:~/xpenguins$ cvs log README RCS file: /home/kai/cvsroot/xpenguins/README,v Working file: README head: 1.4 branch: locks: strict access list: symbolic names: frisch_importiert: 1.1.1.1 foo: 1.1.1 keyword substitution: kv total revisions: 5; selected revisions: 5 description: ---------------------------- revision 1.4 date: 2003/05/12 19:52:38; author: kai; state: Exp; lines: +0 -2 tach-Zeile wieder entfernt... Modified Files: README ---------------------------- revision 1.3 date: 2003/05/12 19:52:09; author: kai; state: Exp; lines: +0 -6 Ich will keinen Hinweis auf Software für M$ Modified Files: README ---------------------------- revision 1.2 date: 2003/05/12 19:36:58; author: kai; state: Exp; lines: +1 -11 Wilde Entwicklungsphase erfolgreich abgeschlossen! Modified Files: README toon.h Added Files: LIESMICH ---------------------------- revision 1.1 date: 2003/05/09 17:34:47; author: kai; state: Exp; branches: 1.1.1; Initial revision ---------------------------- revision 1.1.1.1 date: 2003/05/09 17:34:47; author: kai; state: Exp; lines: +0 -0 xpenguins-Quellcode importiert =================================================================== kai@fREUNd:~/xpenguins$
1.3.2. "Früher war alles anders!" Herausfinden, was sich wirklich verändert hat. (diff -r)
Aus dem Log für die Datei README mag nun das Interesse erwachsen, herauszufinden, was man an der Datei seit dem Ende der "wilden Entwicklungsphase" so alles geändert hat. Dies läßt sich mit folgendem diff -Aufruf herausfinden:
kai@fREUNd:~/xpenguins$ cvs diff -c -r 1.2 README Index: README =================================================================== RCS file: /home/kai/cvsroot/xpenguins/README,v retrieving revision 1.2 retrieving revision 1.4 diff -c -r1.2 -r1.4 *** README 12 May 2003 19:36:58 -0000 1.2 --- README 12 May 2003 19:52:38 -0000 1.4 *************** *** 42,52 **** The xpenguins homepage is located at: http://www.met.rdg.ac.uk/~swrhgnrj/xpenguins/ - - SEE ALSO - - Michael Vines <isamu@neomueller.org> has rewritten the program for - Microsoft Windows and called it `WinPenguins' - visit: - http://neomueller.org/~isamu/winpenguins/ - - tach --- 42,44 ---- kai@fREUNd:~/xpenguins$
Der Schalter -r gibt an, dass ein Diff gegen die Version 1.2 der Datei hergestellt werden soll. Zu beachten ist dabei, daß ein Diff der Datei, wie sie sich derzeit im Arbeitsverzeichnis befindet, gegen die Version 1.2 gemacht wird. In dem Beispiel war die Datei auf dem aktuellen Stand. Deswegen wurde direkt ein diff der beiden Versionen 1.2 und 1.4 durchgeführt. Hätte man seit dem letzten Checkin weitere Änderungen an der Datei vorgenommen, so wäre ein diff gegen die veränderte Version im Arbeitsverzeichnis gemacht worden:
kai@fREUNd:~/xpenguins$ echo Neue Zeile >> README kai@fREUNd:~/xpenguins$ cvs diff -c -r1.2 README Index: README =================================================================== RCS file: /home/kai/cvsroot/xpenguins/README,v retrieving revision 1.2 diff -c -r1.2 README *** README 12 May 2003 19:36:58 -0000 1.2 --- README 17 May 2003 11:20:58 -0000 *************** *** 42,52 **** The xpenguins homepage is located at: http://www.met.rdg.ac.uk/~swrhgnrj/xpenguins/ ! ! SEE ALSO ! ! Michael Vines <isamu@neomueller.org> has rewritten the program for ! Microsoft Windows and called it `WinPenguins' - visit: ! http://neomueller.org/~isamu/winpenguins/ ! ! tach --- 42,45 ---- The xpenguins homepage is located at: http://www.met.rdg.ac.uk/~swrhgnrj/xpenguins/ ! Neue Zeile kai@fREUNd:~/xpenguins$
Zu Begin weist CVS explizit darauf hin, welche Versionen gedifft werden.
diff -c -r1.2 README *** README 12 May 2003 19:36:58 -0000 1.2 --- README 17 May 2003 11:20:58 -0000
Hier sieht man daran, daß in der letzten Zeile keine Versions-Nummer genannt wird, daß die Datei-Version 1.2 gegen die Datei-Version im Arbeitsverzeichnis gedifft wird, die noch nicht ins Repository übertragen wurde.
Möchte man explizit zwei bestimmte Versionen der Datei überprüfen, die bereits im Repository gespeichert sind, so kann man dies über zweimaliges verwenden des Schalters -r erreichen. Z.B. kann man sich mit folgendem Aufruf davon überzeugen, daß der Log-Eintrag für die Version 1.3 die eingecheckten Veränderungen ausreichend umschreibt:
kai@fREUNd:~/xpenguins$ cvs diff -c -r 1.2 -r1.3 README Index: README =================================================================== RCS file: /home/kai/cvsroot/xpenguins/README,v retrieving revision 1.2 retrieving revision 1.3 diff -c -r1.2 -r1.3 *** README 12 May 2003 19:36:58 -0000 1.2 --- README 12 May 2003 19:52:09 -0000 1.3 *************** *** 43,52 **** http://www.met.rdg.ac.uk/~swrhgnrj/xpenguins/ - SEE ALSO - - Michael Vines <isamu@neomueller.org> has rewritten the program for - Microsoft Windows and called it `WinPenguins' - visit: - http://neomueller.org/~isamu/winpenguins/ - tach --- 43,46 ---- kai@fREUNd:~/xpenguins$
1.3.3. "Weißt du noch, damals... !" Alte Versionen betrachten (up -p -r)
Manchmal ist es vielleicht etwas verwirrend, nur die Unterschiede zwischen zwei Dateiversionen zu sehen und man möchte viel lieber einfach eine alte Version der Datei betrachten. Dies erreicht man mit folgendem Aufruf:
kai@fREUNd:~/xpenguins$ cvs up -p -r 1.3 README |less
Der Schalter -p erzwingt dabei, daß die Datei auf STDOUT ausgegeben wird. Der Befehl cvs up kombiniert mit dem Schalter -r versetzt nämlich eigentlich die Arbeitskopie in einen vergangenen Zustand zurück. Dazu nun mehr.
1.3.4. "Früher war es viel schöner!" Eine erste Zeitreise (up -r)
Wie gesagt ersetzt cvs up -r VERSIONSNR eine Datei in der Arbeitskopie mit der geforderten Version. Wenn man wirklich die alte Version der Datei haben will, ist darauf zu achten, daß die Datei in der Arbeitskopie nicht verändert wurde, denn sonst führt CVS die aktuelle und die angeforderte Version zu einer neuen Datei zusammen (was unter bestimmten Umständen natürlich durchaus gewünscht sein kann)!
kai@fREUNd:~/xpenguins$ cvs up -r1.1 penguins/def.h U penguins/def.h kai@fREUNd:~/xpenguins$
Die Anforderung einer alten Datei-Version per cvs up -r ist aber nicht unbedingt das, was man sich als CVS-Neuling darunter vorstellt. Diese alte Version kann nämlich (frei nach dem Motto, daß man als Zeitreisender nichts an der Vergangenheit verändern sollte) nicht verändert werden!
kai@fREUNd:~/xpenguins$ echo "Änderung der Vergangenheit" >> penguins/def.h kai@fREUNd:~/xpenguins$ cvs ci penguins/def.h cvs commit: sticky tag `1.1' for file `penguins/def.h' is not a branch cvs [commit aborted]: correct above errors first! kai@fREUNd:~/xpenguins$
Die obige Fehlermeldung besagt, daß man, wenn man wirklich eine alte Version der Datei verändern will, zunächst einen Branch (im Fachjargon des Zeitreisenden: ein Parallel-Universum) erzeugen muß.
Oft ist das aber gar nicht, was man als CVS-Neuling wirklich will. Eigentlich will man meistens nur in der Gegenwart mit einer alten Version der Datei weiterarbeiten, weil man festgestellt hat, daß die Änderungen, die man vorgenommen hatte, Blödsinn sind. Kurz: man will einfach ein paar Änderungen rückgängig machen. Dies erreicht man mit folgendem Befehl:
kai@fREUNd:~/xpenguins$ cvs up -p -r1.1 README > README =================================================================== Checking out README RCS: /home/kai/cvsroot/xpenguins/README,v VERS: 1.1 *************** kai@fREUNd:~/xpenguins$
Das Resultat dieses Befehls ist, daß die Datei README den selben Inhalt hat, wie die Version 1.1 im Repository. Der Unterschied zu dem vorherigen Befehl ist, dass CVS nicht weiß, woher diese Änderungen an der Datei kommen. Für CVS könnten sie ebensogut von dem Benutzer per Hand eingegeben worden sein.
Aber woher weiß CVS, daß die Änderungen an der Datei penguins/def.h nach dem Aufruf ohne -p nicht vom Benutzer stammen?
1.3.5. Eine klebrige Angelegenheit: Sticky Tags (status)
Die Antwort lautet: Sticky Tags . CVS speichert für jede Datei der Arbeitskopie ein paar wesentliche Informationen (in der Datei ./CVS/Entries ). Diese können per cvs status oder kurz cvs stat abgefragt werden.
kai@fREUNd:~/xpenguins$ cvs stat penguins/def.h README =================================================================== File: def.h Status: Locally Modified Working revision: 1.1 Sat May 17 12:51:27 2003 Repository revision: 1.1 /home/kai/cvsroot/xpenguins/penguins/def.h,v Sticky Tag: 1.1 Sticky Date: (none) Sticky Options: (none) =================================================================== File: README Status: Locally Modified Working revision: 1.4 Sat May 17 14:16:20 2003 Repository revision: 1.4 /home/kai/cvsroot/xpenguins/README,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) kai@fREUNd:~/xpenguins$
Man sieht hier, daß CVS sich für die Datei penguins/def.h mit Hilfe des Sticky Tag gemerkt hat, daß diese in der Version 1.1 vorliegen soll. Dies ist nötig, da CVS sonst beim nächsten Aufruf von cvs up feststellen würde, daß die Version 1.1 , in der die Datei vorliegt, veraltet ist, und dann die neuste Version aus dem Repository holen würde.
Im Fall der Datei README , die wir mit cvs up -p geholt haben, ist dies nicht nötig, da CVS davon ausgeht, daß wir die neuste Version in unserem Arbeitsverzeichnis haben.
Aber wie wird man ein solches Sticky Tag wieder los?
1.3.6. Hände waschen! (cvs up -A)
Ein Sticky Tag kann mit dem Aufruf cvs up -A gelöscht werden (Vorsicht: der Aufruf arbeitet ohne Dateiangabe wie bei CVS üblich rekursiv das aktuelle Arbeitsverzeichnis und alle untergeordneten Verzeichnisse mit ab!). Dabei ist aber darauf zu achten, daß CVS nicht nur das Sticky Tag löscht, sondern die Datei gleichzeitig wieder auf die aktuellste Version bringt. Eventuelle lokale Änderungen werden dabei mit in die neue Version übernommen! Dies kann zu unerwünschten Nebeneffekten führen. Man sollte dem Sticky Tag also mit dem Schalter -p aus dem Weg gehen, wenn man es nicht explizit haben will!
kai@fREUNd:~/xpenguins$ cvs up -A penguins/def.h RCS file: /home/kai/cvsroot/xpenguins/penguins/def.h,v retrieving revision 1.1 retrieving revision 1.2 Merging differences between 1.1 and 1.2 into def.h rcsmerge: warning: conflicts during merge cvs update: conflicts found in penguins/def.h C penguins/def.h kai@fREUNd:~/xpenguins$
In unserem Fall führt das Löschen des Sticky Tag zu einem Konflikt zwischen der Änderung, die wir an der alten Version der Datei vornehmen wollten und der Änderung an dieser alten Version, die wir bereits in das Repository übertragen hatten.
kai@fREUNd:~/xpenguins$ cvs stat penguins/def.h =================================================================== File: def.h Status: File had conflicts on merge Working revision: 1.2 Result of merge Repository revision: 1.2 /home/kai/cvsroot/xpenguins/penguins/def.h,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) kai@fREUNd:~/xpenguins$ tail penguins/def.h { floater_xpm, 8, 1, 30, 30, TOON_DEFAULTS }, { climber_xpm, 8, 2, 30, 30, TOON_DEFAULTS }, { bomber_xpm, 16, 1, 32, 32, TOON_NOCYCLE }, { explosion_xpm, 1, 1, 64, 64, TOON_NOCYCLE } }; <<<<<<< def.h Änderung der Vergangenheit ======= /* Sinnloser Text */ >>>>>>> 1.2 kai@fREUNd:~/xpenguins$
Dies leitet zum nächsten Thema über: Konflikte.
1.4. Wettrennen
1.4.1. CVS: eine wundervolle (Zeit-)Maschine, aber keine Wunder-Maschine
Das Haupteinsatzgebiet von CVS ist die Verwaltung von Programmierprojekten, an denen mehrere Entwickler gemeinsam arbeiten. Auf dem Status von CVS als Quasi-Standard in diesem Bereich basiert ein weit verbreiteter Irrglaube. Dieser besagt, daß man nur CVS aufsetzen muß und sich danach nie mehr Sorgen darum machen muß, wer gerade was bearbeitet, weil es durch den Einsatz von CVS nicht mehr zu Konflikten durch gleichzeitige Bearbeitung einer Datei von mehreren Entwicklern kommen könne. Diese Vorstellung ist bestenfalls eine Halbwahrheit.
Der wichtigste Merksatz beim Umgang mit CVS ist, daß CVS nur helfen kann, Konflikte zu vermeiden bzw. zu beseitigen. CVS kann nicht verhindern, daß bei der gemeinsamen Arbeit mehrerer Entwickler an einem Quellbaum Konflikte entstehen. Dies kann nur durch hinreichende Absprache der Entwickler erreicht werden.
(CVS stellt allerdings Hilfsmittel zur Automatisierung dieser Absprache zur Verfügung: watch , use und edit . Dieses Thema wird hier aber nicht mehr behandelt...) CVS ist zwar eine wundersame Zeitmaschine, aber eben keine Wundermaschine! Damit ist gemeint:
CVS weiß nichts über den Sinn der Dateien, die es behandelt. Es kennt nur die Unterschiede zwischen den verschiedenen Versionen der Dateien.
Was macht CVS also, wenn es konkurrierende Änderungen an einer Datei feststellt? Es versucht einfach, die unterschiedlichen Änderungen zu einer neuen Version der Datei zusammenzuführen.
Wenn es sich um Änderungen an unterschiedlichen Teilen der Datei handelt, werden diese in einer neuen Version der Datei zusammengeführt. Der Benutzer wird darauf durch den Hinweis merging differences aufmerksam gemacht. Ob die durch diese Zusammenführung entstehende Datei sinnvoll ist oder nicht, ist CVS egal. Es kann darüber ja auch gar nichts wissen: wie sollte CVS bewerten, ob die neue Zusammenführung den Vorstellungen des Benutzers entspricht. Wenn man ein Programm dazu bringen könnte solche Beurteilungen zu treffen, dann könnte man es auch gleich für sich programmieren lassen.
Wenn zwei Dateiversionen, die CVS zusammenzuführen versucht, konkurrierende Änderungen an ein und der selben Stelle enthalten, dann kann CVS sie schlicht nicht zu einer Version zusammenführen, da es (analog zum ersten Fall) ja nicht weiß, welche der Änderungen im Sinne des Anwenders Vorrang hat. CVS markiert diese Stellen dann in der Datei und fügt beide Varianten ein. Bevor diese Markierungen von einem Anwender entfernt worden sind, also bevor der entstandene Konflikt von Hand behoben wurde, nimmt CVS die Datei nicht mehr in einem checkin entgegen.
1.4.2. Von der Konkurrenz überholt
Wie sieht das nun in der Praxis aus?
Nehmen wir an, wir haben eine Datei lokal verändert und wollen diese Änderungen nun einchecken. Hinter unserem Rücken hat aber ein anderer Benutzer eine Änderung an der selben Datei vorgenommen und diese Änderungen in das Repository eingefügt. Was zunächst passiert ist folgendes:
kai@fREUNd:~/xpenguins$ echo "/* Änderungen... */" >> xpenguins.c kai@fREUNd:~/xpenguins$ cvs ci xpenguins.c cvs commit: Up-to-date check failed for `xpenguins.c' cvs [commit aborted]: correct above errors first! kai@fREUNd:~/xpenguins$
Welche Fehler meint CVS bloß? Fragen wir CVS doch einfach, was es über den Status der Datei denkt:
kai@fREUNd:~/xpenguins$ cvs stat xpenguins.c =================================================================== File: xpenguins.c Status: Needs Merge Working revision: 1.3 Sun May 25 16:55:38 2003 Repository revision: 1.4 /home/kai/cvsroot/xpenguins/xpenguins.c,v Sticky Tag: (none) Sticky Date: (none) Sticky Options: (none) kai@fREUNd:~/xpenguins$
Ach so! Die Version von xpenguins.c in unserem Arbeitsverzeichnis ist nicht auf dem neusten Stand. Sie benötigt eine Zusammenführung mit der Dateiversion im Repository ( Status: Needs Merge ). CVS besteht also darauf, daß wir uns die neuesten Änderungen aus dem Repository holen, bevor es unsere Änderungen an der Datei akzeptiert. So wird verhindert, daß wir einfach ungewollt die Änderungen des anderen Benutzers rückgängig machen, indem wir unsere ältere Dateiversion, an der wir unsere Änderungen vorgenommen haben, einchecken. (Es wird allerdings nicht verhindert, daß wir einfach die Änderungen des anderen Benutzers nach dem merge von Hand wieder rückgängig machen und dann einchecken, ob das nun Sinn macht, oder nicht -- CVS kann nur verhindern, daß Änderungen anderer aus versehen rückgängig gemacht werden.)
1.4.3. Zurück auf den Stand der Zeit
Um die Datei wieder up-to-date zu bringen, wird natürlich das CVS-Kommando update benutzt. Zuvor sollte allerdings überprüft werden, ob sich die Änderungen des anderen Benutzers mit den unsrigen vertragen, oder ob es notwendig ist, das wir uns mit diesem einigen, welche Änderungen zu bevorzugen sind. Wir erinnern uns: Mit dem Kommando cvs diff -r1.3 -r1.4 xpenguins.c können wir uns ansehen, welche Änderungen der andere Benutzer vorgenommen hat. Der Aufruf cvs diff -r1.4 xpenguins.c vergleicht die Datei in unserer Arbeitskopie mit der von dem anderen Benutzer neu eingecheckten Version. Schließlich zeigt cvs diff xpenguins noch mal unsere Änderungen an. (Bei dem Aufruf von diff ohne weitere Argumente wird die Datei in unserer Arbeitskopie mit der Version verglichen, die wir ausgecheckt hatten.)
Wenn sich die Änderungen vertragen, können wir unsere Datei auf den Stand der Zeit bringen:
kai@fREUNd:~/xpenguins$ cvs up xpenguins.c RCS file: /home/kai/cvsroot/xpenguins/xpenguins.c,v retrieving revision 1.3 retrieving revision 1.4 Merging differences between 1.3 and 1.4 into xpenguins.c M xpenguins.c kai@fREUNd:~/xpenguins$
CVS teilt mit, daß es die Differenz zwischen der Dateiversion, die wir ursprünglich ausgecheckt hatten, und der neuen Version ermittelt und mit dem Ergebnis die Datei gepatcht hat, die sich in unserem Arbeitsverzeichnis befunden hat. Weiterhin enthält die Datei in unserem Arbeitsverzeichnis unsere Änderungen ( M für modified) und wir können diese nun ohne Beschwerde von CVS ins Repository übertragen:
kai@fREUNd:~/xpenguins$ cvs ci -m "Kein Konflikt" xpenguins.c Checking in xpenguins.c; /home/kai/cvsroot/xpenguins/xpenguins.c,v <-- xpenguins.c new revision: 1.5; previous revision: 1.4 done You have new mail in /var/mail/kai kai@fREUNd:~/xpenguins$
Spätestens jetzt sollte man sich mit dem anderen Entwickler in Verbindung setzen und sich mit ihm absprechen, bevor es zu unverträglichen Änderungen kommt. CVS bietet einen Mechanismus, der dies vereinfacht: ausgecheckte Dateien werden dann standardmäßig read-only erzeugt. Wenn man eine Datei verändern will, teilt man dies CVS mit dem Kommando edit mit. Die Datei wird dann schreibbar. Gleichzeitig informiert CVS andere Benutzer über diesen Vorgang, die es per watch dazu aufgefordert haben, die Datei für sie zu "überwachen".
1.4.4. Konfliktbewältigung
Nicht immer verläuft alles so glimpflich, wenn man sich ungenügend mit anderen Entwicklern abgesprochen hat. Angenommen wir haben eine weitere Änderung an xpenguins.c vorgenommen und wollen nun per cvs up überprüfen, ob zwischenzeitlich jemand etwas an anderen Dateien verändert hat, das wir vor unserem checkin noch berücksichtigen sollten. Hinter unserem Rücken hat aber jemand anderes eine Änderung an der selben Stelle von xpenguins.c vorgenommen und ins Repository übertragen:
kai@fREUNd:~/xpenguins$ vim xpenguins.c kai@fREUNd:~/xpenguins$ cvs up cvs update: Updating . M README RCS file: /home/kai/cvsroot/xpenguins/xpenguins.c,v retrieving revision 1.5 retrieving revision 1.6 Merging differences between 1.5 and 1.6 into xpenguins.c rcsmerge: warning: conflicts during merge cvs update: conflicts found in xpenguins.c C xpenguins.c cvs update: Updating penguins kai@fREUNd:~/xpenguins$
CVS hat wieder versucht, unsere lokale Version der Datei mit den Änderungen, die inzwischen ins Repository eingetragen wurden, zu patchen, ist dabei aber auf einen Konflikt unserer Änderungen mit denen des anderen Entwicklers gestoßen. CVS hat diesen Konflikt in der Datei markiert:
if (npenguins > MAX_PENGUINS) { fprintf(stderr,"Warning: only %d penguins created\n", npenguins=MAX_PENGUINS); <<<<<<< xpenguins.c fprintf(stderr,"Should be some more...\n"); ======= fprintf(stderr,"And that are not enough!!\n"); >>>>>>> 1.6 } else if (npenguins <= 0) { fprintf(stderr,"Warning: no penguins created\n"); npenguins=0; 87,1 16%
Solange dieser Konflikt nicht von Hand behoben wurde, d.h. solange die Markierungen nicht wieder aus der Datei entfernt wurden, nimmt CVS diese Datei bei einem commit nicht an.
Die Syntax der Markierungen ist möglichst einfach und gleichzeitig eindeutig gewählt. Wenn aber von zwei Entwicklern an ein und der selben Datei intensiv weiterentwickelt wurde, dann nimmt die Anzahl solcher Markierungen schnell eine Größenordnung an, bei der das Entfernen der Markierungen und der ungewollten Varianten sehr lange dauert. Konflikte sollten daher möglichst vermieden werden. Sie sind als Mittel der Absprache zwischen mehreren Entwicklern weder gedacht, noch geeignet!
1.5. Stolperfallen
In diesem Kapitel sollen einige übliche Stolperfallen bei der Benutzung von CVS angesprochen werden, die dem Anfänger (aber auch dem Fortgeschrittenen) Schwierigkeiten bereiten.
1.5.1. Umgang mit Bildern und anderen Binaries
Leider kann mit Bildern und anderen Binärdateien unter CVS nicht ganz so sorglos umgegangen werden, wie man dies gerne hätte. Dies liegt daran, daß CVS einen Mechanismus anbietet, um in ausgecheckten Dateien automatisch zu vermerken, um welche Version der Datei es sich handelt, wer sie zuletzt verändert hat und vieles mehr. Dies wird realisiert, indem der Benutzer in der Datei bestimmte Schlüsselwörter verwendet, die dann von CVS beim auschecken entsprechend verändert werden. Diese Schlüsselwörter können in einer Binärdatei natürlich an beliebig blödsinnigen Stellen zufällig vorkommen. Man muß CVS daher im Falle einer Binärdatei mitteilen, daß es keine Schlüsselwörter ersetzen soll. Dies geschieht mit dem Schalter -kb , ansonsten ändert sich nichts.
kai@fREUNd:~/xpenguins/penguins$ cp walker.xpm neu.xpm kai@fREUNd:~/xpenguins/penguins$ cvs add -kb neu.xpm cvs add: scheduling file `neu.xpm' for addition cvs add: use 'cvs commit' to add this file permanently kai@fREUNd:~/xpenguins/penguins$ cvs ci -m "Ein Bild" neu.xpm RCS file: /home/kai/cvsroot/xpenguins/penguins/neu.xpm,v done Checking in neu.xpm; /home/kai/cvsroot/xpenguins/penguins/neu.xpm,v <-- neu.xpm initial revision: 1.1 done kai@fREUNd:~/xpenguins/penguins$
Wie man vorgeht, wenn man den Schalter -kb beim c von Bildern vergisst (was leidlich oft passiert), ist in der CVS Online-Doku beschrieben.
1.5.2. Dateien verschieben
Eine weitere Schwierigkeit, die daraus resultiert, wie CVS Dateien eines Projektes intern abbildet, besteht in der simplen Operation eine Datei zu verschieben, bzw. umzubenennen. Dies ist mit CVS schlicht nicht möglich!
Es gibt jedoch zwei Wege, dieses Problem zu umgehen, die jedoch beide Vor- und Nachteile haben:
Man kann die Datei zuerst per cvs rm löschen und anschließend per cvs add unter dem neuen Namen bzw. an dem neuen Ort wieder auferstehen lassen. Der Nachteil dieser Methode ist, daß die Änderungen an dieser Datei nicht mehr an einer Stelle vorliegen: der Teil der Änderungen vor der Umbenennung/Verschiebung ist unter dem alten Dateinamen einsehbar, der Teil danach unter dem neuen Dateinamen. Dieser Nachteil kann gemildert werden, indem die rm - und die add -Operation in einem ci in das Repository übertragen und in der zugehörigen Log-Nachrichtung explizit erwähnt werden.
Die andere Möglichkeit besteht darin, die Datei im Repository umzubenennen, bzw. zu verschieben! Diese Methode ist natürlich viel bequemer. Außerdem sind später alle Änderung an der Datei unter dem neuen Dateinamen abrufbar, allerdings bis auf die nicht unwesentliche Umbenennung, bzw. Verschiebung selbst. Der große Nachteil dieser Methode ist, daß ein Checkout einer Version vor der Umbenennung in der Regel nicht mehr konsistent ist. Denn da CVS nichts von der Umbenennung/Verschiebung weiß, wird die Datei in dieser älteren Version unter ihrem neuen Namen erscheinen!
Da eine Versions-Kontrolle, die keine korrekten Versionen liefert, wenig Sinn macht, sollte die Umbenennung im Repository nur in Ausnahmefällen durchgeführt werden!
1.5.3. Verzeichnisse verschieben
Bei Verzeichnissen bestehen die selben Schwierigkeiten, die mit den selben Workarounds umgangen werden müssen. Der Unterschied besteht darin, daß der Aufwandsunterschied zwischen den beiden Methoden wesentlich größer wird. Wenn man direkt im Repository arbeitet, kann man einfach wie gewohnt das eine Verzeichnis verschieben bzw. umbenennen. Wenn man den Repository über die Bruchstelle der Verschiebung/Umbenennung hinweg konsistent halten will, muß man alle Dateien und Verzeichnisse, die sich in dem Verzeichnis befinden, einzeln löschen und wieder einfügen! Man sollte bei CVS also bei Beginn eines Projektes genau überlegen, wie die Verzeichnisstruktur aussehen soll. Dies ist leider oft nicht möglich!
Weiterhin verwirrend in diesem Zusammenhang ist, daß sich Verzeichnisse unter CVS eigentlich gar nicht löschen lassen! Damit man trotzdem nicht alle ehemaligen Unterverzeichnisse in seiner Arbeitskopie herumfliegen hat, holt CVS Verzeichnisse bei einem update nicht automatisch. Man muß es mit up -d explizit dazu auffordern! Auf diese Weise werden gelöschte Verzeichnisse nicht bei jedem update neu erzeugt. Der Nachteil dabei ist, daß man schnell mal vergißt, -d mit anzugeben, wenn es eigentlich nötig wäre, nämlich wenn dem Repository ein neues Verzeichnis hinzugefüg wurde!
1.6. Nachtrag
Ein wesentlicher Punkt wurden in dem ursrprünglich geplanten Vortragsverlauf nicht berücksichtigt: die Erzeugung von Versionsnummerierungen, die der Sicht des Anwenders auf die einzelnen Versionen im Repository entsprechen. Dies soll hier nachgetragen werden.
1.6.1. Versionsnummern versus Tags
Die Versionsnummern, die in dem Abschnitt Weiterlaufen benutzt wurden, um die Unterschiede zwischen bestimmten, mit Hilfe des Kommandos log ausgesuchten Versionen anzuzeigen, stellen die interne Sicht von CVS auf die im Repository vorhandenen Versionen dar. Aufgrund der Arbeitsweise von CVS sind diese Versionsnummern nicht dafür geeignet, eine gesamte Arbeitskopie auf einen bestimmten Stand zurückzuversetzen! Dies liegt an der dateibasierten Arbeitsweise von CVS. CVS speichert die Versionen der einzelnen Dateien eines Projektes auch intern in einzelnen Dateien ab. Dies hat zur Folge, daß CVS die Versionsnummern für jede Datei eines Projektes einzeln zählt. Dateien, die besonders oft verändert und eingecheckt wurden haben daher zu einem bestimmten Zeitpunkt (z.B. bei einem Release) eine wesentlich höhere Versionsnummer als Dateien, die kaum verändert wurden, oder erst zu einem späteren Zeitpunkt erzeugt wurden. Wenn man also später seine Arbeitskopie auf den Stand dieses Releases zurückversetzen will, so kann man das nicht tun, in dem man mit -r die Versionsnummer angibt, die eine der Dateien zu dem Zeitpunkt des Releases hatte.
Um dieses Ziel zu erreichen, muß man dem Projekt zu diesem Zeitpunkt eine symbolische Versionsbezeichnung geben. Symbolisch, weil diese Versionsbezeichnung nicht unbedingt eine Zahlenfolge ist. Dies geschieht mit dem Kommando tag . Die symbolische Versionsbezeichnung muß mit einem Buchstaben anfangen und darf außer Buchstaben und Zahlen nur einen Unter- oder Bindestrich enthalten.
kai@fREUNd:~/xpenguins$ cvs tag Version-1_2kai01 cvs tag: Tagging . T AUTHORS T COPYING T ChangeLog T INSTALL T LIESMICH T Makefile T README T toon.c T toon.h T vroot.h T xpenguins T xpenguins.1 T xpenguins.c cvs tag: Tagging penguins T penguins/bomber.xpm T penguins/climber.xpm T penguins/def.h T penguins/explosion.xpm T penguins/faller.xpm T penguins/floater.xpm T penguins/neu.xpm T penguins/tumbler.xpm T penguins/walker.xpm kai@fREUNd:~/xpenguins$
Dieses Kommando ordnet den Dateiversionen, die sich zur Zeit in der Arbeitskopie befinden, die symbolische Version Version-1_2kai01 zu. Später können also genau die Dateiversionen, die sich zum Zeitpunkt des tag -Aufrufes in der Arbeitskopie befanden mit cvs up -r Version-1_2kai01 wieder aus dem Repository in die Arbeitskopie geholt werden.
Zwei Bilder aus dem CVS-Buch (siehe Quellen) veranschaulichen den Nutzen von tag
File A File B File C File D File E ------ ------ ------ ------ ------ 1.1 1.1 1.1 1.1 1.1 ----1.2-. 1.2 1.2 1.2 1.2 1.3 | 1.3 1.3 1.3 1.3 \ 1.4 .-1.4-. 1.4 1.4 \ 1.5 / 1.5 \ 1.5 1.5 \ 1.6 / 1.6 | 1.6 1.6 \ 1.7 / | 1.7 1.7 \ 1.8 / | 1.8 .-1.8-------> \ 1.9 / | 1.9 / 1.9 `1.10' | 1.10 / 1.10 1.11 | 1.11 | | 1.12 | | 1.13 | \ 1.14 | \ 1.15 / \ 1.16 / `-1.17-' [Figure 2.1: How a tag might stand in relation to files's revisions.]
Die geschlängelte Linie repräsentiert dabei den Stand der Arbeitskopie zum Zeitpunkt des tag -Aufrufes (nicht alle Dateien befanden sich auf dem aktuellsten Stand).
File A File B File C File D File E ------ ------ ------ ------ ------ 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.1 1.8 1.2 1.9 1.3 1.10 1.1 1.4 1.11 1.2 1.5 1.12 1.3 1.6 1.13 1.4 1.7 1.1 1.14 1.5 1.8 1.2 1.15 1.6 1.1 1.9 1.3 1.16 1.7 ----1.2---------1.10--------1.4---------1.17--------1.8-------> 1.3 1.11 1.5 1.17 1.9 1.6 1.17 1.10 [Figure 2.2: The same tag as a "straight sight" through the revision history.]
Bei der Benutzung des Kommandos tag sind zwei Besonderheiten zu beachten:
- Das Kommando arbeitet direkt auf dem Repository. Es wird direkt durch den Aufruf des Kommandos veranlaßt, daß im Repository für die einzelnen Dateien vermerkt wird, welche Dateiversion zu dem Tag gehört.
Das tag -Kommando interessiert nur, welche Dateiversionen in der Arbeitskopie liegen. Da das Kommando direkt auf dem Repository arbeitet bleiben eventuell in der Arbeitskopie vorgenommene Änderungen, die noch nicht eingecheckt wurden, unberücksichtigt!
Es wird diesbezüglich auch keine Warnmeldung ausgegeben!
Die Tags können später ebenso wie die Versionsnummern benutzt werden.
1.6.2. Zeitreisen per Datum
Eine weitere Möglichkeit, die gesamte Arbeitskopie in einen vergangenen Zustand zurückzuversetzen, ist die Angabe eines Datums. Was bei der Angabe des Datums zu beachten ist, um wirklich die Versionen zu erhalten, die man haben möchte, ist im CVS-Buch erklärt.
1.6.3. Branching
Dort ist auch erklärt, wie man einen Tag zu dem Abzweig für einen Branch machen kann.
1.7. Weiterführende Dokumentation
- * CVS Online-Doku
Online Dokumentation der CVS-Entwickler auf http://www.cvshome.org/
- * The CVS Book
Online-Version eines kompletten Buches über CVS. Das Buch steht unter der GPL!
- * Das CVS Buch
Die deutsche online Übersetzung dieses Buches (nicht ganz vollständig).