|
In Kapitel 4 habe ich kurz das Kommando cvs history erwähnt. Dieses
Kommando zeigt eine Zusammenfassung aller checkouts, commits, updates,
rtags und releases an, die im Archiv getätigt wurden (vorausgesetzt,
Logging war bei Erstellung der Datei CVSROOT/history im Archiv aktiv).
Mit den folgenden Kommandos können Sie Inhalt und Erscheinungsbild
der Zusammenfassung mit verschiedenen Optionen kontrollieren.
Der erste Schritt liegt darin, sicherzustellen, dass Logging im Archiv
eingeschaltet ist. Der Archivadministrator sollte erst einmal
sicherstellen, dass es eine Datei history gibt:
user@linux ~$
cd /usr/local/newrepos/CVSROOT
user@linux ~$
ls -l history
ls: history: No such file or directory
|
und falls es keine gibt, sollte er eine wie folgt erstellen:
user@linux ~$
touch history
user@linux ~$
ls -l history
-rw-r--r-- 1 jrandom cvs 0 Jul 22 14:57 history
|
Die Datei history soll außerdem von jedem, der das Archiv benutzt,
beschreibbar sein, ansonsten wird dieser jedes Mal, wenn er ein
CVS-Kommando, das diese Datei verändert, ausführen will, eine
Fehlermeldung erhalten. Am einfachsten macht man die Datei von allen
beschreibbar:
user@linux ~$
chmod a+rw history
user@linux ~$
ls -l history
-rw-rw-rw- 1 jrandom cvs 0 Jul 22 14:57 history
|
Bemerkung
Im Fall, dass das Archiv mit dem Kommando cvs init angelegt wurde,
existiert die Datei bereits. Um die Zugriffsrechte muss man sich
allerdings noch kümmern.
|
In den folgenden Beispielen wird davon ausgegangen, dass History
Logging, also die Aufzeichnung der Projekthistorie, schon eine Weile
eingeschaltet war, sodass sich schon einiges an Daten in der Datei
history angesammelt hat.
Die Ausgabe von cvs history ist etwas knapp geraten (sie ist
vermutlich nicht dafür gedacht, von Menschen analysiert zu werden,
obwohl sie mit ein wenig Übung gut lesbar ist). Rufen wir das Kommando
kurz auf und sehen, was wir bekommen:
user@linux ~$
paste$ pwd
/home/qsmith/myproj
user@linux ~$
paste$ cvs history -e -a
O 07/25 15:14 +0000 qsmith myproj =mp= ~/* M 07/25 15:16 +0000 qsmith 1.14 hello.c myproj == ~/mp U 07/25 15:21 +0000 qsmith 1.14 README.txt myproj == ~/mp G 07/25 15:21 +0000 qsmith 1.15 hello.c myproj == ~/mp A 07/25 15:22 +0000 qsmith 1.1 goodbye.c myproj == ~/mp M 07/25 15:23 +0000 qsmith 1.16 hello.c myproj == ~/mp M 07/25 15:26 +0000 qsmith 1.17 hello.c myproj == ~/mp U 07/25 15:29 +0000 qsmith 1.2 goodbye.c myproj == ~/mp G 07/25 15:29 +0000 qsmith 1.18 hello.c myproj == ~/mp M 07/25 15:30 +0000 qsmith 1.19 hello.c myproj == ~/mp O 07/23 03:45 +0000 jrandom myproj =myproj= ~/src/* F 07/23 03:48 +0000 jrandom =myproj= ~/src/* F 07/23 04:06 +0000 jrandom =myproj= ~/src/* M 07/25 15:12 +0000 jrandom 1.13 README.txt myproj == ~/src/myproj U 07/25 15:17 +0000 jrandom 1.14 hello.c myproj == ~/src/myproj M 07/25 15:18 +0000 jrandom 1.14 README.txt myproj == ~/src/myproj M 07/25 15:18 +0000 jrandom 1.15 hello.c myproj == ~/src/myproj U 07/25 15:23 +0000 jrandom 1.1 goodbye.c myproj == ~/src/myproj U 07/25 15:23 +0000 jrandom 1.16 hello.c myproj == ~/src/myproj U 07/25 15:26 +0000 jrandom 1.1 goodbye.c myproj == ~/src/myproj G 07/25 15:26 +0000 jrandom 1.17 hello.c myproj == ~/src/myproj M 07/25 15:27 +0000 jrandom 1.18 hello.c myproj == ~/src/myproj C 07/25 15:30 +0000 jrandom 1.19 hello.c myproj == ~/src/myproj M 07/25 15:31 +0000 jrandom 1.20 hello.c myproj == ~/src/myproj M 07/25 16:29 +0000 jrandom 1.3 whatever.c myproj/a-subdir == ~/src/myproj
|
Ist doch alles klar verständlich, oder?
Bevor wir die Ausgabe näher untersuchen, sei angemerkt, dass der
Aufruf zusammen mit zwei Optionen geschah: -e und
-a. Wenn Sie history
aufrufen, werden Sie fast immer Optionen mit angeben wollen, die
festlegen, welche Daten wie angezeigt werden sollen. Darin
unterscheidet es sich von den meisten anderen CVS-Kommandos, die
normalerweise bereits dann etwas Sinnvolles tun, wenn sie ganz ohne
Optionen aufgerufen werden. In unserem Beispiel bedeuten die Optionen
»alles« (jede Art von Ereignis) beziehungsweise »alle« (für alle
Benutzer).
Das history-Kommando unterscheidet sich von anderen Kommandos auch
noch darin, dass, obwohl es normalerweise aus einer Arbeitskopie
heraus aufgerufen wird, es seine Ausgabe nicht auf das in der
Arbeitskopie enthaltene Projekt beschränkt. Stattdessen zeigt es die
gesamte Historie aller Projekte im Archiv an - die Arbeitskopie dient
nur dazu, CVS mitzuteilen, welchem Archiv die history-Daten entnommen
werden sollen. (Im vorangegangenen Beispiel waren die einzigen
history-Daten die vom Projekt myproj, daher sieht man sonst keine.)
Das generelle Format der Ausgabe ist
KÜRZEL DATUM BENUTZER [REVISION] [DATEI] PFAD_IM_ARCHIV NAME_DER_ARBEITSKOPIE
Die Buchstabenkürzel beziehen sich auf die verschiedenen
CVS-Operationen, wie in Tabelle 6.1 dargestellt.
Für Operationen (wie z.B. checkout), die sich auf das Projekt als
Ganzes anstelle von einzelnen Dateien davon beziehen, werden die
REVISION und DATEI weggelassen, stattdessen wird der Pfad des Archivs
zwischen die Gleichheitszeichen gesetzt.
Obwohl die Ausgabe des Kommandos history vom Design her als kompakte,
interpretierbare Eingabe für andere Programme gedacht ist, gibt CVS
einem viel Kontrolle über Umfang und Inhalt. Die in Tabelle 6.2
aufgelisteten Optionen kontrollieren, welche Typen von Ereignissen
gemeldet werden. Wenn Sie ausgewählt haben, welche Ereignisse Sie
angezeigt bekommen möchten, können Sie noch weitere Filterkriterien
der Tabelle 6.3 entnehmen.
Buchstabenkürzel
|
Bedeutung
|
O
|
Auschecken (Checkout) einer Datei
|
T
|
Marke (Tag)
|
F
|
Freigabe (siehe Release)
|
W
|
Update (Benutzerdatei wurde gelöscht, Datei aus entries
entfernt. Die Datei war im Archiv gelöscht worden.)
|
U
|
Update (Datei hat unveränderte Datei des Benutzers überschrieben)
|
G
|
Update (Datei wurde erfolgreich mit einer vom Benutzer
veränderten Datei verschmolzen)
|
C
|
Update (Datei wurde verschmolzen, aber Konflikt mit einer vom
Benutzer geänderten Datei, conflicts)
|
M
|
Commit (einer modifizierten Datei)
|
A
|
Commit (einer neuen Datei, add)
|
R
|
Commit (Löschen einer Datei, remove)
|
E
|
Export (siehe Kapitel 9)
|
Tabelle 6.1 Die Bedeutung der Buchstabenkürzel
Option
|
Bedeutung
|
-m MODUL
|
Zeige Vorgänge, die MODUL betreffen
|
-c
|
Zeige Commit-Vorgänge
|
-o
|
Zeige Checkout-Vorgänge
|
-T
|
Zeige alle Vorgänge, die Marken (Tags) betreffen
|
-x KÜRZEL
|
Zeige alle Vorgänge, die vom Typ KÜRZEL sind (mindestens
eines aus OTFWUGCMARE, siehe Tabelle 6.1)
|
-e
|
Zeige einfach alle Vorgänge
|
Tabelle 6.2 Optionen, die nach Ereignistyp filtern
Option
|
Bedeutung
|
-a
|
Zeige die Aktionen aller Benutzer
|
-w
|
Zeige nur die Aktionen, die aus dieser Arbeitskopie heraus
vorgenommen wurden
|
-l
|
Zeige nur die letzte solche Aktion dieses Benutzers
|
-u BENUTZER
|
Zeige die Einträge für BENUTZER
|
Tabelle 6.3 Optionen, die Benutzer heraus filtern
|
Wenn das history-Kommando einem einen groben Überblick über die
Projektaktivitäten gibt, dann ist das annotate9-Kommando sozusagen das
Mikroskop, das es einem ermöglicht, die Details zu erkennen. Mit
annotate kann man sehen, wer die letzte Person war, die ihre Finger an
den einzelnen Zeilen einer Datei hatte, und bei welcher Revision dies
geschah:
user@linux ~$
floss$ cvs annotate
Annotations for README.txt *************** 1.14 (jrandom 25-Jul-99): blah 1.13 (jrandom 25-Jul-99): test 3 for history 1.12 (qsmith 19-Jul-99): test 2 1.11 (qsmith 19-Jul-99): test 1.10 (jrandom 12-Jul-99): blah 1.1 (jrandom 20-Jun-99): Just a test project. 1.4 (jrandom 21-Jun-99): yeah. 1.5 (jrandom 21-Jun-99): nope. Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.15 (jrandom 25-Jul-99): /* another test for history */ 1.13 (qsmith 19-Jul-99): /* random change number two */ 1.10 (jrandom 12-Jul-99): /* test */ 1.21 (jrandom 25-Jul-99): printf ("Hellooo, world!\n"); 1.3 (jrandom 21-Jun-99): printf ("hmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.11 (qsmith 18-Jul-99): /* added this comment */ 1.16 (qsmith 25-Jul-99): /* will merge these changes */ 1.18 (jrandom 25-Jul-99): /* will merge these changes too */ 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): } Annotations for a-subdir/whatever.c *************** 1.3 (jrandom 25-Jul-99): /* A completely non-empty C file. */ Annotations for a-subdir/subsubdir/fish.c *************** 1.2 (jrandom 25-Jul-99): /* An almost completely empty C file. */ Annotations for b-subdir/random.c *************** 1.1 (jrandom 20-Jun-99): /* A completely empty C file. */
|
Die Ausgabe von annotate lässt sich intuitiv erfassen. Links sind
Revisionsnummer, Entwickler und da Datum, zu dem die fragliche Zeile
hinzugefügt oder verändert wurde. Rechts sieht man die eigentliche
Zeile zur jeweils aktuellen Revision. Da jede Zeile mit Anmerkungen
(also Revisionsnummer, Entwickler und Datum) versehen ist, bekommt
man den ganzen Inhalt der Datei aufgelistet, aber um die Anmerkungen
nach rechts verschoben.
Wenn man eine Revisionsnummer oder eine Marke (Tag) spezifiziert,
bekommt man die Anmerkungen, die zu dieser Revision aktuell waren;
soll heißen: Es werden die letzten Modifikationen jeder Zeile zu oder
bis zu dieser Revision angezeigt. Das ist wahrscheinlich der üblichste
Weg, annotate zu benutzen: Eine einzige Datei zu einer bestimmten
Revision zu untersuchen, um zu erkennen, welche Entwickler an welchen
Teilen der Datei aktiv waren.
Zum Beispiel kann man in der Ausgabe aus dem vorangegangenen Beispiel
sehen, dass die aktuellste Revision von hello.c 1.21 ist, als jrandom
etwas an folgender Zeile änderte:
printf ("Hellooo, world!\n");
Ein Weg herauszufinden, was sie getan hat, ist, sich den diff10
zwischen dieser Revision und der vorangegangenen anzusehen:
user@linux ~$
cvs diff -r 1.20 -r 1.21 hello.c
index: hello.c =============================================== RCS file: /usr/local/newrepos/myproj/hello.c,v retrieving revision 1.20 retrieving revision 1.21 diff -r1.20 -r1.21 9c9 < printf ("Hello, world!\n"); -- > printf ("Hellooo, world!\n");
|
Eine weitere Möglichkeit, unter Beibehaltung des dateiweiten
Überblicks über die allgemeinen Aktivitäten herauszufinden, was
geschehen ist, liegt darin, die aktuellen Anmerkungen mit denen der
vorigen Version zu vergleichen:
user@linux ~$
floss$ cvs annotate -r 1.20 hello.c
Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.15 (jrandom 25-Jul-99): /* another test for history */ 1.13 (qsmith 19-Jul-99): /* random change number two */ 1.10 (jrandom 12-Jul-99): /* test */ 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.3 (jrandom 21-Jun-99): printf ("hmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.11 (qsmith 18-Jul-99): /* added this comment */ 1.16 (qsmith 25-Jul-99): /* will merge these changes */ 1.18 (jrandom 25-Jul-99): /* will merge these changes too */ 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): }
|
Obwohl diff die Fakten über die Veränderung des Quelltextes in
knapperer Form darstellt, können die Anmerkungen vorzuziehen sein,
denn durch sie wird der geschichtliche Kontext hergestellt, indem
gezeigt wird, wie lange die vorige Ausführung vorhanden war (in
unserem Fall die ganze Zeit, seit Revision 1.1). Dieses Wissen kann
Ihnen bei der Entscheidung helfen, ob Sie in die Logs schauen wollen,
um die Motivation für die Änderungen herauszufinden:
user@linux ~$
cvs log -r 1.21 hello.c
RCS file: /usr/local/newrepos/myproj/hello.c,v Working file: hello.c head: 1.21 branch: locks: strict access list: symbolic names: random-tag: 1.20 start: 1.1.1.1 jrandom: 1.1.1 keyword substitution: kv total revisions: 22; selected revisions: 1 description: --------------------------- evision 1.21 date: 1999/07/25 20:17:42; author: jrandom; state: Exp; lines: +1 -1 say hello with renewed enthusiasm ==============================================
|
Zusätzlich zu -r können Sie die Anmerkungen auch mit der Option -D
DATUM filtern:
user@linux ~$
cvs annotate -D "5 weeks ago" hello.c
Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.1 (jrandom 20-Jun-99): } floss$ cvs annotate -D "3 weeks ago" hello.c Annotations for hello.c ************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.3 (jrandom 21-Jun-99): printf ("hmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): }
|
Anmerkungen und Verzweigungen
Wenn Sie keine weiteren Optionen angeben, zeigt annotate immer die
Aktivitäten der Stammversion (engl. trunk). (Die Tendenz, die
Stammversion so zu bevorzugen, ist entweder ein Bug oder ein Feature,
je nach Standpunkt.) Sie können CVS zwingen, die Anmerkungen einer
abgezweigten Version auszugeben, indem Sie die Marke dieses Zweiges
als Argument für -r übergeben. Hier ein Beispiel einer Arbeitskopie,
in der sich hello.c in einer abgezweigten Version namens
Brancho_Gratuito befindet und in der mindestens eine Änderung in dem
Zweig per Commit vorgenommen wurde:
user@linux ~$
cvs status hello.c
================================================== File: hello.c Status: Up-to-date Working revision: 1.10.2.2 Sun Jul 25 21:29:05 1999 Repository revision: 1.10.2.2 /usr/local/newrepos/myproj/hello.c,v Sticky Tag: Brancho_Gratuito (branch: 1.10.2) Sticky Date: (none) Sticky Options: (none floss$ cvs annotate hello.c Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.10 (jrandom 12-Jul-99): /* test */ 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.3 (jrandom 21-Jun-99): printf ("hmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): } floss$ cvs annotate -r Brancho_Gratuito hello.c Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.10 (jrandom 12-Jul-99): /* test */ 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.10.2.2 (jrandom 25-Jul-99): printf ("hmmmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.10.2.1 (jrandom 25-Jul-99): printf ("added this line"); 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): }
|
Sie können auch die Nummer der Zweigversion übergeben:
user@linux ~$
cvs annotate -r 1.10.2 hello.c
Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.10 (jrandom 12-Jul-99): /* test */ 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.10.2.2 (jrandom 25-Jul-99): printf ("hmmmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.10.2.1 (jrandom 25-Jul-99): printf ("added this line"); 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): }
|
oder auch eine vollständige Revisionsnummer innerhalb der Zweigversion:
user@linux ~$
cvs annotate -r 1.10.2.1 hello.c
Annotations for hello.c *************** 1.1 (jrandom 20-Jun-99): #include <stdio.h> 1.1 (jrandom 20-Jun-99): 1.1 (jrandom 20-Jun-99): void 1.1 (jrandom 20-Jun-99): main () 1.1 (jrandom 20-Jun-99): { 1.10 (jrandom 12-Jul-99): /* test */ 1.1 (jrandom 20-Jun-99): printf ("Hello, world!\n"); 1.3 (jrandom 21-Jun-99): printf ("hmmm\n"); 1.4 (jrandom 21-Jun-99): printf ("double hmmm\n"); 1.10.2.1 (jrandom 25-Jul-99): printf ("added this line"); 1.2 (jrandom 21-Jun-99): printf ("Goodbye, world!\n"); 1.1 (jrandom 20-Jun-99): }
|
Wenn Sie so vorgehen, vergessen Sie nicht, dass die Nummern nur für
diese eine Datei gültig sind. Generell ist es wohl besser, - sofern
möglich - den Namen der Zweigversion zu benutzen.
|
|