# ln -s /usr/share/cvs/contrib/cvscheck /usr/local/bin To create a repository. It's best to not "import" anything. This is because of difficulty of not breaking things without making _everything_ writable; AND that import does violates Watch rules. Note that you can't import just directories (which are easy to keep secure yet available). See permission strategy towards the end of this file. $ cvs -d /dir/repos init # Now create a "module" and enable Watching. IF no starting content: # write ".*swp" to /dir/repos/CVSROOT/cvsignore $ mkdir /dir/repos/modname $ chgrp sharegrp /dir/repos/modname; $ chmod 2775 /dir/repos/modname # Need a chmod g+s on Solaris $ cd /tmp/skel # checkout the empty module (will make "modulename" dir) $ cvs -d /dir/repos co modname # modname dir will be created in $PWD $ cd modname (don't have to specify -d /dir/repos within here, usually) # This just says to do "chmod -w" for checkouts and updates after commits. $ cvs watch on # IF you want to be notified about EVERYTHING, then $ cvs watch add # Populate without import $ cd /some/where # Move all files to load into co'ed tree $ find . -depth -print | cpio -pdVm /tmp/skel/modulename $ cd /tmp/skel/modname # Remove everything you don't want $ rm -rf /tmp/skel/modname/path/to/RCS... # find /tmp/skel/modname -name '*.class' -exec rm {} \; # (Wildcards below are just to exclude /tmp/skel/modname/CVS branch) $ cvs add $(find . ! -name . ! -name CVS -type d) # Immediately added to repos. # Need to now add files, excluding the CVS files that the previous "add" # wrote. $ cvs add $(find . -type f ! -name Entries ! -name Repository ! -name Root ! -name Entries.Log ) $ cvs commit # Finish setting up Watching set up by "cd /dir/repos/CVSROOT; co -zLT -l notify # edit notify file and users files (make the "users" file if it doesn't # exist). vi notify users # enable the "mail" command in notify; # change 'mail' to 'mailx' for Solaris. # Add lines like "blaine:blaine.simpson@admc.com" to users ci -u -zLT -m'email notification turned on' notify Make a file /dir/repos/CVSROOT/cvsignore containing ".*.swp" (and any other files that you want ALL modules in this repos to not control). Like I said, I recommend against it, but you can import early on... # OTHERWISE import data (preferably only directories) # Fix perms. Need top open up to at least... # The main module directory 2775, and at least some CVS files must be # writable too. # Populate the module if you have a directory skeleton or beginning files. $ cd /some/where # Everything inside "where" will be uploaded $ cvs -d /tmp/repos import -m 'Original Msg' modulename branchTag relTag # In the import above, branchTag and relTag "fill no purpose". $ chgrp -R sharegrp /dir/repos/modname $ find /dir/repos/modname -type d -exec chmod 2775 {} \; # Following line ONLY IF FILES WERE IMPORTED! $ find /dir/repos/modname -type f -exec chmod 664 {} \; Man pages "cvs" and "5 cvs" are not complete!". (E.g. "cvs admin", "cvs edit", "cvs watch", "cvs watchers", "cvs editors"). I think they're all in the info files. VITALLY IMPORTANT: Be careful to not mangle your mods. Don't just run "update". That could "merge" your modifications. Before you will run an update or a commit (ci), always run "update -n". ###### N.b.: I think I meant "-n update"?? cvs -H cvscommand (help for command) Learn the "ESSENTIAL COMMANDS" at top of "man cvs", plus (localfiles... are paths to localfiles that have a local entry in the CVS subdir of the dir the file resides in. The names don't matter since the files in CVS map the source files to the real RCS file in the repository). Note that switches differ from RCS switches in that RCS switches prohibit white spaces after the switch and CVS does not. RCS: ci -m'the message' CVS: ci -m 'the message' Note that "-n" switch is usually useless in that it doesn't tell you what it would have done were the -n switch not given. The exception to this is "update -n", which works great. ###### N.b.: I think I meant "-n update"?? IF there is a CVS subdir of your $PWD and that uses the right repository, then you don't need to use "-d repos" switches. cvs -d /repos/path status localfiles... # Cf. local files to repository cvs log localfiles... cvs -d /repos/path history [-a] -z LT [-l] cvs -d /repos/path release -d module cvs diff file... cvs update -d file1 sdir1 sdir2... # includes all directories (even new # ones generally don't do without specifying # files, because you may get # stuff that you previously excluded. cvs -n upate -I exludedir -I excludefile ... cvs commit -m 'the message' # all modifieds and adds/dels in branch (== ci) checkout == co REMOTE SSH USE export CVS_RSH to ssh and Prefix the repos path with :ext:[user@]hostname:, like CVS_RSH=ssh cvs -d :ext:localhost:/tmp/repos co initdir/init.d CVS_RSH=ssh cvs -d :ext:blaine@localhost:/tmp/repos co initdir/init.d USING WATCHES (inbetween reserved and unreserved locking) (See how to setup above) cvs watch on|off # Recursively turns on watch mode for [file...] # (this just makes ro copies so users must "cvs edit") # Works like g+s in future, but # DOES NOT APPLY TO IMPORTS!!!! cvs watch add|remove [-a action|all] files... # Email me of others' mods cvs [un]edit files... # Makes file readable+notifies. Un reverts. # Just to be nosey about who's watching. cvs watchers files... cvs editors files... put file .cvsignore which lists files and directories to ignore Don't forget to "-kb" binary files with adds (can change afterwards by running' "cvs admin -kb binary.file1 binary.file2..."). I haven't tested it, but it looks like "cvs diff" just compares to what you checked out, not what is in the repository (which is what "cvs -n update" does). THINGS UNDER /reposdir/CVSROOT that need to be writable to users. Emptydir (dir) history, perm 666 val-tags ??, perm 666 cvs log -r lists info about the HEAD revisions (incl. labels) cvs -d :ext:nhqsnpr1:/opt/cvsrepos rtag -D 'criter' NEWTAG mod1/path mod2 ... # The last args are modules of paths beginning with modules. I.e, # anything (other than CVSROOT) relative to the repository root. Contrary to man page, "cvs log" is different from "cvs rlog" (I don't know what rlog is supposed to do). rlog is for a whole module: cvs -d :ext:nhqsnpr1:/opt/cvsrepos rlog -h modname1 modname2... cvs update -p -D 8/6/2003 filepattern > some/where Checks out the file as it was at midnight on 8/6 (i.e., it will not show changes made on 8/6). N.b.! Dates without times are midnight of that morning, i.e. the very BEGINNING of that day. SPECIFYING DATES N.b: Times printed by "cvs *log" are in GMT by default, but times given as arguments to any cvs command are to local by default. Therefore, use local times normally, but if you are using times with respect to CVS log times, then specify GMT, like cvs update -p -D '8/6/2003 10:00 GMT' filepattern > some/where (That is Equivalent to '8/6/2003 6:00 EST' or '8/6/2003 6:00') cvs -q log -D '8/6/2003 10:00 GMT' filepattern Edits are "cleared" when the SAME USER "checks out" that repos file. cvs commit -r REV... REV must be a tag or revision > current revision (if a tag, the tag must already exist for this file). BRANCHES (See the REVISION NUMBERING section) Branch tags appear to "FLOATING" tags of the form x.x.0.y. (I guess that 0 signals that the next number is a branch identifier, and not a revision counter). "y" appears to be the same identifier for normal (non-floating) tags like x.x.y.z, where z is the revision counter. If you specify a branch tag for a file, it generally means the latest revision of that branch. MERGE CONFLICTS Merge conflicts are noted by a wimpy message: rcsmerge: warning: conflicts during merge without pausing. All "merged" files will have a .filename# counterpart, but they don't necessarily have conflicts. All conflictors have the string '^=======$'. "cvs log" shows global history of artifacts. Doesn't matter what branch you run it on. MERGING MERGING. cvs -q update -j START_TAG -j SOURCE_BRANCH ! Always use -q with merges, otherwise C (conflicts) may be missed. You always merge into your working copy. SOURCE_BRANCH may be HEAD. Can do similar things with "cvs -q co -j...". This does NOT write just diffs to a new directory. I don't understand the purpose. Man page says that history only kept if you create $CVSROOT/CVSROOT/history. WRAPPER SCRIPTS. Make a script to return false to prohibit commits. Call it via CVSROOT/commitinfo. The commitinfo script gets $CVSROOT set to whatever the client uses. This seems to always match the beginning of the paths to the resources. CVS FILES Root: Has the CVS Root. Repository: Contrary to the name, has the "module" name. PERMISSION STRATEGY: There is no satisfactory strategy for restricting tag/branch writes. Use "group write" to allow users to "read" anything in a repository (there is no way to prevent these users from writing tags, though :( ). (Need write because they need to be able to write lock files). Use a wrapper script to permit users from any OS groups to commit changes to specific modules. User "cvs" owns the repository root, which is cvs:cvs 02755; and all module roots, which are cvs:cvs 02775; (The latter will work automatically if cvs's umask is set to 02). and repos-root/CVSROOT should be cvs:root 02755). Set up sudo so that people in the "cvs Administration group" can su to 'cvs'. (Also see section "THINGS..."). IGNORES Ignore patterns are only applied to files that only have local residence. They do no good if there is a corresponding file in the repository. You can not "ignore" anything in the repository. Useful history command. Checkins since given date. cvs -q history -c -D '12/08/2003' | more SYM LINKS Can use sym links to share files among different repositories, but DO NOT "cvs remove" THE ONE FROM THE SOURCE SIDE OF THE SYM-LINK. For some reason, that command actually attics the target file and leaves the source link as it is (but orphaned). add: -m arg seems to be 100% useless because no cvs command shows the file description (as opposed to revision messages). NOTE MODE (cvs watch on) just sets read-only perms for all checkouts (incl. Source Forge's anonymous). WATCHING: watch on just means to do "chmod -w" for checkouts and updates after commits. You can still "watch" and "edit" files with watch off, but be aware that unedits will do a "chmod -w", even if edit is off! "cvs log" shows the same output regardless of sticky branch (this is not necessarily true if you use switches!). In particular, "cvs log" lists ALL tags and revisions for the file for all branches. REVISION NUMBERING a.b[.c.d] a = 1 unless you increment version manually. LAST DIGIT (b or d) = real revision number IN THIS BRANCH. For branches, b identifies the branch = trunk revision of branch point. c = ? Always 2 for me. Branches are revision numbers with odd numbers of ordinal digits. "cvs log" inserts another 0 digit though, like this: REAL REVISION: 1.3.4 = 1.3.0.4 (as shown by "cvs log") The last ordinal number itself is nearly always an even number, normally starting at 2 and going up by 2's, but the main branch is just "1". Nested branches will have a branch revision as the branch point, so the revisions will look like 1.2.2.1.2.3 (I.e., branched from revision 1.2.2.1, on artifact revision 3). If you "check out" with a tag, the checked out thing is sticky, regardless of whether it is a static tag or a branch. FILES differing between 2 tags: cvs -q rdiff -kk -s -rTAG1 -rTAG2 filepath... (where filepath begins with the module name, like modname/dir1/...). Similarly with -D 2004-10-22 for dates. Unfortunately, there's no corresponding -s switch for "cvs... diff". RETAGGING For "cvs... tag", use -F. ("Don't know how you get -a capability). For "cvs... rtag", also use -a to clear tags that don't need it. IMO this doesn't work 100%. Always check afterwards. Example: beyla$ cvs rtag -B -F -a -r Disc-Mainline -b ADMC_MIRROR wlapp beyla$ # Disk-Mainline and ADMC_MIRROR should be exactly equal here beyla$ cvs rdiff -s -kk -rADMC_MIRROR -rDisc-Mainline wlapp File wlapp/doc/antedit.txt is removed; ADMC_MIRROR revision 1.1.2.1 beyla$ cvs rtag -B -d ADMC_MIRROR wlapp beyla$ cvs rtag -B -F -a -r Disc-Mainline -b ADMC_MIRROR wlapp beyla$ cvs rdiff -s -kk -rADMC_MIRROR -rDisc-Mainline wlapp beyla$ # Equal NOTIFICATION WITHOUT EDIT MODE De-comment the notification line in "notify". Make a "users" file of form cvs-username:email-addr. Run "cvs watch add..." to get commit notifications. Old versions of CVS do not have the -B switch for rtag (which allows removal and modification of Branch tags). GOTCHA! Removal of directories (in normal client-side fashion) has absolutely no effect at all. FIXING FILE PERMISSIONS Beware that file adds from Windows will typically set wrong file permissions. The only way to fix artifact permissions is to chmod the ,v file on the server. Removing the file and re-adding from the client side will not work because when you re-add an artifact, the server just restores the ATTICed ,v file. KEYWORDS CVS's "ident" and SCCS's "what" extract keywords from binaries. -k Modes -kkv NORMAL SUBSTITUTION. DEFAULT for text files. -ko NO SUBSTITUTION -kb -ko + No EOL transformations + update/co -k switches ignored -kkvl Useless -kk Changes keywords to format $keyword$ (facilitates comparisons) -kv Replaces $keyword[:...]$ with just the VALUE export (checkout without CVS files) When doing code exports, you must decide to export either keyword values or keywords: you can't have both. export: Get values (losing keywords upon any subsequent import). co -kk: Get keywords (losing values upon any subsequent import). Contrary to docs, at least sometimes, "checkout" does not "check out" empty directories, and there is no override for this behavior corresponding to "cvs update -d".