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}.
|