Make a CVS project read-only

In the previous post, Converting a CVS project to a Git repository, I describe using cvs2git to convert a CVS project to a git repository. After I made the conversion, I wanted to make the CVS project read-only.

There’s probably no reason to keep the CVS project around (the history is in the git repo, and I have backups of the CVS project), but it felt like the right thing to do. The blog post Read-only CVS access for only certain projects was extremely helpful to accomplish this.

The key component is the CVSROOT/commitinfo file within your CVS repository. Like any other project in CVS, you need to check this out to make changes:

cvs co CVSROOT
cd CVSROOT && vi commitinfo

You specify a regular expression and a script to run before committing data to a project matching that regular expression. If the script exits with a non-zero exit code (indicating an error), the commit is aborted. For initial testing, I used false (or /bin/false) for the script component, which does nothing and returns an exit code of 1.

I had some problems with this, in part because I was not sure what the project string would look like. I tried a few things:

  • ^/testrepo/.* false (didn’t work)
  • ^testrepo/.* false didn’t work
  • ^t.* false worked, but would match other projects as well

Eventually I switched to using the example from the aforementioned blog post, which printed out the values of the project path and the filenames to be committed.

From there I could see that the project path:

  • Does not include an initial slash
  • Does not include a trailing slash
  • May include additional slashes if the project contains subdirectories

The same script suggests including the following in commitinfo:

^projectname/.* /path/to/script "%p" %s

That regular expression does not work — it would match a file at projectname/subdir1/file1 but not projectname/file1.

And what do the “%p” and %s mean? From C.3.4 Commitinfo:

Currently, if no format strings are specified, a default string of ` %r/%p %{s}’ will be appended to the command line template before replacement is performed, but this feature is deprecated.

I found another document, C.3.1 The common syntax, which describes the format strings.

  • p – the name of the directory being operated on within the repository.
  • {s} – the file name(s), in curly braces because it is a list

The same page includes a sample regular expression that solves the problem I was having:


Finally, here is what I added to CVSROOT/commitinfo:

^testrepo\(/\|$\) /usr/local/script/

Note that this script needs to exist on the same machine as the CVS repository (which may or may not be the same machine as your checked-out copy).

2 thoughts on “Make a CVS project read-only”

  1. I’ve made a maintenance on a cvs repo that was used by quite a few people a while back and simply created locks for this purpose with:

    find /home/cvs/cvsroot/ -type d -exec touch {}/#cvs.lock \;

  2. The substitution strings (%p, %s, etc.) are listed in the default `commitinfo` file. (Would’ve been nice if they were in the documentation, but alas.) For anyone else who needs them:

    # Format strings present in the filter will be replaced as follows:
    # %c = canonical name of the command being executed
    # %R = the name of the referrer, if any, otherwise the value NONE
    # %p = path relative to repository
    # %r = repository (path portion of $CVSROOT)
    # %{s} = file name, file name, …

    Also, I had a helluva time trying to get this approach to work properly on CVS running in a RootJail, because, at least on my company’s installation, the example script failed because`/bin/sh` isn’t available in the jail. Copying `sh` into the jail wasn’t sufficient because it depends on various other commands and libraries that also weren’t present. Rather than go off and learn how `cvsd-buildroot` works as we’re trying to get away from CVS, I found that omitting the shebang (#!/bin/sh) at the top of the script worked as long as the script doesn’t do anything shell-specific. In my case, I just did something like this:

    # Invoke from commitinfo as /myscript %r “%p”
    echo Commit rejected: $1/$2 is read-only!

Leave a Reply

Your email address will not be published. Required fields are marked *