man VCP::Source::cvs () - A CVS repository source


VCP::Source::cvs - A CVS repository source


   vcp cvs:module/... -d ">=2000-11-18 5:26:30" <dest>
                                  # All file revs newer than a date/time

   vcp cvs:module/... -r foo      # all files in module and below labelled foo
   vcp cvs:module/... -r foo:     # All revs of files labelled foo and newer,
                                  # including files not tagged with foo.
   vcp cvs:module/... -r 1.1:1.10 # revs 1.1..1.10
   vcp cvs:module/... -r 1.1:     # revs 1.1 and up on main trunk

   ## NOTE: Unlike cvs, vcp requires spaces after option letters.


Source driver enabling CWvcp to extract versions form a cvs repository.

The source specification for CVS looks like:

    cvs:cvsroot:module/filespec [<options>]

or optionally, if the CWCVSROOT environment variable is set:

    cvs:module/filespec [<options>]

The cvsroot is passed to CWcvs with cvs' CW-d option.

The filespec and <options> determine what revisions to extract.

CWfilespec may contain trailing wildcards, like CW/a/b/... to extract an entire directory tree.

If the cvsroot looks like a local filesystem (if it doesn't start with : and if it points to an existing directory or file), this module will read the RCS files directly from the hard drive unless --use-cvs is passed. This is more accurate (due to poor design of the cvs log command) and much, much faster.


Used to set the CVS working directory. VCP::Source::cvs will cd to this directory before calling cvs, and won't initialize a CVS workspace of it's own (normally, VCP::Source::cvs does a cvs checkout in a temporary directory). This is an advanced option that allows you to use a CVS workspace you establish instead of letting vcp create one in a temporary directory somewhere. This is useful if you want to read from a CVS branch or if you want to delete some files or subdirectories in the workspace. If this option is a relative directory, then it is treated as relative to the current directory.
   -k sadf
Pass the CVS -k options through to the underlying CVS command.
Pass the -kb option to cvs, forces a binary checkout. This is useful when you want a text file to be checked out with Unix linends, or if you know that some files in the repository are not flagged as binary files and should be.
   -r v_0_001:v_0_002
   -r v_0_002:
Passed to CWcvs log as a CW-r revision specification. This corresponds to the CW-r option for the rlog command, not either of the CW-r options for the cvs command. Yes, it's confusing, but cvs log calls rlog and passes the options through.
Do not try to read local repositories directly; use the cvs command line interface. This is much slower than reading the files directly but is useful to see if there is a bug in the RCS file parser or possibly when dealing with corrupt RCS files that cvs will read. If you find that this option makes something work, then there is a discrepancy between the code that reads the RCS files directly (in the absence of this option) and cvs itself. Please let me know ( Thanks.
   -d "2000-11-18 5:26:30<="
Passed to 'cvs log' as a CW-d date specification. WARNING: if this string doesn't contain a '>' or '<', you're probably doing something wrong, since you're not specifying a range. vcp may warn about this in the future. see log command in cvs(1) man page for syntax of the date specification.

CVS Conversion issues

Files that aren't tagged

CVS has one peculiarity that this driver works around.

If a file does not contain the tag(s) used to select the source files, CWcvs log outputs the entire life history of that file. We don't want to capture the entire history of such files, so VCP::Source::cvs ignores any revisions before and after the oldest and newest tagged file. CVS allows branches to be tagged with multiple tags using a command like

   cvs admin second_branch_tag:branch_tag

When VCP::Source::cvs notices this, it creates multiple branches with identical revisions. This is done by choosing the first branch tag for the branches to be the primary branch and applying all actual changes to it then cloneing each revision from that branch to all others.

For instance, if file foo is branched once in to a branch tagged with bar and later a goof tag is aliased to the bar tag, then

    trunk     branch bar         branch goof
    =======   ================   ==================

      |    \
      |     \
      |      \
     ...      foo#<bar>
                 |            \
                 |             \
                 |              \
                 |               foo#<goof>
                 |            \
                 |             \
                 |              \
                 |               foo#<goof>

This is EXPERIMENTAL and it's likely to give VCP::Dest::cvs fits. It is tested with CVS->p4 transfers.

If you only want the primary branch, you may use a Map: section in the .vcp file to discard non-primary branches:

        ...<goof>   <<delete>>

Currently, there is no way to ignore the primary branch other than getting rid of that branch tag in the RCS files or hacking VCP::Source::cvs's source code to ignore it.


(EXPERIMENTAL) It's possible somehow (I've never done it) to set the state on edited revisions to dead, which may result in a series of revisions all marked dead. CVS, at least older versions, deleted a file by marking the head rev as state dead instead of adding a new revision. So a dead revision is both an edit and a deletion. I am not sure whether the metadata on the rev refers to the time and user that committed the edit, or the time and user that committed the delete.

VCP::Source::cvs detects consecutive dead revisions and dead revisions that are also edits and issues a normal edit revision followed by a concocted delete revision with a .0 appended to the rev_id.


Stores all revisions for a file in RAM before sending so it can link all the revisions properly. Also stores all branch parents and the first revision on every branch for all files scanned so it can insert placeholders for branches with no revs. Except for these branch point revisions, all other revs for each file are sent before the next file is scanned.

TODO: just send placeholders for all branches that match the filespec and revspec?

Does not yet set the same time in all branch creation revisions. This may be necessary in order to help the changeset aggregator. It will probably take buffering all branch revs before sending them on. Also, it is not possible in the general case: not all files on a branch are actually branched from parents that are checked in before the first file on a branch is created. It also makes no sense to do this for untagged branches as there is no detectable semantic association between untagged branches.

CVS does not try to protect itself from people checking in things that look like snippets of CVS log file: they come out exactly like they went in, confusing the log file parser. So, if a repository contains messages in the log file that look like the output from some other cvs log command, things will likely go awry when using remote repositories (local repositories are read directly and do not suffer this problem). The direct RCS file parser does not have this problem.

CVS stores the -k keyword expansion setting per file, not per revision, so vcp will mark all revisions of a file with the current setting of the -k flag for a file.

At least one cvs repository out there has multiple revisions of a single file with the same rev number. The second and later revisions with the same rev number are ignored with a warning like Can't add same revision twice:....

The xfree86 repository has several files xc/programs/Xserver/hw/xfree86//vga256/drivers/s3/s3Bt485.h:

   1.2     dead lines +1, -1
   1.1     Exp  lines Exp  lines +1, -1 Exp  lines +1, -1

In this case, VCP::Source::cvs doesn't know how to retrieve rev 1.2 to create the branch 1.2.2.x, so it uses 1.1. If you know how to force it to get rev 1.2, please let me know (in the future, the RCS parser will allow this, but currently we always use cvs checkout to retrieve versions). I'd like to know how to use the cvs command to modify a revision and then force it to the dead state without upping the revision number, as that appears to have happened here. I suspect something other than the cvs command at play here, like the rcs command or RCS file editing by hand or by script


VCP::Dest::cvs, vcp, VCP::Process.


Barrie Slaymaker <>


Copyright (c) 2000, 2001, 2002 Perforce Software, Inc. All rights reserved.

See VCP::License (CWvcp help license) for the terms of use.