File: chapter-4.texi

package info (click to toggle)
cvsbook 1.21-3
  • links: PTS
  • area: main
  • in suites: woody
  • size: 664 kB
  • ctags: 25
  • sloc: makefile: 108; python: 52; lisp: 24
file content (2246 lines) | stat: -rw-r--r-- 86,069 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
@c ---------------------------------------------------------------------
@node Repository Administration
@unnumbered Repository Administration

In @ref{An Overview of CVS}, you learned enough CVS to use it
effectively as a project participant.  If you're going to be a project
maintainer, however, you'll need to know how to install CVS and
administer repositories.  In this chapter, we'll throw back the curtain
and look in detail at how the repository is structured, and how CVS uses
it.  You'll learn all the major steps CVS goes through during updates
and commits, and how you can modify its behavior.  By understanding how
CVS works, you'll also be able to trace problems to their causes, and
fix them in maintainable ways.

This may sound very involved, but remember that CVS has already proven
quite long-lived, and will probably be around for many years to come.
Whatever you learn now will be useful for a long time.  CVS also tends
to become more indispensable the more you use it.  If you're going to be
that dependent on something (and trust me, you are), it's worth really
getting to know it.

With that in mind, let's begin at the beginning: putting CVS on your
system.

@menu
* Getting And Installing CVS::             Putting CVS on your system.
* Anatomy Of A CVS Distribution::          What's in the CVS distribution.
* Starting A Repository::                  Setting up a repository.
* The Password-Authenticating Server::     One method of remote access.
* Anonymous Access::                       Granting access to the public.
* Repository Structure::                   How the repository is arranged.
* RCS Format::                             How repository storage works.
* What Happens When You Remove A File::    CVS keeps an Attic for old files.
* The CVSROOT/ Administrative Directory::  Run-time server configuration files.
* Commit Emails::                          Arranging automatic commit notices.
* Finding Out More::                       Other sources of information.
@end menu

@c -----------------------------------------------------
@node Getting And Installing CVS
@section Getting And Installing CVS

In many cases, you won't have to go out and get CVS, because it will
already be on your system.  If you run one of the major Linux or FreeBSD
distributions, it's probably already installed in /usr/bin or some other
likely location.  If not, Red Hat Linux users can usually find an RPM
(Red Hat Package) for the latest, or nearly latest, version of CVS in
their distributions.  And Debian users can install the latest Debian
package with these commands:

@example
floss$ apt-get update
floss$ apt-get install cvs
@end example

If CVS isn't already on your machine, you'll probably have to build it
from source.  If you're a non-Unix user, you'll probably find it easier
to get a prebuilt binary for your operating system (more on that later).
Fortunately, CVS is fully @dfn{autoconfiscated} -- that is, it uses the
GNU autoconfiguration mechanism, making compilation from source
surprisingly easy.

@menu
* Getting And Building CVS Under Unix::
* Getting And Installing CVS Under Windows::
* Getting And Installing CVS On A Macintosh::
* Limitations Of The Windows And Macintosh Versions::
@end menu

@c ---------------------------
@node Getting And Building CVS Under Unix
@subsection Getting And Building CVS Under Unix

As of this writing, there are two canonical sites from which you can
download CVS.  One is the Free Software Foundation's FTP site,
@uref{ftp://ftp.gnu.org/gnu/cvs/}, which offers CVS as an official GNU
tool.  The other is Cyclic Software's download site.  Cyclic Software
is, if not the maintainer of CVS, then the "maintainer of the
maintainers", by providing a repository server and download access for
users and developers.  They distribute releases from
@uref{http://download.cyclic.com/pub/}.

Either location is fine.  In the following example, I use Cyclic
Software's site.  If you point your FTP client (probably your Web
browser) there, you'll see a list of directories, something like this:

@example
Index of /pub
    cvs-1.10.5/            18-Feb-99 21:36      -  
    cvs-1.10.6/            17-May-99 10:34      -  
    cvs-1.10/              09-Dec-98 17:26      -  
    macintosh/             23-Feb-99 00:53      -  
    os2/                   09-Dec-98 17:26      -  
    packages/              09-Dec-98 17:26      -  
    rcs/                   09-Dec-98 17:26      -  
    tkcvs/                 09-Dec-98 17:26      -  
    training/              09-Dec-98 17:26      -  
    unix/                  09-Dec-98 17:26      -  
    vms/                   09-Dec-98 17:26      -  
@end example

Pay attention to the directories beginning with "cvs-" (you can ignore
most of the others).  There are three such directories, which means that
you're already faced with a choice: Get the designated "stable" release,
or go with a newer (but less-tested) interim release.  The stable
releases have only one decimal point, as in "cvs-1.10", whereas the
interim releases have minor version increments tacked on the end, as in
"1.10.5".

The GNU site usually only offers the major releases, not the interim
ones, so you won't see all of this if you get CVS from there.  In
general, the interim releases have been pretty safe, and sometimes
contain fixes to bugs that were found in the major release.  Your best
policy is to go with the highest interim release, but if you encounter
any problems with it, be prepared to drop back to the previous release,
as many times as necessary.  The highest release listed in the earlier
example is cvs-1.10.6.  Entering that directory, we see this:

@example
Index of /pub/cvs-1.10.6
    cvs-1.10.6.tar.gz      17-May-99 08:44   2.2M  
@end example

That's it -- the full source code to CVS.  Just download it to your
machine, and you're ready to build.  At this point, if you're already
familiar with the standard build process for GNU tools, you know what to
do and probably don't need to read anything between here and the section
@ref{Anatomy Of A CVS Distribution}.  On the other hand, if you're not
sure how to proceed, then read on....

The following compilation instructions and examples assume that you have
a fairly standard distribution of Unix.  Any of the free versions of
Unix (for example, FreeBSD or Linux) should work with no problem, as
should the major commercial Unix versions (such as SunOS/Solaris, AIX,
HP-UX, or Ultrix).  Even if these instructions don't work for you
exactly as written, don't give up hope.  Although covering the details
of compiling on every operating system is beyond the scope of this book,
I'll give some pointers to other help resources later in this chapter.

Anyway, to proceed with the compilation, first unpack the tar file using
GNU gunzip and tar (if you don't have these installed on your system,
you can get gunzip from @uref{ftp://ftp.gnu.org/gnu/gzip/} and GNU's
version of tar from @uref{ftp://ftp.gnu.org/gnu/tar/}):

@example
floss$ gunzip cvs-1.10.6.tar.gz
floss$ tar xvf cvs-1.10.6.tar
@end example

You'll see a lot of file names fly by on your screen. 

Now you have a new directory on your machine -- cvs-1.10.6 -- and it is
populated with the CVS source code.  Go into that directory and
configure CVS for your system, by using the provided configure script:

@example
floss$ cd cvs-1.10.6
floss$  ./configure
creating cache ./config.cache
checking for gcc... gcc
checking whether we are using GNU C... yes
checking whether gcc accepts -g... yes
checking how to run the C preprocessor... gcc -E
  (etc) 
@end example

When the configure command finishes, the source tree will know
everything it needs to know about compiling on your machine.  The next
step is to type:

@example
floss$ make
@end example

You'll see lots of output fly by, then type:

@example
floss$ make install
@end example

You'll see yet more output fly by; when it's all over, CVS will be
installed on your system.  (You will probably need to do that last step
as the superuser.)

By default, the CVS executable will end up as @file{/usr/local/bin/cvs}.
This assumes you have a decent make program installed on your system
(again, if you don't have one, get the GNU project's make from
@uref{ftp://ftp.gnu.org/gnu/make/}).

If you want CVS to install to a location other than /usr/local/bin, you
should change how you run the initial configuration step.  For example,

@example
floss$ ./configure --prefix=/usr
@end example

results in CVS being installed as /usr/bin/cvs (it always ends up as
PREFIX/bin/cvs).  The default prefix is /usr/local, which is fine for
most installations.

Note To Experienced Users: Although older versions of CVS consisted of
more than just an executable in that they depended on having RCS
installed as well, this has not been the case since Version 1.10.
Therefore, you don't need to worry about any libraries or executables
other than cvs itself.

If you just intend to use CVS to access remote repositories, the
preceding is all you need to do.  If you also plan to serve a repository
from this system, a few additional steps are necessary, which are
covered later in this chapter.

@c ---------------------------
@node Getting And Installing CVS Under Windows
@subsection Getting And Installing CVS Under Windows

Unless you're truly religious about having the source code to your
executable, you don't need to compile CVS from source on your Windows
box.  Unlike Unix, the necessary compilation tools probably do not
already exist on your system, so a source build would involve first
going out and getting those tools.  Because such a project is beyond the
scope of this book, I'll just give instructions for getting a
precompiled CVS binary.

First, note that Windows binary distributions of CVS are usually made
only for major releases of CVS -- not for the interim releases -- and
are not found on the GNU FTP site.  So you'll need to go to Cyclic
Software's download site, where in the major version directory,
@uref{http://download.cyclic.com/pub/cvs-1.10/}, you'll see an extra
subdirectory

@example
Index of /pub/cvs-1.10
    cvs-1.10.tar.gz        14-Aug-98 09:35   2.4M  
    windows/        
@end example

inside of which is a ZIP file:

@example
Index of /pub/cvs-1.10/windows
    cvs-1.10-win.zip       14-Aug-98 10:10   589k  
@end example

This ZIP file contains a binary distribution of CVS.  Download and
extract that ZIP file:

@example
floss$ unzip cvs-1.10-win.zip

Archive:  cvs-1.10-win.zip
  inflating: cvs.html
  inflating: cvs.exe
  inflating: README
  inflating: FAQ
  inflating: NEWS
  inflating: patch.exe
  inflating: win32gnu.dll
@end example

The README there contains detailed instructions.  For most
installations, they can be summarized as follows: Put all of the EXE and
DLL files in a directory in your PATH.  Additionally, if you're going to
be using the pserver method to access a remote repository, you may need
to put the following in your @file{C:\AUTOEXEC.BAT} file and reboot:

@example
set HOME=C: 
@end example

This tells CVS where to store the .cvspass file.

CVS running under Windows cannot currently serve repositories to remote
machines; it can be a client (connecting to remote repositories), and
operate in local mode (using a repository on the same machine).  For the
most part, this book assumes that CVS under Windows is operating as a
client.  However, it shouldn't be too hard to set up a local repository
under Windows after reading the Unix-oriented instructions in the rest
of this chapter.

If you are only accessing remote repositories, you may not even need to
run CVS.  There is a tool called WinCvs that implements only the
client-side portion of CVS.  It is distributed separately from CVS
itself but, like CVS, is freely available under the GNU General Public
License.  More information is available from @uref{http://www.wincvs.org}.

@c -------------------------
@node Getting And Installing CVS On A Macintosh
@subsection Getting And Installing CVS On A Macintosh

CVS is available for the Macintosh, but not as part of the main
distribution.  At the moment, there are actually three separate
Macintosh CVS clients available:

@itemize
@item MacCvs -- @uref{http://www.wincvs.org}
@item MacCVSClient -- @uref{http://www.glink.net.hk/~jb/MacCVSClient}
      or @uref{http://www.cyclic.com/maccvsclient/}
@item MacCVS Pro -- @uref{http://www.maccvs.org}
@end itemize

Frankly, I have no idea which one is best.  Try them all, not
necessarily in the order given, and see which one you like.  MacCVS Pro
seems to be under active development.  MacCvs is apparently a companion
project of WinCVS and shares a home page with it. (As of this writing, a
notice on the WinCVS page states, "Development of MacCvs will be resumed
soon.", whatever that means.)

@c -------------------------------------------------------------
@node Limitations Of The Windows And Macintosh Versions
@subsection Limitations Of The Windows And Macintosh Versions

The Windows and Macintosh distributions of CVS are generally limited in
functionality.  They can all act as clients, meaning that they can
contact a repository server to obtain a working copy, commit, update,
and so on.  But they can't serve repositories themselves.  If you set it
up right, the Windows port can use a local-disk repository, but it still
can't serve projects from that repository to other machines.  In
general, if you want to have a network-accessible CVS repository, you
must run the CVS server on a Unix box.

@c -----------------------------------------------------
@node Anatomy Of A CVS Distribution
@section Anatomy Of A CVS Distribution

The preceding instructions are designed to get you up and running
quickly, but there's a lot more inside a CVS source distribution than
just the code.  Here's a quick road map to the source tree, so you'll
know which parts are useful resources and which can be ignored.

@menu
* Informational Files::             NEWS, BUGS, FAQ, etc.
* Subdirectories::                  How the distribution is laid out.
* The Cederqvist Manual::           The CVS Online Manual.
* Other Sources Of Information::    Where else to find help.
@end menu

@c ---------------------------------------------------
@node Informational Files
@subsection Informational Files

In the top level of the distribution tree, you'll find several files
containing useful information (and pointers to further information).
They are, in approximate order of importance:

@itemize

@item
@file{NEWS} -- This file lists the changes from one release to the next,
in reverse chronological order (that is, most recent first).  If you've
already been using CVS for a while and have just upgraded to a new
version, you should look at the NEWS file to see what new features are
available.  Also, although most changes to CVS preserve backward
compatibility, noncompatible changes do occur from time to time.  It's
better to read about them here than be surprised when CVS doesn't behave
the way you expect it to.

@item
@file{BUGS} -- This file contains exactly what you think it does: a list
of known bugs in CVS.  They usually aren't show-stoppers, but you should
read over them whenever you install a new release.

@item
@file{DEVEL-CVS} -- This file is the CVS "constitution".  It describes
the process by which changes are accepted into the main CVS distribution
and the procedures through which a person becomes a CVS developer.  You
don't really need to read it if you just want to use CVS; however, it's
highly interesting if you want to understand how the mostly
uncoordinated efforts of people scattered across the globe coalesce into
a working, usable piece of software.  And of course, it's required
reading if you plan to submit a patch (be it a bug fix or new feature)
to CVS.

@item
@file{HACKING} -- Despite its name, the HACKING file doesn't say much
about the design or implementation of CVS.  It's mainly a guide to
coding standards and other technical administrivia for people thinking
of writing a patch to CVS.  It can be thought of as an addendum to the
DEVEL-CVS file.  After you understand the basic philosophy of CVS
development, you must read the HACKING file to translate that into
concrete coding practices.

@item
@file{FAQ} -- This is the CVS "Frequently Asked Questions" document.
Unfortunately it has a rather spotty maintenance history.  David Grubbs
took care of it until 1995, then he (presumably) got too busy and it
languished for a while.  Eventually, in 1997, Pascal Molli took over
maintenance.  Molli also didn't have time to maintain it by hand, but at
least he found time to put it into his automated FAQ-O-Matic system,
which allows the public to maintain the FAQ in a decentralized manner
(basically, anyone can edit or add entries via a Web form).  This was
probably a good thing, in that at least the FAQ was once again being
maintained; however, its overall organization and quality control are
not on the same level as if a person were maintaining it.

The master version of the FAQ is always available from Molli's Web site
(@uref{http://www.loria.fr/~molli/cvs-index.html}, under the link
"Documentation").  The FAQ file shipped with CVS distributions is
generated automatically from that FAQ-O-Matic database, so by the time
it reaches the public it's already a little bit out of date.
Nevertheless, it can be quite helpful when you're looking for hints and
examples about how to do something specific (say, merging a large branch
back into the trunk or resurrecting a removed file).  The best way to
use it is as a reference document; you can bring it up in your favorite
editor and do text searches on terms that interest you.  Trying to use
it as a tutorial would be a mistake -- it's missing too many important
facts about CVS to serve as a complete guide.

@end itemize

@c -------------------------
@node Subdirectories
@subsection Subdirectories

The CVS distribution contains a number of subdirectories.  In the course
of a normal installation, you won't have to navigate among them, but if
you want to go poking around in the sources, it's nice to know what each
one does.  Here they are:

@example
contrib/
diff/
doc/
emx/
lib/
man/
os2/
src/
tools/
vms/
windows-NT/
zlib/
@end example

The majority of these can be ignored.  The emx/, os2/, vms/, and
windows-NT/ subdirectories all contain operating-system-specific source
code, which you would only need if you're actually trying to debug a
code-level problem in CVS (an unlikely situation, though not unheard
of).  The diff/ and zlib/ subdirectories contain CVS's internal
implementations of the diff program and the GNU gzip compression
library, respectively. (CVS uses the latter to reduce the number of bits
it has to send over the network when accessing remote repositories.)

The contrib/ and tools/ subdirectories contain free third-party software
meant to be used with CVS.  In contrib/, you will find an assortment of
small, specialized shell scripts (read contrib/README to find out what
they do).  The tools/ subdirectory used to contain contributed software,
but now contains a README file, which says in part:

@example
This subdirectory formerly contained tools that can be used with CVS.
In particular, it used to contain a copy of pcl-cvs version 1.x.
Pcl-cvs is an Emacs interface to CVS.

If you are looking for pcl-cvs, we'd suggest pcl-cvs version 2.x, at: 
    ftp://ftp.weird.com/pub/local/
@end example

The PCL-CVS package it's referring to is very handy, and I'll have more
to say about it in @ref{Third-Party Tools}.

The src/ and lib/ subdirectories contain the bulk of the CVS source
code, which involves the CVS internals.  The main data structures and
commands are implemented in src/, whereas lib/ contains small code
modules of general utility that CVS uses.

The man/ subdirectory contains the CVS man pages (intended for the Unix
online manual system).  When you ran make install, they were
incorporated into your Unix system's regular man pages, so you can type

@example
floss$ man cvs
@end example

and get a rather terse introduction and subcommand reference to CVS.
Although useful as a quick reference, the man pages may not be as up to
date or complete as the Cederqvist manual (see the next section);
however, the man pages are more likely to be incomplete than actually
wrong, if it's any comfort.

@c -------------------------
@node The Cederqvist Manual
@subsection The Cederqvist Manual

That leaves the doc/ subdirectory, whose most important inhabitant is
the famed @dfn{Cederqvist}.  These days, it's probably a stretch to call
it "the Cederqvist".  Although Per Cederqvist (of Signum Support,
Linkoping Sweden, www.signum.se) wrote the first version around 1992, it
has been updated since then by many other people.  For example, when
contributors add a new feature to CVS, they usually also document it in
the Cederqvist.

The Cederqvist manual is written in Texinfo format, which is used by the
GNU project because it's relatively easy to produce both online and
printed output from it (in Info and PostScript formats, respectively).
The Texinfo master file is doc/cvs.texinfo, but CVS distributions come
with the Info and PostScript pregenerated, so you don't have to worry
about running any Texinfo tools yourself.

Although the Cederqvist can be used as an introduction and tutorial, it
is probably most useful as a reference document.  For that reason, most
people browse it online instead of printing it out (although the
PostScript file is @file{doc/cvs.ps}, for those with paper to spare).
If this is the first time you've installed CVS on your system, you'll
have to take an extra step to make sure the manual is accessible online.

The Info files (doc/cvs.info, doc/cvs.info-1, doc/cvs.info-2, and so on)
were installed for you when you ran make install.  Although the files
were copied into the system's Info tree, you may still have to add a
line for CVS to the Info table of contents, the "Top" node. (This will
only be necessary if this is the first time CVS has been installed on
your system; otherwise, the entry from previous installations should
already be in the table of contents.)

If you've added new Info documentation before, you may be familiar with
the process.  First figure out where the Info pages were installed.  If
you used the default installation (in /usr/local/), then the Info files
are /usr/local/info/cvs.info*.  If you installed using

@example
floss$ ./configure --prefix=/usr
@end example

the files ended up as /usr/info/cvs.*.  After you locate the files,
you'll need to add a line for CVS to the Info table of contents, which
is in a file named dir in that directory (so in the latter case, it
would be /usr/info/dir).  If you don't have root access, ask your system
administrator to do it.  Here is an excerpt from dir before the
reference to CVS documentation was added:

@example
* Bison: (bison).         The Bison parser generator. 
* Cpp: (cpp).             The GNU C preprocessor. 
* Flex: (flex).           A fast scanner generator
@end example

And here is the same region of dir afterwards: 

@example
* Bison: (bison).         The Bison parser generator. 
* Cpp: (cpp).             The GNU C preprocessor. 
* Cvs: (cvs).             Concurrent Versions System
* Flex: (flex).           A fast scanner generator
@end example

The format of the line is very important.  You must include the
asterisk, spaces, and colon in @w{@samp{* Cvs:}} and the parentheses and
period in @samp{(cvs).} after it.  If any of these elements are missing,
the Info dir format will be corrupt, and you'll be unable to read the
Cederqvist.

Once the manual is installed and referred to from the table of contents,
you can read it with any Info-compatible browser.  The ones most likely
to be installed on a typical Unix system are either the command-line
Info reader, which can be invoked this way if you want to go straight to
the CVS pages

@example
floss$ info cvs
@end example

and the one within Emacs, which is invoked by typing

@example
M-x info 
@end example

or 

@example
C-h i
@end example

Take whatever time is necessary to get the Cederqvist set up properly on
your system when you install CVS; it will pay off many times down the
road when you need to look something up.

@c -------------------------
@node Other Sources Of Information
@subsection Other Sources Of Information

In addition to the Cederqvist, the FAQ, and the other files in the
distribution itself, there are Internet resources devoted to CVS.  If
you're going to administrate a CVS server, you'll probably want to join
the info-cvs mailing list.  To subscribe, send email to
@email{info-cvs-request@@gnu.org} (the list itself is
@email{info-cvs@@gnu.org}).  Traffic can be medium to heavy, around 10
to 20 emails a day, most of them questions seeking answers.  The
majority of these can be deleted without reading (unless you want to
help people by answering their questions, which is always nice), but
every now and then someone will announce the discovery of a bug or
announce a patch that implements some feature you've been wanting.

You can also join the formal bug report mailing list, which includes
every bug report sent in.  This probably isn't necessary, unless you
intend to help fix the bugs, which would be great, or you're
terrifically paranoid and want to know about every problem other people
find with CVS.  If you do want to join, send email to
@email{bug-cvs-request@@gnu.org}.

There's also a Usenet newsgroup, @code{comp.software.config-mgmt}, which
is about version control and configuration management systems in
general, in which there is a fair amount of discussion about CVS.

Finally, there are at least three Web sites devoted to CVS.  Cyclic
Software's @uref{http://www.cyclic.com} has been CVS's informal home
site for a few years, and probably will continue to be for the
foreseeable future.  Cyclic Software also provides server space and Net
access for the repository where the CVS sources are kept.  The Cyclic
Web pages contain comprehensive links to experimental patches for CVS,
third-party tools that work with CVS, documentation, mailing list
archives, and just about everything else.  If you can't find what you
need in the distribution, @uref{http://www.cyclic.com} is the place to
start looking.

Two other good sites are Pascal Molli's
@uref{http://www.loria.fr/~molli/cvs-index.html} and Sean Dreilinger's
@uref{http://durak.org/cvswebsites/}.  The biggest attraction at Molli's
site is, of course, the FAQ, but it also has links to CVS-related tools
and mailing list archives.  Dreilinger's site specializes in information
about using CVS to manage Web documents and also has a CVS-specific
search engine.

@c -----------------------------------------------------
@node Starting A Repository
@section Starting A Repository

Once the CVS executable is installed on your system, you can start using
it right away as a client to access remote repositories, following the
procedures described in @ref{An Overview of CVS}.  However, if you want
to serve revisions from your machine, you have to create a repository
there.  The command to do that is

@example
floss$ cvs -d /usr/local/newrepos init
@end example

where @file{/usr/local/newrepos} is a path to wherever you want the
repository to be (of course, you must have write permission to that
location, which may imply running the command as the root user).  It may
seem somewhat counterintuitive that the location of the new repository
is specified before the init subcommand instead of after it, but by
using the -d option, it stays consistent with other CVS commands.

The command will return silently after it is run.  Let's examine the new
directory:

@example
floss$ ls -ld /usr/local/newrepos
drwxrwxr-x   3 root     root         1024 Jun 19 17:59 /usr/local/newrepos/
floss$ cd /usr/local/newrepos
floss$ ls
CVSROOT
floss$ cd CVSROOT
floss$ ls
checkoutlist     config,v        history     notify     taginfo,v
checkoutlist,v   cvswrappers     loginfo     notify,v   verifymsg
commitinfo       cvswrappers,v   loginfo,v   rcsinfo    verifymsg,v
commitinfo,v     editinfo        modules     rcsinfo,v
config           editinfo,v      modules,v   taginfo

floss$ 
@end example

The single subdirectory in the new repository -- CVSROOT/ -- contains
various administrative files that control CVS's behavior.  Later on,
we'll examine those files one by one; for now, the goal is just to get
the repository working.  In this case, "working" means users can import,
check out, update, and commit projects.

Don't confuse the CVSROOT environment variable introduced in @ref{An
Overview of CVS} with this CVSROOT subdirectory in the repository.  They
are unrelated -- it is an unfortunate coincidence that they share the
same name.  The former is a way for users to avoid having to type
@w{@samp{-d <repository-location>}} every time they use CVS; the latter
is the administrative subdirectory of a repository.

Once the repository is created, you must take care of its permissions.
CVS does not require any particular, standardized permission or file
ownership scheme; it merely needs write access to the repository.
However -- partly for security reasons, but mainly for your own sanity
as an administrator -- I highly recommend that you take the following
steps:

@enumerate

@item
Add a Unix group @code{cvs} to your system.  Any users who need to
access the repository should be in this group.  For example, here's the
relevant line from my machine's @file{/etc/group} file:

@example
cvs:*:105:kfogel,sussman,jimb,noel,lefty,fitz,craig,anonymous,jrandom
@end example

@item
Make the repository's group ownership and permissions reflect this new
group:

@example
floss$ cd /usr/local/newrepos
floss$ chgrp -R cvs .
floss$ chmod ug+rwx . CVSROOT
@end example

@end enumerate

Now any of the users listed in that group can start a project by running
@w{@code{cvs import}}, as described in @ref{An Overview of CVS}.
Checkout, update, and commit should work as well.  They can also reach
the repository from remote locations by using the @code{:ext:} method,
assuming that they have rsh or ssh access to the repository
machine. (You may have noticed that the chgrp and chmod commands in that
example gave write access to a user named @code{anonymous}, which is not
what one would expect.  The reason is that even anonymous, read-only
repository users need system-level write access, so that their CVS
processes can create temporary lockfiles inside the repository.  CVS
enforces the "read-only" restriction of anonymous access not through
Unix file permissions, but by other means, which will be covered in
@ref{Anonymous Access}.)

If your repository is intended to serve projects to the general public,
where contributors won't necessarily have accounts on the repository
machine, you should set up the password-authenticating server now
(@pxref{The Password-Authenticating Server}).  It's necessary for
anonymous read-only access, and it's also probably the easiest way to
grant commit access to certain people without giving them full accounts
on the machine.

@c -----------------------------------------------------
@node The Password-Authenticating Server
@section The Password-Authenticating Server

Before running through the steps needed to set up the password server,
let's examine how such connections work in the abstract.  When a remote
CVS client uses the @code{:pserver:} method to connect to a repository,
the client is actually contacting a specific port number on the server
machine -- specifically, port number 2401 (which is 49 squared, if you
like that sort of thing).  Port 2401 is the designated default port for
the CVS pserver, although one could arrange for a different port to be
used as long as both client and server agree on it.

The CVS server is not actually waiting for connections at that port --
the server won't get started up until a connection actually arrives.
Instead, the Unix inetd (InterNET Daemon) program is listening on that
port, and needs to know that when it receives a connection request
there, it should start up the CVS server and connect it to the incoming
client.

This is accomplished by modifying inetd's configuration files:
@file{/etc/services} and @file{/etc/inetd.conf}.  The services file maps
raw port numbers to service names and then inetd.conf tells inetd what
to do for a given service name.

First, put a line like this into /etc/services (after checking to make
sure it isn't already there):

@example
cvspserver	2401/tcp
@end example

Then in /etc/inetd.conf, put this:

@example
cvspserver stream tcp nowait root /usr/local/bin/cvs cvs \
   --allow-root=/usr/local/newrepos pserver
@end example

(In the actual file, this should be all one long line, with no
backslash.)  If your system uses tcpwrappers, you may want to use
something like this instead:

@example
cvspserver stream tcp nowait root /usr/sbin/tcpd /usr/local/bin/cvs \
   --allow-root=/usr/local/newrepos pserver
@end example

Now, restart inetd so it notices the changes to its configuration files
(if you don't know how to restart the daemon, just reboot the machine --
that will work too).

That's enough to permit connections, but you'll also want to set up
special CVS passwords -- separate from the users' regular login
passwords -- so people can access the repository without compromising
overall system security.

The CVS password file is CVSROOT/passwd in the repository.  It was not
created by default when you ran cvs init, because CVS doesn't know for
sure that you'll be using pserver.  Even if the password file had been
created, CVS would have no way of knowing what usernames and passwords
to create.  So, you'll have to create one yourself; here's a sample
CVSRoot/passwd file:

@example
kfogel:rKa5jzULzmhOo
anonymous:XR4EZcEs0szik
melissa:tGX1fS8sun6rY:pubcvs
@end example

The format is as simple as it looks.  Each line is:

@c todo: get rid of angle brackets here?
@example
<USERNAME>:<ENCRYPTED_PASSWORD>:<OPTIONAL_SYSTEM_USERNAME>
@end example

The extra colon followed by an optional system username tells CVS that
connections authenticated with USERNAME should run as the system account
SYSTEM_USERNAME -- in other words, that CVS session would only be able
to do things in the repository that someone logged in as SYSTEM_USERNAME
could do.

If no system username is given, USERNAME must match an actual login
account name on the system, and the session will run with that user's
permissions.  In either case, the encrypted password should not be the
same as the user's actual login password.  It should be an independent
password used only for CVS pserver connections.

The password is encrypted using the same algorithm as the standard Unix
system passwords stored in /etc/passwd.  You may be wondering at this
point, how does one acquire an encrypted version of a password?  For
Unix system passwords, the passwd command takes care of the encryption
in /etc/passwd for you.  Unfortunately, there is no corresponding cvs
passwd command (it has been proposed several times, but no one's gotten
around to writing it -- perhaps you'll do it?).

This is an inconvenience, but only a slight one.  If nothing else, you
can always temporarily change a regular user's system password using
passwd, cut and paste the encrypted text from /etc/passwd into
CVSROOT/passwd, and then restore the old password (note that on some
systems, the encrypted passwords are found in /etc/shadow and are
readable only by root.)

That scheme is workable but rather cumbersome.  It would be much easier
to have a command-line utility that takes a plain text password as its
argument and outputs the encrypted version.  Here is such a tool,
written in Perl:

@example
#!/usr/bin/perl

srand (time());
my $randletter = "(int (rand (26)) + (int (rand (1) + .5) % 2 ? 65 : 97))";
my $salt = sprintf ("%c%c", eval $randletter, eval $randletter); 
my $plaintext = shift; 
my $crypttext = crypt ($plaintext, $salt); 

print "$@{crypttext@}\n";
@end example

I keep the preceding script in @file{/usr/local/bin/cryptout.pl}:

@example
floss$ ls -l /usr/local/bin/cryptout.pl 

-rwxr-xr-x   1   root   root   265  Jun 14 20:41 /usr/local/bin/cryptout.pl
floss$ cryptout.pl "some text"
sB3A79YDX5L4s

floss$ 
@end example

If I took the output of this example and used it to create the following
entry in CVSROOT/passwd

@example
jrandom:sB3A79YDX5L4s:craig
@end example

then someone could connect to the repository with the following command:

@example
remote$ cvs -d :pserver:jrandom@@floss.red-bean.com:/usr/local/newrepos login
@end example

They could then type @code{some text} as their password and thereafter
be able to execute CVS commands with the same access privileges as the
system user @code{craig}.

If someone attempts to authenticate with a username and password that
don't appear in CVSROOT/passwd, CVS will check to see if that username
and password are present in /etc/passwd.  If they are (and if the
password matches, of course), CVS will grant access.  It behaves this
way for the administrator's convenience, so that separate CVSROOT/passwd
entries don't have to be set up for regular system users.  However, this
behavior is also a security hole, because it means that if one of those
users does connect to the CVS server, her regular login password will
have crossed over the network in cleartext, potentially vulnerable to
the eyes of password sniffers.  A bit further on, you'll learn how to
turn off this "fallback" behavior, so that CVS consults only its own
passwd file.  Whether you leave it on or off, you should probably force
any CVS users who also have login accounts to maintain different
passwords for the two functions.

Although the passwd file authenticates for the whole repository, with a
little extra work you can still use it to grant project-specific access.
Here's one method:

Suppose you want to grant some remote developers access to project
@code{foo}, and others access to project @code{bar}, and you don't want
developers from one project to have commit access to the other.  You can
accomplish this by creating project-specific user accounts and groups on
the system and then mapping to those accounts in the CVSROOT/passwd
file.

Here's the relevant excerpt from /etc/passwd

@example
cvs-foo:*:600:600:Public CVS Account for Project Foo:/usr/local/cvs:/bin/false
cvs-bar:*:601:601:Public CVS Account for Project Bar:/usr/local/cvs:/bin/false
@end example

and from /etc/group

@example
cvs-foo:*:600:cvs-foo
cvs-bar:*:601:cvs-bar
@end example

and, finally, CVSROOT/passwd:

@example
kcunderh:rKa5jzULzmhOo:cvs-foo
jmankoff:tGX1fS8sun6rY:cvs-foo
brebard:cAXVPNZN6uFH2:cvs-foo
xwang:qp5lsf7nzRzfs:cvs-foo
dstone:JDNNF6HeX/yLw:cvs-bar
twp:glUHEM8KhcbO6:cvs-bar
ffranklin:cG6/6yXbS9BHI:cvs-bar
yyang:YoEqcCeCUq1vQ:cvs-bar
@end example

Some of the CVS usernames map onto the system user account
@code{cvs-foo} and some onto @code{cvs-bar}.  Because CVS runs under the
user ID of the system account, you just have to make sure that the
relevant parts of the repository are writeable only by the appropriate
users and groups.  If you just make sure that the user accounts are
locked down pretty tight (no valid login password, @file{/bin/false} as
the shell), then this system is reasonably secure (but see later in this
chapter about CVSROOT permissions!).  Also, CVS does record changes and
log messages under the CVS username, not the system username, so you can
still tell who is responsible for a given change.


@c -----------------------------------------------------
@node Anonymous Access
@section Anonymous Access

So far we've only seen how to use the password-authenticating server to
grant normal full access to the repository (although admittedly one can
restrict that access through carefully arranged Unix file permissions).
Turning this into anonymous, read-only access is a simple step: You just
have to add a new file, or possibly two, in CVSROOT/.  The files' names
are @code{readers} and @code{writers} -- the former containing a list of
usernames who can only read the repository, the latter users who can
read and write.

If you list a username in CVSROOT/readers, that user will have only read
access to all projects in the repository.  If you list a username in
CVSROOT/writers, that user will have write access, and every pserver
user not listed in writers will have read-only access (that is, if the
writers file exists at all, it implies read-only access for all those
not listed in it).  If the same username is listed in both files, CVS
resolves the conflict in the more conservative way: the user will have
read-only access.

The format of the files is very simple: one user per line (don't forget
to put a newline after the last user).  Here is a sample readers file:

@example
anonymous
splotnik
guest
jbrowse
@end example

Note that the files apply to CVS usernames, not system usernames.  If
you use user aliasing in the CVSROOT/passwd file (putting a system
username after a second colon), the leftmost username is the one to list
in a readers or writers file.

Just to be painfully accurate about it, here is a formal description of
the server's behavior in deciding whether to grant read-only or
read-write access:

If a readers file exists and this user is listed in it, then she gets
read-only access.  If a writers file exists and this user is not listed
in it, then she also gets read-only access (this is true even if a
readers file exists but that person is not listed there).  If that
person is listed in both, she gets read-only access.  In all other
cases, that person gets full read-write access.

Thus, a typical repository with anonymous CVS access has this (or
something like it) in CVSROOT/passwd

@example
anonymous:XR4EZcEs0szik
@end example

this (or something like it) in /etc/passwd

@example
anonymous:!:1729:105:Anonymous CVS User:/usr/local/newrepos:/bin/false
@end example

and this in CVSROOT/readers:

@example
anonymous
@end example

And, of course, the aforementioned setup in /etc/services and
/etc/inetd.conf.  That's all there is to it!

Note that some older Unix systems don't support usernames longer than
eight characters.  One way to get around this would be to call the user
@code{anon} instead of @code{anonymous} in CVSROOT/passwd and in the
system files, because people often assume that anon is short for
anonymous anyway.  But it might be better to put something like this
into the CVSROOT/passwd file

@example
anonymous:XR4EZcEs0szik:cvsanon
@end example

(and then of course use @code{cvsanon} in the system files).  That way,
you'd be able to publish a repository address that uses
@code{anonymous}, which is more or less standard now.  People accessing
the repository with

@example
cvs -d :pserver:anonymous@@cvs.foobar.com:/usr/local/newrepos (etc...)
@end example

would actually run on the server as cvsanon (or whatever).  But they
wouldn't need to know or care about how things are set up on the server
side -- they'd only see the published address.

@c -----------------------------------------------------
@node Repository Structure
@section Repository Structure

The new repository still has no projects in it.  Let's re-run the
initial import from @ref{An Overview of CVS}, watching what happens to
the repository. (For simplicity's sake, all commands will assume that
the CVSROOT environment variable has been set to /usr/local/newrepos, so
there's no need to specify the repository with -d on imports and
checkouts.)

@example
floss$ ls /usr/local/newrepos
CVSROOT/
floss$ pwd
/home/jrandom/src/
floss$ ls
myproj/
floss$ cd myproj
floss$ cvs import -m "initial import into CVS" myproj jrandom start
N myproj/README.txt
N myproj/hello.c
cvs import: Importing /usr/local/newrepos/myproj/a-subdir
N myproj/a-subdir/whatever.c
cvs import: Importing /usr/local/newrepos/myproj/a-subdir/subsubdir
N myproj/a-subdir/subsubdir/fish.c
cvs import: Importing /usr/local/newrepos/myproj/b-subdir
N myproj/b-subdir/random.c

No conflicts created by this import

floss$ ls /usr/local/newrepos
CVSROOT/  myproj/
floss$ cd /usr/local/newrepos/myproj
floss$ ls
README.txt,v  a-subdir/     b-subdir/	  hello.c,v
floss$ cd a-subdir
floss$ ls
subsubdir/    whatever.c,v
floss$ cd .. 

floss$ 
@end example

Before the import, the repository contained only its administrative
area, CVSROOT.  After the import, a new directory -- @file{myproj} --
appeared.  The files and subdirectories inside that new directory look
suspiciously like the project we imported, except that the files have
the suffix @code{,v}.  These are RCS-format version control files (the
@code{,v} stands for "version"), and they are the backbone of the
repository.  Each RCS file stores the revision history of its
corresponding file in the project, including all branches and tags.

@c -----------------------------------------------------
@node RCS Format
@section RCS Format

You do not need to know any of the RCS format to use CVS (although there
is an excellent writeup included with the source distribution, see
doc/RCSFILES).  However, a basic understanding of the format can be of
immense help in troubleshooting CVS problems, so we'll take a brief peek
into one of the files, @file{hello.c,v}.  Here are its contents:

@example
head     1.1; 
branch   1.1.1; 
access   ; 
symbols  start:1.1.1.1 jrandom:1.1.1; 
locks    ; strict; 
comment  @@ * @@;

1.1
date     99.06.20.17.47.26;  author jrandom;  state Exp; 
branches 1.1.1.1; 
next; 

1.1.1.1
date     99.06.20.17.47.26;  author jrandom;  state Exp; 
branches ; 
next; 

desc
@@@@

1.1
log
@@Initial revision
@@
text
@@#include <stdio.h>

void
main ()
@{
  printf ("Hello, world!\n");
@}
@@

1.1.1.1
log
@@initial import into CVS
@@
text
@@@@
@end example

Whew!  Most of that you can ignore; don't worry about the relationship
between 1.1 and 1.1.1.1, for example, or the implied 1.1.1 branch --
they aren't really significant from a user's or even an administrator's
point of view.  What you should try to grok is the overall format.  At
the top is a collection of header fields:

@example
head     1.1; 
branch   1.1.1; 
access   ; 
symbols  start:1.1.1.1 jrandom:1.1.1; 
locks    ; strict; 
comment  @@ * @@;
@end example

Farther down in the file are groups of meta-information about each
revision (but still not showing the contents of that revision), such as:

@example
1.1
date     99.06.20.17.47.26;  author jrandom;  state Exp; 
branches 1.1.1.1; 
next     ; 
@end example

And finally, the log message and text of an actual revision:

@example
1.1
log
@@Initial revision
@@
text
@@#include <stdio.h>

void
main ()
@{
  printf ("Hello, world!\n");
@}
@@

1.1.1.1
log
@@initial import into CVS
@@
text
@@@@
@end example

If you look closely, you'll see that the first revision's contents are
stored under the heading 1.1, but that the log message there is "Initial
revision", whereas the log message we actually used at import time was
"initial import into CVS", which appears farther down, under
@code{Revision 1.1.1.1}.  You don't need to worry about this discrepancy
right now.  It happens because imports are a special circumstance: In
order to make repeated imports into the same project have a useful
effect, import actually places the initial revision on both the main
trunk and on a special branch (the reasons for this will become clearer
when we look at vendor branches in @ref{Advanced CVS}).  For now, you
can treat @code{1.1} and @code{1.1.1.1} as the same thing.

The file becomes even more revealing after we commit the first
modification to hello.c:

@example
floss$ cvs -Q co myproj
floss$ cd myproj
floss$ emacs hello.c
    (make some changes to the file) 

floss$ cvs ci -m "print goodbye too"
cvs commit: Examining . 
cvs commit: Examining a-subdir
cvs commit: Examining a-subdir/subsubdir
cvs commit: Examining b-subdir
Checking in hello.c; 
/usr/local/newrepos/myproj/hello.c,v  <--  hello.c
new revision: 1.2; previous revision: 1.1
done
@end example

If you look at hello.c,v in the repository now, you can see the effect
of the commit:

@example
head  1.2; 
access; 
symbols
      start:1.1.1.1 jrandom:1.1.1; 
locks; strict; 
comment   @@ * @@;

1.2
date   99.06.21.01.49.40;   author jrandom;   state Exp; 
branches; 
next   1.1; 

1.1
date   99.06.20.17.47.26;   author jrandom;   state Exp; 
branches
       1.1.1.1; 
next   ; 

1.1.1.1
date   99.06.20.17.47.26;   author jrandom;   state Exp; 
branches; 
next   ; 

desc
@@@@

1.2
log
@@print goodbye too
@@
text
@@#include <stdio.h>

void
main ()
@{
  printf ("Hello, world!\n");
  printf ("Goodbye, world!\n");
@}
@@

1.1
log
@@Initial revision
@@
text
@@d7 1
@@

1.1.1.1
log
@@initial import into CVS
@@
text
@@@@
@end example

Now the full contents of Revision 1.2 are stored in the file, and the
text for Revision 1.1 has been replaced with the cryptic formula:

@example
d7 1
@end example

The @w{@code{d7 1}} is a diff code that means "starting at line 7,
delete 1 line".  In other words, to derive Revision 1.1, delete line 7
from Revision 1.2!  Try working through it yourself.  You'll see that it
does indeed produce Revision 1.1 -- it simply does away with the line we
added to the file.

This demonstrates the basic principle of RCS format: It stores only the
differences between revisions, thereby saving a lot of space compared
with storing each revision in full.  To go backwards from the most
recent revision to the previous one, it patches the later revision using
the stored diff.  Of course, this means that the further back you travel
in the revision history, the more patch operations must be performed
(for example, if the file is on Revision 1.7 and CVS is asked to
retrieve Revision 1.4, it has to produce 1.6 by patching backwards from
1.7, then 1.5 by patching 1.6, then 1.4 by patching 1.5).  Fortunately,
old revisions are also the ones least often retrieved, so the RCS system
works out pretty well in practice: The more recent the revision, the
cheaper it is to obtain.

As for the header information at the top of the file, you don't need to
know what all of it means.  However, the effects of certain operations
show up very clearly in the headers, and a passing familiarity with them
may prove useful.

When you commit a new revision on the trunk, the @code{head} label is
updated (note how it became 1.2 in the preceding example, when the
second revision to hello.c was committed).  When you add a file as
binary or tag it, those operations are recorded in the headers as well.
As an example, we'll add foo.jpg as a binary file and then tag it a
couple of times:

@example
floss$ cvs add -kb foo.jpg
cvs add: scheduling file 'foo.jpg' for addition
cvs add: use 'cvs commit' to add this file permanently
floss$ cvs -q commit -m "added a random image; ask jrandom@@red-bean.com why"
RCS file: /usr/local/newrepos/myproj/foo.jpg,v
done
Checking in foo.jpg; 
/usr/local/newrepos/myproj/foo.jpg,v  <--  foo.jpg
initial revision: 1.1
done
floss$ cvs tag some_random_tag foo.jpg
T foo.jpg
floss$ cvs tag ANOTHER-TAG foo.jpg
T foo.jpg
floss$ 
@end example

Now examine the header section of foo.jpg,v in the repository:

@example
head   1.1; 
access; 
symbols
      ANOTHER-TAG:1.1
      some_random_tag:1.1; 
locks; strict; 
comment   @@# @@;
expand	@@b@@;
@end example

Notice the b in the expand line at the end -- it's due to our having
used the -kb flag when adding the file, and means the file won't undergo
any keyword or newline expansions, which would normally occur during
checkouts and updates if it were a regular text file.  The tags appear
in the symbols section, one tag per line -- both of them are attached to
the first revision, since that's what was tagged both times. (This also
helps explain why tag names can only contain letters, numbers, hyphens,
and underscores.  If the tag itself contained colons or dots, the RCS
file's record of it might be ambiguous, because there would be no way to
find the textual boundary between the tag and the revision to which it
is attached.)

@c -----------------------------------------------------
@heading RCS Format Always Quotes @@ Signs

The @code{@@} symbol is used as a field delimiter in RCS files, which
means that if one appears in the text of a file or in a log message, it
must be quoted (otherwise, CVS would incorrectly interpret it as marking
the end of that field).  It is quoted by doubling -- that is, CVS always
interprets @code{@@@@} as "literal @@ sign", never as "end of current
field".  When we committed foo.jpg, the log message was

@example
"added a random image; ask jrandom@@red-bean.com why"
@end example

which is stored in foo.jpg,v like this:

@example
1.1
log
@@added a random image; ask jrandom@@@@red-bean.com why
@@
@end example

The @@ sign in jrandom@@@@red-bean.com will be automatically unquoted
whenever CVS retrieves the log message:

@example
floss$ cvs log foo.jpg
RCS file: /usr/local/newrepos/myproj/foo.jpg,v
Working file: foo.jpg
head: 1.1
branch: 
locks: strict
access list: 
symbolic names: 
      ANOTHER-TAG: 1.1
      some_random_tag: 1.1
keyword substitution: b
total revisions: 1;	selected revisions: 1
description: 
----------------------------
revision 1.1
date: 1999/06/21 02:56:18;  author: jrandom;  state: Exp; 
added a random image; ask jrandom@@red-bean.com why
============================================================================

floss$ 
@end example

The only reason you should care is that if you ever find yourself
hand-editing RCS files (a rare circumstance, but not unheard of), you
must remember to use double @@ signs in revision contents and log
messages.  If you don't, the RCS file will be corrupt and will probably
exhibit strange and undesirable behaviors.

Speaking of hand-editing RCS files, don't be fooled by the permissions
in the repository:

@example
floss$ ls -l
total 6
-r--r--r--   1 jrandom   users         410 Jun 20 12:47 README.txt,v
drwxrwxr-x   3 jrandom   users        1024 Jun 20 21:56 a-subdir/
drwxrwxr-x   2 jrandom   users        1024 Jun 20 21:56 b-subdir/
-r--r--r--   1 jrandom   users         937 Jun 20 21:56 foo.jpg,v
-r--r--r--   1 jrandom   users         564 Jun 20 21:11 hello.c,v

floss$ 
@end example

(For those not fluent in Unix ls output, the @code{-r--r--r--} lines on
the left essentially mean that the files can be read but not changed.)
Although the files appear to be read-only for everyone, the directory
permissions must also be taken into account:

@example
floss$ ls -ld . 
drwxrwxr-x   4 jrandom   users        1024 Jun 20 22:16 ./ 
floss$
@end example

The myproj/ directory itself -- and its subdirectories -- are all
writeable by the owner (jrandom) and the group (users).  This means that
CVS (running as jrandom, or as anyone in the users group) can create and
delete files in those directories, even if it can't directly edit files
already present.  CVS edits an RCS file by making a separate copy of it,
so you should also make all of your changes in a temporary copy, and
then replace the existing RCS file with the new one. (But please don't
ask why the files themselves are read-only -- there are historical
reasons for that, having to do with the way RCS works when run as a
standalone program.)

Incidentally, having the files' group be @code{users} is probably not
what you want, considering that the top-level directory of the
repository was explicitly assigned group @code{cvs}.  You can correct
the problem by running this command inside the repository:

@example
floss$ cd /usr/local/newrepos
floss$ chgrp -R cvs myproj
@end example

The usual Unix file-creation rules govern which group is assigned to new
files that appear in the repository, so once in a while you may need to
run chgrp or chmod on certain files or directories in the repository
(setting the SGID bit with @w{@code{chmod g+s}} is often a good
strategy: it makes children of a directory inherit the directory's group
ownership, which is usually what you want in the repository).  There are
no hard and fast rules about how you should structure repository
permissions; it just depends on who is working on what projects.

@c -----------------------------------------------------
@node What Happens When You Remove A File
@section What Happens When You Remove A File

When you remove a file from a project, it doesn't just disappear.  CVS
must be able to retrieve such files when you request an old snapshot of
the project.  Instead, the file gets put in the @code{Attic}, literally:

@example
floss$ pwd
/home/jrandom/src/myproj
floss$ ls /usr/local/newrepos/myproj/
README.txt,v  a-subdir/     b-subdir/     foo.jpg,v   hello.c,v
floss$ rm foo.jpg
floss$ cvs rm foo.jpg
cvs remove: scheduling 'foo.jpg' for removal
cvs remove: use 'cvs commit' to remove this file permanently
floss$ cvs ci -m "Removed foo.jpg" foo.jpg
Removing foo.jpg; 
/usr/local/newrepos/myproj/foo.jpg,v  <--  foo.jpg
new revision: delete; previous revision: 1.1
done
floss$ cd /usr/local/newrepos/myproj/
floss$ ls
Attic/      README.txt,v  a-subdir/     b-subdir/   hello.c,v
floss$ cd Attic
floss$ ls
foo.jpg,v
floss$
@end example

In each repository directory of a project, the presence of an
@file{Attic/} subdirectory means that at least one file has been removed
from that directory (this means that you shouldn't use directories named
Attic in your projects).  CVS doesn't merely move the RCS file into
Attic/, however; it also commits a new revision into the file, with a
special revision state of @code{dead}.  Here's the relevant section from
Attic/foo.jpg,v:
 
@example
1.2
date   99.06.21.03.38.07;   author jrandom;   state dead; 
branches; 
next	1.1; 
@end example

If the file is later brought back to life, CVS has a way of recording
that it was dead at some point in the past and is now alive again.

This means that if you want to restore a removed file, you can't just
take it out of the Attic/ and put it back into the project.  Instead,
you have to do something like this in a working copy:

@example
floss$ pwd
/home/jrandom/src/myproj
floss$ cvs -Q update -p -r 1.1 foo.jpg > foo.jpg
floss$ ls
CVS/       README.txt   a-subdir/   b-subdir/   foo.jpg     hello.c
floss$ cvs add -kb foo.jpg
cvs add: re-adding file foo.jpg (in place of dead revision 1.2) 
cvs add: use 'cvs commit' to add this file permanently
floss$ cvs ci -m "revived jpg image" foo.jpg
Checking in foo.jpg; 
/usr/local/newrepos/myproj/foo.jpg,v  <-- foo.jpg
new revision: 1.3; previous revision: 1.2
done
floss$ cd /usr/local/newrepos/myproj/
floss$ ls
Attic/	      a-subdir/     foo.jpg,v
README.txt,v  b-subdir/     hello.c,v
floss$ ls Attic/
floss$ 
@end example

There's a lot more to know about RCS format, but this is sufficient for
a CVS adminstrator to maintain a repository.  It's quite rare to
actually edit an RCS file; you'll usually just have to tweak file
permissions in the repository, at least if my own experience is any
guide.  Nevertheless, when CVS starts behaving truly weirdly (rare, but
not completely outside the realm of possibility), you may want to
actually look inside the RCS files to figure out what's going on.

@c -----------------------------------------------------
@node The CVSROOT/ Administrative Directory
@section The CVSROOT/ Administrative Directory

The files in newrepos/CVSROOT/ are not part of any project, but are used
to control CVS's behavior in the repository.  The best way to edit those
files is to check out a working copy of CVSROOT, just like a regular
project:

@example
floss$ cvs co CVSROOT
cvs checkout: Updating CVSROOT
U CVSROOT/checkoutlist
U CVSROOT/commitinfo
U CVSROOT/config
U CVSROOT/cvswrappers
U CVSROOT/editinfo
U CVSROOT/loginfo
U CVSROOT/modules
U CVSROOT/notify
U CVSROOT/rcsinfo
U CVSROOT/taginfo
U CVSROOT/verifymsg
floss$ 
@end example

We'll take the files in their approximate order of importance.  Note
that each of the files comes with an explanatory comment at the
beginning (the comment convention is the same across all of them: A
@code{#} sign at the beginning of the line signifies a comment, and CVS
ignores such lines when parsing the files).  Remember that any change
you make to the administrative files in your checked out working copy
won't affect CVS's behavior until you commit the changes.

If you're extremely security conscious, you may want to arrange the
Unix-level permissions on CVSROOT to be different from permissions
elsewhere in the repository, in order to have fine-grained control over
who can commit changes to CVSROOT.  As you'll see a little later, being
able to modify the files in CVSROOT essentially gives any CVS user --
even remote ones -- the ability to run arbitrary commands on the
repository machine.

@menu
* The config File::
* The modules File::
* The commitinfo And loginfo And rcsinfo Files::
* The verifymsg And rcsinfo Files::
* The taginfo File::
* The cvswrappers File::
* The editinfo File::
* The notify File::
* The checkoutlist File::
@end menu

@c --------------------------------------
@node The config File
@subsection The config File
@cindex config file

The @dfn{config} file allows you to configure certain global behavioral
parameters.  It follows a very strict format

@example
PARAMETER=VALUE
(etc) 
@end example

with no extra spaces allowed.  For example, here is a possible config
file:

@example
SystemAuth=yes
TopLevelAdmin=no
PreservePermissions=no
@end example

(An absent entry would be equivalent to @code{no}.)

The @code{SystemAuth} parameter governs whether CVS should look in the
system passwd file if it fails to find a given username in the
CVSROOT/passwd file.  CVS distributions are shipped with this set to
@code{no} to be conservative about your system's security.

@code{TopLevelAdmin} tells CVS whether to make a sibling CVS/ directory
when it checks out a working copy.  This CVS/ directory would not be
inside the working copy, but rather next to it.  It might be convenient
to turn this on if you tend (and your repository's users tend) to check
out many different projects from the same repository.  Otherwise, you
should leave it off, as it can be disconcerting to see an extra CVS/
directory appear where you don't expect it.

@code{PreservePermissions} governs whether to preserve file permissions
and similar metadata in the revision history.  This is a somewhat
obscure feature that probably isn't worth describing in detail.  See the
node @cite{Special Files} in the Cederqvist if you're interested
(@dfn{node} is Texinfo-speak for a particular location within an Info
document.  To go to a node while reading Info, just type @kbd{g}
followed by the name of the node, from anywhere inside the document).

@code{LockDir} is also a rarely used feature.  In special circumstances,
you may want to tell CVS to create its lockfiles somewhere other than
directly in the project subdirectories, in order to avoid permission
problems.  These lockfiles keep CVS from tripping over itself when
multiple operations are performed on the same repository directory
simultaneously.  Generally, you never need to worry about them, but
sometimes users may have trouble updating or checking out from a
repository directory because they're unable to create a lockfile (even
on read-only operations, CVS needs to create a lockfile to avoid
situations where it could end up reading while another invocation of CVS
is writing).  The usual fix for this is to change repository
permissions, but when that's not feasible, the LockDir parameter can
come in handy.

There are no other parameters at this time, but future versions of CVS
may add new ones; you should always check the Cederqvist or the
distribution config file itself for updates.
@c todo: or the NEWS file!

@c ----------------------------
@node The modules File
@subsection The modules File
@cindex modules file

In modules, you can define aliases and alternate groupings for projects
in the repository.  The most basic module line is of the form:

@example
MODULE_NAME   DIRECTORY_IN_REPOSITORY
@end example

for example,

@example
mp    myproj
asub  myproj/a-subdir
@end example

(The paths given on the right are relative to the top of the
repository.)  This gives developers an alternate name by which to check
out a project or a portion of a project:

@example
floss$ cvs co mp
cvs checkout: Updating mp
U mp/README.txt
U mp/foo.jpg
U mp/hello.c
cvs checkout: Updating mp/a-subdir
U mp/a-subdir/whatever.c
cvs checkout: Updating mp/a-subdir/subsubdir
U mp/a-subdir/subsubdir/fish.c
cvs checkout: Updating mp/b-subdir
U mp/b-subdir/random.c
@end example

or

@example
floss$ cvs -d /usr/local/newrepos/ co asub
cvs checkout: Updating asub
U asub/whatever.c
cvs checkout: Updating asub/subsubdir
U asub/subsubdir/fish.c
@end example

Notice how in both cases the module's name became the name of the
directory created for the working copy.  In the case of asub, it didn't
even bother with the intermediate myproj/ directory, but created a
top-level asub/ instead, even though it came from myproj/a-subdir in the
repository.  Updates, commits, and all other CVS commands will behave
normally in those working copies -- the only thing unusual about them
are their names.

By putting file names after the directory name, you can define a module
consisting of just some of the files in a given repository directory.
For example

@example
readme  myproj  README.txt
@end example

and

@example
no-readme  myproj  hello.c  foo.jpg
@end example

would permit the following checkouts, respectively:

@example
floss$ cvs -q co readme
U readme/README.txt
floss$ cvs -q co no-readme
U no-readme/hello.c
U no-readme/foo.jpg
floss$
@end example

You can define a module that will include multiple repository
directories by using the -a (for @code{alias}) flag, but note that the
directories will get them checked out under their original names.  For
example, this line

@example
twoproj  -a  myproj  yourproj
@end example

would allow you to do this (assuming that both myproj/ and yourproj/ are
in the repository):

@example
floss$ cvs co twoproj
U myproj/README.txt
U myproj/foo.jpg
U myproj/hello.c
U myproj/a-subdir/whatever.c
U myproj/a-subdir/subsubdir/fish.c
U myproj/b-subdir/random.c
U yourproj/README
U yourproj/foo.c
U yourproj/some-subdir/file1.c
U yourproj/some-subdir/file2.c
U yourproj/some-subdir/another-subdir/blah.c
@end example

The name @code{twoproj} was a convenient handle to pull in both
projects, but it didn't affect the names of the working copies. (There
is no requirement that alias modules refer to multiple directories, by
the way; we could have omitted twoproj, in which case myproj would still
have been checked out under the name @code{myproj}.)

Modules can even refer to other modules, by prefixing them with an
ampersand:

@example
mp    myproj
asub  myproj/a-subdir
twoproj -a myproj yourproj
tp  &twoproj
@end example

Doing a checkout of @code{tp} would have exactly the same result as the
checkout of @code{twoproj} did.

There are a few other tricks you can do with modules, most of them less
frequently used than the ones just presented.  See the node modules in
the Cederqvist for information about them.

@c ----------------------------------------------------------
@node The commitinfo And loginfo And rcsinfo Files
@subsection The commitinfo And loginfo And rcsinfo Files

Most of the other administrative files provide programmatic @dfn{hooks}
into various parts of the commit process (for example, the ability to
validate log messages or file states before permitting the commit, or
the ability to notify a group of developers whenever a commit happens in
a certain directory of the repository).

The files generally share a common syntax.  Each line is of the form:

@example
REGULAR_EXPRESSION    PROGRAM_TO_RUN
@end example

The regular expression will be tested against the directory into which
the commit is taking place (with the directory name relative to the top
of the repository).  If it matches, the designated program will be run.
The program will be passed the names of each of the files in the commit;
it can do whatever it likes with those names, including opening up the
files and examining their contents.  If the program returns with a
nonzero exit status, the commit is prevented from taking place.

(@dfn{Regular expressions} are a system for concisely describing classes
of strings.  If you aren't familiar with regular expressions, you can
get by with the following short summary: @code{foo} would match any file
whose name contains the string @code{foo}; and @code{foo.*bar} would
match any file whose name contains @code{foo}, followed by any number of
characters, followed by the string @code{bar}.  That's because normal
substrings match themselves, but @code{.} and @code{*} are special.
@code{.} matches any character, and @code{*} means match any number of
the preceding character, including zero.  The @code{^} and @code{$}
signs mean match at the beginning and end of the string, respectively;
thus, @code{^foo.*bar.*baz$} would match any string beginning with
@code{foo}, containing @code{bar} somewhere in the middle, and ending
with @code{baz}.  That's all we'll go into here; this summary is a very
abbreviated subset of full regular expression syntax.)

@cindex commitinfo
The @dfn{commitinfo} file is for generic hooks you want run on every
commit.  Here are some example commitinfo lines:

@example
^a-subdir*     /usr/local/bin/check-asubdir.sh
ou             /usr/local/bin/validate-project.pl
@end example

So any commit into myproj/a-subdir/ would match the first line, which
would then run the check-asubdir.sh script.  A commit in any project
whose name (actual repository directory name, not necessarily module
name) contained the string @code{ou} would run the validate-project.pl
script, unless the commit had already matched the previous a-subdir
line.

In place of a regular expression, the word @code{DEFAULT} or @code{ALL}
may be used.  The DEFAULT line (or the first DEFAULT line, if there are
more than one) will be run if no regular expression matches, and each of
the ALL lines will be run in addition to any other lines that may match.

The file names passed to the program do not refer to RCS files -- they
point to normal files, whose contents are exactly the same as the
working-copy files being committed.  The only unusual aspect is that CVS
has them temporarily placed inside the repository, so they'll be
available to programs running on the machine where the repository is
located.

@cindex loginfo
The @dfn{loginfo} file is similar to commitinfo, except that instead of
acting on the files' contents, it acts on the log message.  The left
side of the loginfo file contains regular expressions, including
possibly DEFAULT and ALL lines.  The program invoked on the right side
receives the log message on its standard input; it can do whatever it
wants with that input.

The program on the right side can also take an arbitrary number of
command-line arguments.  One of those arguments can be a special
@code{%} code, to be expanded by CVS at runtime, as follows:

@example
%s    ------>      name(s) of the file(s) being committed
%V    ------>      revision number(s) before the commit
%v    ------>      revision number(s) after the commit
@end example

The expansion always begins with the repository subdirectory (relative
to the top of the repository), followed by the per-file information.
For example, if the files committed were foo, bar, and baz, all in
@file{myproj/a-subdir}, then @code{%s} would expand into

@example
myproj/a-subdir  foo  bar  baz
@end example

whereas @code{%V} would expand to show their old revision numbers

@example
myproj/a-subdir  1.7  1.134  1.12
@end example

and @code{%v} their new revision numbers:

@example
myproj/a-subdir  1.8  1.135  1.13
@end example

You can combine @code{%} expressions by enclosing them in curly braces
following @code{%} sign -- this will expand them into a series of
comma-separated sublists, each containing the corresponding information
for one file in the commit.  For instance, @code{%@{sv@}} would expand
to

@example
myproj/a-subdir  foo,1.8  bar,1.135  baz,1.13
@end example

and @code{%@{sVv@}} would expand to

@example
myproj/a-subdir  foo,1.7,1.8  bar,1.134,1.135  baz,1.12,1.13
@end example

(You may have to look carefully to distinguish the commas from the
periods in those examples.)

Here is a sample loginfo file:

@example
^myproj$   /usr/local/newrepos/CVSROOT/log.pl -m myproj-devel@@foobar.com %s
ou         /usr/local/bin/ou-notify.pl  %@{sv@}
DEFAULT    /usr/local/bin/default-notify.pl  %@{sVv@}
@end example

In the first line, any commit in the myproj subdirectory of the
repository invokes @file{log.pl}, passing it an email address (to which
@file{log.pl} will send a mail containing the log message), followed by
the repository, followed by all the files in the commit.

In the second line, any commit in a repository subdirectory containing
the string @code{ou} will invoke the (imaginary) @file{ou-notify.pl}
script, passing it the repository followed by the file names and new
revision numbers of the files in the commit.

The third line invokes the (equally imaginary) @file{default-notify.pl}
script for any commit that didn't match either of the two previous
lines, passing it all possible information (path to repository, file
names, old revisions, and new revisions).

@c ----------------------------------------------
@node The verifymsg And rcsinfo Files
@subsection The verifymsg And rcsinfo Files

Sometimes you may just want a program to automatically verify that the
log message conforms to a certain standard and to stop the commit if
that standard is not met.  This can be accomplished by using
@code{verifymsg}, possibly with some help from @code{rcsinfo}.

The @dfn{verifymsg} file is the usual combination of regular expressions
and programs.  The program receives the log message on standard input;
presumably it runs some checks to verify that the log message meets
certain criteria, then it exits with status zero or nonzero.  If the
latter, the commit will fail.

Meanwhile, the left side of rcsinfo has the usual regular expressions,
but the right side points to template files instead of programs.  A
template file might be something like this

@example
Condition: 
Fix: 
Comments: 
@end example

or some other collection of fields that a developer is supposed to fill
out to form a valid log message.  The template is not very useful if
everyone commits using the -m option explicitly, but many developers
prefer not to do that.  Instead, they run

@example
floss$ cvs commit
@end example

and wait for CVS to automatically fire up a text editor (as specified in
the EDITOR environment variable).  There they write a log message, then
save the file and exit the editor, after which CVS continues with the
commit.

In that scenario, an rcsinfo template would insert itself into the
editor before the user starts typing, so the fields would be displayed
along with a reminder to fill them in.  Then when the user commits, the
appropriate program in @file{verifymsg} is invoked.  Presumably, it will
check that the message does follow that format, and its exit status will
reflect the results of its inquiry (with zero meaning success).

As an aid to the verification programs, the path to the template from
the rcsinfo file is appended as the last argument to the program command
line in @code{verifymsg}; that way, the program can base its
verification process on the template itself, if desired.

Note that when someone checks out a working copy to a remote machine,
the appropriate rcsinfo template file is sent to the client as well
(it's stored in the CVS/ subdirectory of the working copy).  However,
this means that if the rcsinfo file on the server is changed after that,
the client won't see the changes without re-checking out the project
(merely doing an update won't work).

Note also that in the verifymsg file, the ALL keyword is not supported
(although DEFAULT still is).  This is to make it easier to override
default verification scripts with subdirectory-specific ones.

@c -------------------------------------------
@node The taginfo File
@subsection The taginfo File

What loginfo does for log messages, taginfo does for tags.  The left
side of taginfo is regular expressions, as usual, and the right side is
programs.  Each program is automatically handed arguments when CVS tag
is invoked, in this order:

@example
arg 1:          tag name
arg 2:          operation ("add" => tag, "mov" => tag -F, "del" => tag -d) 
arg 3:          repository
arg 4, 5, etc:  file revision [file revision ...] 
@end example

If the program returns nonzero, the tag is aborted.

We haven't covered the -F option to tag before now, but it's exactly
what the above implies: a way to move a tag from one revision to
another.  For example, if the tag @code{Known_Working} is attached to
Revision 1.7 of a file and you want it attached to Revision 1.11
instead, you'd do this

@example
cvs tag -r 1.11 -F Known_Working foo.c
@end example

which removes the tag from 1.7, or wherever it was previously in that
file, and puts it at 1.11.

@c ------------------------------------------
@node The cvswrappers File
@subsection The cvswrappers File

The redundantly-named cvswrappers file gives you a way to specify that
certain files should be treated as binary, based on their file name.
CVS does not assume that all .jpg files are JPG image data, for example,
so it doesn't automatically use -kb when adding JPG files.  Nonetheless,
certain projects would find it very useful to simply designate all JPG
files as binary.  Here is a line in cvswrappers to do that:

@example
*.jpg -k 'b'
@end example

The @code{b} is separate and in quotes because it's not the only
possible RCS keyword expansion mode; one could also specify @code{o},
which means not to expand @code{$} sign keywords but to do newline
conversion.  However, @code{b} is the most common parameter.

There are a few other modes that can be specified from the wrappers
file, but they're for such rare situations that they're probably not
worth documenting here (translation: your author has never had to use
them).  See the node @cite{Wrappers} in the Cederqvist if you're
curious.

@c ----------------------------------------------------
@node The editinfo File
@subsection The editinfo File

This file is obsolete, even though it's still included in distributions.
Just ignore it.

@c ----------------------------------------------------
@node The notify File
@subsection The notify File

This file is used in conjunction with CVS's @code{watch} features, which
are described in @ref{Advanced CVS}.  Nothing about it will make sense
until you understand what watches are (they're a useful but
non-essential feature), so see @ref{Advanced CVS} for details about this
file and about watches.

@c ----------------------------------------------------
@node The checkoutlist File
@subsection The checkoutlist File

If you look inside CVSROOT/, you'll see that working copies of the files
exist side by side with their RCS revision files:

@example
floss$ ls /usr/local/newrepos/CVSROOT
checkoutlist     config,v       history     notify     taginfo
checkoutlist,v   cvswrappers    loginfo     notify,v   taginfo,v
commitinfo       cvswrappers,v  loginfo,v   passwd     verifymsg
commitinfo,v     editinfo       modules     rcsinfo    verifymsg,v
config           editinfo,v     modules,v   rcsinfo,v

floss$ 
@end example

CVS only pays attention to the working versions, not the RCS files, when
it's looking for guidance on how to behave.  Therefore, whenever you
commit your working copy of CVSROOT/ (which might, after all, even be
checked out to a different machine), CVS automatically updates any
changed files in the repository itself.  You will know that this has
happened because CVS will print a message at the end of such commits:

@example
floss$ cvs ci -m "added mp and asub modules" modules
Checking in modules; 
/usr/local/newrepos/CVSROOT/modules,v  <--  modules
new revision: 1.2; previous revision: 1.1
done
cvs commit: Rebuilding administrative file database
@end example

CVS automatically knows about the standard administrative files, and
will rebuild them in CVSROOT/ as necessary.  If you decide to put custom
files in CVSROOT/ (such as programs or rcsinfo template files), you'll
have to tell CVS explicitly to treat them the same way.

That's the purpose of the checkoutlist file.  It has a different format
from most of the files we've looked at so far

@example
FILENAME     ERROR_MESSAGE_IF_FILE_CANNOT_BE_CHECKED_OUT
@end example

for example,

@example
log.pl           unable to check out / update log.pl in CVSROOT

bugfix.tmpl      unable to check out / update bugfix.tmpl in CVSROOT
@end example

Certain files in CVSROOT are traditionally not kept under revision
control.  One such is the @dfn{history} file, which keeps a running
record of all actions in the repository, for use by the @w{@code{cvs
history}} command (which lists checkout, update, and tag activity for a
given file or project directory).  Incidentally, if you just remove the
@file{history} file, CVS will obligingly stop keeping that log.

Note: sometimes the history file is the cause of permission problems,
and the easiest way to solve them is to either make it world-writeable
or just remove it.

Another @code{unrevisioned} administrative file is passwd, the
assumption being that having it checked out over the network might
compromise the passwords (even though they're encrypted).  You'll have
to decide based on your own security situation whether you want to add
passwd to checkoutlist or not; by default, it is not in checkoutlist.

Two final notes about the CVSROOT/ directory: It is possible, if you
make a big enough mistake, to commit an administrative file that is
broken in such a way as to prevent any commits from happening at all.
If you do that, naturally you won't be able to commit a fixed version of
the administrative file!  The solution is to go in and hand-edit the
repository's working copy of the administrative file to correct the
problem; the whole repository may stay inaccessible until you do that.

Also, for security's sake, make sure your CVSROOT/ directory is only
writeable by users you trust (by @code{trust}, I mean you trust both
their intentions and their ability not to compromise their password).
The @file{*info} files give people the ability to invoke arbitrary
programs, so anyone who can commit or edit files in the CVSROOT/
directory can essentially run any command on the system.  That's
something you should always keep in mind.

@c -------------------------------------------------------
@node Commit Emails
@section Commit Emails

The loginfo file is how one sets up commit emails -- automated emails
that go out to everyone working on a project whenever a commit takes
place. (It may seem counterintuitive that this is done in loginfo
instead of commitinfo, but the point is that one wants to include the
log message in the email).  The program to do the mailing --
@file{contrib/log.pl} in the CVS source distribution -- can be installed
anywhere on your system.  I customarily put it in the repository's
CVSROOT/ subdirectory, but that's just a matter of taste.

You may need to edit @file{log.pl} a bit to get it to work on your
system, possibly changing the first line to point to your Perl
interpreter, and maybe changing this line

@example
$mailcmd = "| Mail -s 'CVS update: $modulepath'";
@end example

to invoke your preferred mailer, which may or may not be named
@code{Mail}.  Once you've got it set the way you like it, you can put
lines similar to these into your loginfo:

@example
listerizer CVSROOT/log.pl %s -f CVSROOT/commitlog -m listerizer@@red-bean.com
RoadMail   CVSROOT/log.pl %s -f CVSROOT/commitlog -m roadmail@@red-bean.com
bk/*score  CVSROOT/log.pl %s -f CVSROOT/commitlog -m \
                                        bkscore-devel@@red-bean.com
@end example

The @code{%s} expands to the names of the files being committed; the -f
option to @file{log.pl} takes a file name, to which the log message will
be appended (so CVSROOT/commitlog is an ever-growing file of log
messages); and the -m flag takes an email address, to which
@file{log.pl} will send a message about the commit.  The address is
usually a mailing list, but you can specify the -m option as many times
as necessary in one log.pl command line.

@c --------------------------------------------------------------
@node Finding Out More
@section Finding Out More

Although this chapter tries to give a complete introduction to
installing and administering CVS, I've left out things that are either
too rarely used to be worth mentioning or already well documented in the
Cederqvist manual.  The latter category includes setting up the other
remote access methods: RSH/SSH, kserver (Kerberos 4), and GSSAPI (which
includes Kerberos 5, among other things).  It should be noted that
nothing special needs to be done for RSH/SSH connections, other than
making sure that the user in question can log into the repository
machine using RSH or SSH.  If they can and CVS is installed on both
client and server, and they have the right permissions to use the
repository directly from the server machine, then they should be able to
access the repository remotely via the :ext: method.

Descriptions of certain specialized features of CVS have been deferred
to later chapters, so they can be introduced in contexts where their
usefulness is obvious.  General CVS troubleshooting tips are found in
@ref{Tips And Troubleshooting}.  Although it's not necessary to read the
entire Cederqvist manual, you should familiarize yourself with it; it
will be an invaluable reference tool.  If for some reason you don't have
Info working on your machine and don't want to print the manual, you can
browse it online at @uref{http://durak.org/cvswebsites/doc/} or
@uref{http://www.loria.fr/~molli/cvs/doc/cvs_toc.html}.