BRL-CAD Concurrent Versions System Policy and Guidelines
========================================================

The document includes a set of requirements and recommended procedures
for how to effectively use CVS with this project.  Included are
details on checking code in and out, effective use of commit messages,
tag naming conventions, branch management, making releases, and more.
Basic knowledge of CVS, it's capabilities, and to a lesser extent it's
limitations are beyond the scope of this document.  See the CVS
website and the "References" section for more information.  That said,
the following general rules should always be adhered to:

1. Code committed against HEAD should at least be tested and compile
   for the developer committing changes.  "Don't break it."

2. There is a STABLE branch that may only have code committed against
   it that a) compiles on all relevant platforms, b) does not
   detrimentally degrade performance, and c) runs correctly passing
   available validation tests.

3. Branches should be used for experimental work that would otherwise
   leave HEAD in an inconsistent, non-compiling, or untestable state.
   Branches are not merged into HEAD until the code has been tested
   for correct and proper functionality.

4. Commit and update frequently.  Large or complicated changes should
   be broken up into smaller succint commits as best possible to make
   reviewing easier.  Commit working code early and commit often.

5. Be consistent and informative.  Tags need to follow a consistent
   naming convention.  Commit messages need to be informative.  Source
   code changes should follow existing style and be usefully
   commented.


TABLE OF CONTENTS
-----------------
    Introduction
    Table of Contents
    Overview
    Checking out sources
	from HEAD
	from STABLE
	from a branch/revision
    Checking in sources
        commit messages
	to HEAD
	to STABLE
	to a branch/revision
    Tag naming convention
	for releases
	for branches
    Making a release
	creating a maintenance branch
	applying release patches
    Merging a branch
	merging a branch into HEAD
	merging HEAD into a branch
    Making a branch
    Usage Tips
    References


OVERVIEW
--------

    Code organizational sanity and consistency are of paramount
    importance.  As CVS can both help and hinder efforts to keep the
    sources organized, the policy and guidelines outlined herein
    overview the manner in which CVS should be used with this project.

    This CVS policy and guidelines document should be used in
    combination with a developer's guide that covers other aspects of
    code contributions and developer behavior such as how and where to
    provide patches, what coding styles should be used, and how to
    make releases.  Likewise, exact semantics of testing policy,
    requirements for migrating code from HEAD to STABLE, basic CVS
    usage, and release policy are outside the scope of this document.

    The intent of this document is to cover the broad aspects of how
    CVS is to be organized and used.  This includes branch management,
    tag naming conventions, checking sources in and out, and other
    relevent usage policy.

    CVS branches should be used to separate out the various types of
    source code revisions.  These include:

	1) current or "active" sources
	2) stable sources
	3) releases
	4) experimental sources

    The CVS HEAD is for active development.  A separate STABLE branch
    exists to hold a revision of the sources that is validated and
    tested across platforms.  Releases should only made off of stable
    revisions of the source code.  When a release is made, a
    maintenance branch may and should exist for making patch releases.
    Finally, various experimental and developer undertakings that may
    benefit by being isolated from changes to HEAD or STABLE, or would
    likewise be distruptive to normal HEAD functionality, may live on
    a branch of their own.

    It's very important that the main CVS HEAD revision be a "mostly"
    stable code base so that at any given time users may download the
    latest sources, get the source code to compile with minimal
    effort, and have the core components mostly function as expected.
    See the "Checking in sources to HEAD" section for more details.

    Some users and developers will need from time to time to obtain a
    relatively recent version of the sources that is certain or at
    least expected to "work".  This is what the STABLE branch is for.
    See the "Checking in sources to STABLE" section for more
    information.


CHECKING OUT SOURCES
--------------------

    There are two basic ways to check out the sources: anonymously or
    as a developer.  Developers have full read-write access to the
    source code.  Anonymous users have read-only access; and the
    version of the sources checked out may actually lag the most
    recent commits by several hours.

    Regardless of whether the sources are being checked out by a
    developer or anonymously, CVS_RSH should be set to "ssh".

    Anonymous users will need to login first:

	cvs -d :pserver:anonymous@cvs.sf.net:/cvsroot/brlcad login

    Once logged in, the access method for anonymous users will be via
    :pserver: (provide an empty password if prompted).  Developers
    will checkout using the default implicit :ext: method and will
    need to provide an authorized username.  Be sure to use the "-P"
    checkout option to remove (prune) empty directories.  The "-z9"
    global CVS option is encouranged to minimze network utilization.


    FROM HEAD:

    As anonymous:
        cvs -z9 -d :pserver:anonymous@cvs.sf.net:/cvsroot/brlcad checkout -P brlcad

    As a developer:
	cvs -z9 -d <username>@cvs.sf.net:/cvsroot/brlcad checkout -P brlcad


    FROM STABLE:

    Checking out from STABLE is like checking out from any specific
    revision or branch -- provide the tag name upon checkout:

    As anonymous:
	cvs -z9 -d :pserver:anonymous@cvs.sf.net:/cvsroot/brlcad checkout -P -r STABLE brlcad

    As a developer:
	cvs -z9 -d <username>@cvs.sf.net:/cvsroot/brlcad checkout -P -r STABLE brlcad


    FROM A BRANCH/REVISION:

    The process for checking out a given revision number is pretty
    much a matter of knowing which revision tag name is desired, and
    then checking out with that symbolic tag name:
    
    As anonymous:
	cvs -z9 -d :pserver:anonymous@cvs.sf.net:/cvsroot/brlcad checkout -P -r <tagname> brlcad

    As a developer:
	cvs -z9 -d <username>@cvs.sf.net:/cvsroot/brlcad checkout -P -r <tagname> brlcad

    If the tag names are not known, you can check out HEAD or STABLE
    and perform a "cvs log" on any file to see the known tag names:

	cd brlcad
	cvs status -v README

    Once you find the revision or branch tag name in question, you can
    "cvs update" to that revision:

	cvs -z9 update -r <tagname>

    See the CVS manual documentation for more information.


CHECKING IN SOURCES
-------------------

    Commit access is generally provided on a case-by-case basis as the
    need arises after careful consideration of the individual's
    ability to follow the project's coding style, follow this CVS
    commit policy, and work productively with the other developers.
    If you have to ask for commit access, you probably won't get it.
    So don't ask.  Provide patches and interact with the existing
    developers.

    If you are given commit access, you are expected to
    read and follow this policy and it's guidelines as well as the
    developer's guide.


    COMMIT MESSAGES:

    When code is committed to CVS, a commit message should be provided
    that appropriately describes the change in a succinct and useful
    manner.  It's important to remember that CVS commit comments are
    stored per-file.  Care should be taken to not be vague,
    undescriptive, or ambiguous often tailoring commit messages to
    individual files even if the change was made as part of a larger
    modification.

    While the comments need to be descriptive and informative, they
    should also be as short and to the point as possible.  The CVS
    commit comments are not the appropriate place for legal
    disclaimers, usage documentation, extensive debugging details,
    business politics, or mini novels of who/what/when/where/why.

    They should be no more than a few lines long at most, normally
    only consisting of a short single-line statement.  CVS commit
    comments are for documenting changes so that other developers may
    derive a clue about what the change was without necessarily
    needing to look at the actual source differences.

    Instead of making generic statements about fixing or improving the
    source code, succinctly describe the change in a manner that may
    be useful for someone else reading the comment that is not
    familiar with the change.  If the changes are merely formatting or
    whitespace adjustments, a simple commit message of "ws" or "M-x
    indent-region" is generally understood and sufficient.

    If a file is being moved/renamed, the comment should include both
    where the file is moved from and where it was moved to in the
    message, e.g. "moved from librt/bool.c to src/librt/bool.c".


    TO HEAD: 
    
    It's very important that the main CVS HEAD revision be a "mostly"
    stable code base so that at any given time users may download the
    latest source, get it to compile with minimal effort, and have the
    core components mostly function as expected.  HEAD is where active
    development takes places, so this necessarily means that there may
    be small windows of opportunity where the sources do not compile,
    but those should not persist.  Likewise, since the developers
    potentially and often have specific or relatively independent
    development efforts, the CVS commits of one developer should be
    made in a means that will have limited or understood impact on
    other developers.

    This minimally means that CVS commits need to at least work for
    the developer committing the changes.  If it's discovered that the
    changes break other major supported platforms, the broken state
    should not be allowed to linger.  Effort and arrangements need to
    be made to either resolve the problem promptly or the changes
    should be reverted.


    TO STABLE:

    Code being committed to STABLE require special attention and just
    a little more detail in their commit messages.

    Some users and developers will need from time to time to obtain a
    relatively recent version of the sources but a version that is
    certain or at least expected to "work".  This shall be known as
    the STABLE branch.  For code to make it to the STABLE branch, it
    needs to pass several criteria and commits should be well
    documented indicating the nature, purpose, and impact of the
    change.  These criteria include the following:

    a) Compiles -- The code must compile on all supported platforms.
       This generally requires coordination with other developers if
       access to other platforms is limited.

    b) Improves -- Without reasonable justification, the changes must
       not degrade performance, be inconsistent in style or behavior
       of the sources, or break support for existing functionality.

    c) Passes -- The changes must successfully pass any available
       validation tests.  If the tests are flawed or simply require
       modification, justification and explanation should be provided
       along with fixes to the tests before submitting code that would
       otherwise not pass validation.


    TO A BRANCH/REVISION:

    Checking in code to a branch other than STABLE generally do not
    necessarily need to follow the same requirements of compiling
    cleaning or "working" until those changes are merged back in to
    either STABLE or HEAD unless the branch is a release maintenance
    branch.  Release maintenance branches generally follow the same
    commit rules as checking into HEAD.

    As it's not possible to commit against a non-branch checkout (such
    as a release tag export like "rel-7-0"), changes to a revision
    that is otherwise immutable can still be made by performing a
    "diff" against a clean checkout of that same revision (unmodified)
    and then applying the patch to a maintenance branch or to the CVS
    HEAD.  See the "Applying release patches" under "Making a release"
    for examples.


TAG NAMING CONVENTIONS
----------------------
    <keyword>[-<revision>][-<date>][-<comment>]

    <keyword> ::= { rel, ansi, jra, sean, ppc, ... }

        The <keyword> is normally something short and concise.  For
        release tags, it is "rel".  Other branch keywords may indicate
        functionality, developers, etc.

    <revision> ::= <major>[-<minor>[-<patch>]]  (e.g., 6-0-2 and 5-2)

        The <revision> numbering convention is fairly standard and
        common practice:

        <major> is the major revision number and changes relatively
                infrequently.  Major releases contain significant
                architectural changes and are not generally backwards
                compatible with existing code or data to some extent.
                They may require data and/or code to be converted in
                order to upgrade.

        <minor> is the minor revision number a usually changes on a
                fairly regular basis.  As new features are added and
                releases are made, the minor revision number changes
                to reflect those additions.  Odd minor numbers
                indicate a developer revision.  Even minor numbers
                indicate a release revision.  Minor releases may or
                may not be backwards compatible.

        <patch> is the patch revision number and is used to make bug
                fixes on an as-needed basis.  These changes are not
                usually as extensively tested as minor and major
                releases, but they should always be backwards
                compatible.

    <date> := YYYYMMDD (e.g., 20021231)
        
        When creating tags, the date a tag is made is sometimes noted
        and useful or even recommended.  The format of the date is
        YYYYMMDD and should correspond to tag creation dates.  Branch
        and release tags should not include a date in the tag name.

    <comment>
        
        For branches the comment is "branch".  For releases, it is
        left blank.  For other miscellaneous tags, the comment is up
        to the person tagging.

    Note that hyphens (-) are used, not underscores.  Periods (.) are
    never used because they upset CVS's branch naming.

    Tag names (including branches) should be in lower case only.
    Upper case is reserved for HEAD and STABLE.

    Non-branch tags are used for 1) marking a release, 2) merging
    branches, and 3) miscellaneous tags (e.g., to remember a specific
    starting or stopping point).


    FOR RELEASES:

	Release tags are used to indicate a revision of the source
	code that was made publicly available.  It should match the
	sources released, bugs and all, so that proper and useful
	diffs may be made.  The format for release tags is:

        rel-<revision>

	    <revision> ::= <major>-<minor>[-<patch>]

	    The revision number should match the version reported by
	    the source code.

	Examples: rel-6-0 rel-7-2-5


    FOR BRANCHES:

        Branches are symbolic tags that are used to denote and allow
	separate isolated revisions of code.  The following format
	should be used for branch tags:

	<keyword>[-<revision>]-branch

	    <keyword> ::= describes the purpose of the branch.

	    If the branch is a maintenance branch, the keyword should
	    match the revision's keyword and revision.

	Examples: rel-7-0-branch ansi-branch photonmap-branch


    FORMAT FOR MERGES:

	When joining a branch that has a large set of changes into
	HEAD, there should be a tag before and after the merge.  When
	joining HEAD into a branch, tagging is optional. Joins into
	head should be tagged, though.

        On HEAD before the merge, use the following tag format:

            premerge[-<revision>][-<date>]-<comment>

	    Example: premerge-20040404-ansi

        On HEAD after the merge, use the following tag format:

            postmerge[-<revision>][-<date>]-<comment>

	    Example: postmerge-20040315-windows 

	The <comment> should be a simple identifying keyword.  The
	branch keyword being merged suffices quite well.  A date is
	preferred.

	If development on a particular branch is considered "final",
	it should be marked with a "freeze" tag on the branch:

	    <keyword>[-<revision>][-<date>]-freeze

	    Example: windows-20040315-freeze

	If applying patches directly to the CVS HEAD where there is
	potential to need to revert the changes, using "pre" and
	"post" as the tag comment is appropriate.

	    <keyword>[-<revision>][-<date>]-pre
	    <keyword>[-<revision>][-<date>]-post
	    
	    Examples: hartley-6-0-pre ctj-4-5-post offsite-5-3-pre


    FORMAT FOR MISCELLANEOUS TAGS:

	For everything else, the basic structure of the tags still
	applies.  Lower case, dash-separated, and hopefully succintly
	informative tag names should be used.  Dates are highly
	recommended as CVS tags are not associated by date, but rather
	to the individual revision of a file.
    
        <keyword>[-<revision>][-<date>][-<comment>]

    When in doubt, tag.  It's easy to remove or rename tags, but it
    can be rather complicated to create one after the fact.


MAKING A RELEASE
----------------

    Making a release is generally a matter of making sure that all
    desired code changes are committed and well tested.  Code
    committed to HEAD should be well tested by performing any
    validation steps required to migrate those changes to STABLE.
    Once HEAD is verified, it may be joined into STABLE, which should
    likewise be thoroughly tested.

    Once all the code is verified, the release should be tagged:

	cvs tag rel-<revision>

    Revision numbers should follow a numbering convention consistent
    with the developer guidelines.  Minor and patch revision numbers
    that are odd numbered are used to denote developer revisions of
    the source code.  Release tags should use even numbers for the
    minor and patch revision numbers.  See the "Tag naming convention"
    section for more details.


    CREATING A MAINTENANCE BRANCH:

    If minor maintenance is expected to continue or development on
    HEAD needs to continue in an incompatible manner, a maintenance
    branch should be made:

	cvs rtag -r rel-<revision> -b rel-<revision>-branch

    That will create a branch named rel-<revision>-branch anchored at
    the same revision of the sources as rel-<revision>.


    APPLYING RELEASE PATCHES:

    In general, unified diff patches should be requested from people
    providing patches whenever possible.  For people working with a
    cvs checkout, generating a diff is generally a simple matter of
    running:

	cvs diff -u > my.patch

    This will create a unified diff patch file called "my.patch" that
    is trivially applied to a checkout using the patch command:

	patch -p0 < my.patch

    Assuming there have not been overlapping/conflicting changes,
    patch should say on the first attempt that all chunks were
    successfully applied.  If not, there will be reject files that
    will have changes that need to be manually reviewed and resolved..

    Users who are perhaps working off of a source tarball instead of a
    CVS checkout can fairly easily generate a unified diff patch by
    comparing their modified tree against an unmodified source tree:

	diff -u brlcad brlcad.modified > my.patch

    In this example, brlcad is an unmodified top-level source
    directory and "brlcad.modified" is a top-level source directory
    that has been modified.  That same patch file may then be applied
    to a checkout and commited to CVS.

    If there is an active maintenance branch that a patch was started
    from, it is generally easier to apply the patch to the maintenance
    branch first and then join the maintenance branch into HEAD per
    the usual means to join branch changes into HEAD instead of
    merging directly into the CVS HEAD.  HEAD will have often changed
    too significantly and may result in patch being unable to resolve
    chunks.  See the patch manual documentation for more details.

    Failing any of the above, patches may also be applied manually.
    This is often even desireable to become more familiar with the
    changes being made providing an opportunity for a healthy peer
    review.


MERGING A BRANCH
----------------
    CVS branches can be both very useful or difficult.  Proper usage
    of branches generally requires a firm understanding of CVS
    otherwise complications and mistakes are bound to happen as there
    are several usage pitfalls.  Following the directions shown below
    should help avoid the pitfalls and assist in making effective use
    of a CVS branch.

    Regardless if the branch is a maintenance branch or the STABLE
    branch, the fundamental "action" in performing a merge is called a
    CVS join.  You can join code commited to one branch revision into
    another branch revision by passing the "-j" option to the cvs
    update command.  It's important to note that joins occur from code
    that is already committed.

    Once the code is joined, it may be committed to CVS.  If you have
    changes on a branch that have not yet been commited, they should
    first be commited before attempting the join.


    MERGING A BRANCH INTO HEAD:

    Merging branches in CVS is generally a matter of "joining" in the
    changes from one the branch revision into another branch revision.
    HEAD can itself be considered a branch.  If, for example, you have
    a maintenance branch named "rel-7-0-branch" that has had changes
    applied to it and you wish to apply those same changes to HEAD you
    would checkout HEAD:

	  cvs -z9 -d <CVSROOT> checkout -kk -P brlcad

    The join the changes from the desired branch:

	  cvs update -kk -dP
	  cvs tag premerge-<revision>-<date>-<comment>
	  cvs update -kk -dP -j rel-7-0-branch
	  [ resolve conflicts & test ]
	  cvs commit
	  cvs tag postmerge-<revision>-<date>-<comment>

    The comment should contain or be the keyword of the branch being
    merged in.  For example, "premerge-20040315-windows" indicates a
    merge that occured on March 15th, 2004, from the windows-branch.

    If there are any conflicts, they would of course need to be
    manually resolved.  Once any conflicts are resolved and the
    sources are tested for functionality, the changes could then be
    commited to HEAD.  Be careful to notice any file additions or
    deletions as CVS, generally speaking, will not manage those for
    you until they are committed.

    In both the checkout and the join update, the -kk flag was used to
    cause CVS to not expand the CVS variables such as \$Revision\$ and
    \$Id\$.  If those keyword variables are expanded, you're likely to
    have many conflicts depending on time-stamps.
    
    If the branch being checked in an extensive set of changes,
    testing is essential.  It is also a good idea to warn other
    developers of what you are planning to do.  You should indicate
    what parts of the system will be affected and coordinate in detail
    with other developers as appropriate.


    MERGING HEAD INTO A BRANCH:

    Merging changes from HEAD into a branch (such as STABLE) is not
    really any different than the scenario described for merging a
    branch into HEAD.  Again, HEAD itself can be simply considered a
    branch too.  For example with an existing branch checkout:

	cvs update -kk
	cvs update -kk -j HEAD
	[resolve conflicts & test ]
	cvs commit

    The important step to realize is that your working checkout needs
    to be the revision you want to join changes into.  When in doubt,
    commit all your changes to the appropriate branch, delete all your
    sources, and checkout fresh.  "cvs status README" will tell you
    what revision you have checked out.  It will be listed as a
    "Sticky Tag".


MAKING A BRANCH
---------------
    Making a branch is a matter of using the "-b" option when tagging.
    Branch tags are special symbolic CVS tags that allow for isolated
    changes and controlled merging of modifications.

    CASE 1: You have no checked out source code revision:

        If you want to use the latest sources on the CVS HEAD as the
        starting point for your branch:

            cvs rtag -b <keyword>-branch brlcad
            cvs checkout -r <keyword>-branch brlcad

        If you want to use some other tag as the starting point for
        your branch:

            cvs rtag -b -r <tag> <keyword>-branch brlcad
            cvs checkout -r <keyword>-branch brlcad

    CASE 2: You have a checked out revision with all changes committed
    and you want to tag it and start using it as a branch:

        cvs tag -b <keyword>-branch
        cvs update -dP -r <keyword>-branch

    CVS will denote the tag as a "sticky" tag to indicate which
    version is currently checked out.  You can verify this by using
    'cvs status', for example:

        cvs status README

    To see all tags that have been set for a particular file in
    addition to checkout status, use the "-v" status option:

        cvs status -v README

    or via the generally more detailed file log:

	cvs log README


USAGE TIPS
----------
    0) Checkout with the -P option to prune empty directories:

       cvs checkout -P brlcad

    1) Be sure to perform an "update -dP" to check for new directories
       from time to time and to prune empty ones.

       cvs update -dP

    2) Update and commit frequently.  Frequent updates are a good
       thing.  Perform them often to minimize conflicts.

    4) A convenient way to check what files have been modified when
       you are certain that you've not added files:

       cvs -q update | grep -v \?

       That performs a quiet update (the directory tree isn't output)
       and ignores lines that have a question mark (normally build
       files).

    3) To avoid having to specify the repository for a checkout, you
       can set your CVSROOT environment variable to the location of
       the repository:

       For anonymous users:
           export CVSROOT=:pserver:anonymous@cvs.sf.net:/cvsroot/brlcad

       For developers with accounts:
           export CVSROOT=<username>@cvs.sf.net:/cvsroot/brlcad

    5) CVS does not manage directories so care must be taken when
       creating new directories or moving things around.  Do NOT add
       directories that include non-static information as part of the
       directory name.  Examples include adding directories that
       include a version in their name (e.g. libtcl8), indicate age
       (e.g. newRt), or contain other volatile data.

    6) If you need to move a directory, rethink why and try not to.
       If you still need to move a directory, .. try to find another
       way to cope.  If you still REALLY need to move a directory, a
       little find scripting can make it easy.  In case you didn't get
       the hint DO NOT MOVE/RENAME DIRECTORIES unless there's a _very_
       good reason.  This implictly means that extra care and thought
       should be made when naming new directories to be added to the
       repository.

    7) It is possible to move directories using a little find
       scripting.  Assuming you've not got build files cluttering
       things up and are ready to simply move files to a new location
       in CVS, an otherwise complicated task becomes mostly simple
       with a few find scripts.  Here is an example where a directory
       ./foo/ is moved to a new location ./src/foo2/:

       cd foo
       # copy the files to their new home
       find . -type d -not -name CVS -exec mkdir -p ../src/foo2/{} \;
       find . -type f -not -regex '.*/CVS/.*' -exec cp -p {} ../src/foo2/{} \;
       cd ../src
       # add the new directories to cvs
       find foo2 -type d -not -name CVS -exec cvs add {} \;
       find foo2 -type f -not -regex '.*/CVS/.*' -exec cvs add {} \;
       # commit the new sources
       cvs commit -m "moved from foo to src/foo" foo2
       cd ..
       # delete the old source subtree
       find foo -type f -not -regex '.*/CVS/.*' -exec rm {} \;
       find foo -type d -not -name CVS -exec rm -f {} \; -exec cvs delete {} \;
       cvs commit -m "moved from foo to src/foo" foo
       cvs update -P foo

       If you don't have CVS keys set up and have too many files to
       move, each find script could be passed to xargs so that only a
       single password is prompted instead of one per file.  Since
       moving/renamed directories in CVS is "bad", though, that's left
       as an exercise to the reader.

    8) When renaming files, be sure to indicate both where the file
       was moved from and where it was moved to and/or the name before
       the move and the name after the move.  Do this both on
       committing the file deletion and on committing the file
       addition.  This way, people reading the file's log will know
       where to find the rest of the file's history.

    9) If experiencing trouble consolidating conflicts that involve
       CVS "$" variables, set the keyword sticky flag which will tell
       CVS to not perform the keyword variable expansions.  Perform a
       "cvs update -kk" and the conflicts should go away.

   10) Denote binary files as binary in CVS via the
       CVSROOT/cvswrappers administrative file or via the "-kb" option
       when adding files.  In the CVSROOT/cvswrappers file, the
       following line would denote files ending in ".pix" as binary:

       *.pix -k 'b'

       You can likewise denote arbitrary files as binary via the "-kb"
       option on commit:

       cvs add -kb new_file_name_here

       If the file has already been added to CVS, it may be
       administratively marked as a binary file after the fact using
       the "cvs admin" command:

       cvs admin -kb some_existing_file
       cvs update -A some_existing_file


REFERENCES
----------
    This CVS policy and guidelines document was in part derived off
    some of the principal ideas of other projects' usage of CVS such
    as the Linux Documentation Project, the XFree86 DRI project, Zope,
    FreeBSD, and AT&T's SML/NJ among others.

Version Management with CVS
https://www.cvshome.org/docs/manual/

CVS Best Practices
http://www.magic-cauldron.com/cm/cvs-bestpractices/index.html

XFree86 Direct Rendering Infrastructure CvsPolicy
http://dri.sourceforge.net/cgi-bin/moin.cgi/CvsPolicy
http://dri.sourceforge.net/doc/cvspolicy.txt

Zope 
http://dev.zope.org/CVS/ZopeReleasePolicy

FreeBSD
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/cvs-tags.html

AT&T SML/NJ
http://www.smlnj.org/DEV/policy.html
http://cm.bell-labs.com/cm/cs/what/smlnj/DEV/policy.html

--- 
This document was initially written in 2002 and later almost
completely rewritten in 2004 by Christopher Sean Morrison.
