--cvs-exclude claims to ingore files in the same way CVS does, but this isn't quite the case. In particular, the code in exclude.c filters only on filename. But CVS itself is more particular, and differentiates between directories and files. For example, CVS is very willing to recurse into a directory named "a.a", "yadda.old" or "core" The workaround is to document this weakness, but the less surprising thing to do would be to enhance exclude.c such that it could do the exclusion the way CVS actually does it: do most of the exclusions on files only, but exclude both files and directories named CVS.
Your diagnosis is slightly inaccurate -- CVS does exclude directories that match any of the ignore terms (e.g. run "mkdir foobar.a; cvs up" and CVS won't output "? foobar.a"). What you're seeing is that it's possible to commit any file or directory into CVS, even if it matches an ignore term, so the presence of an item in the CVS/Entires file overrides an ignore. There's a fairly new diff in the "patches" dir named "cvs-entries.patch" that handles this problem: http://rsync.samba.org/ftp/unpacked/rsync/patches/cvs-entries.patch This patch causes rsync to enter "include" rules for every item in each directory's CVS/Entries file. I'm debating whether I think this is a good idea or not to include in the regular distribution, since it ties rsync even more tightly to a single SCM system. (Note that this diff was included in the 2.6.5pre1 tar file.) Another solution is to translate the CVS/Entries into rsync filter rules (filter rules were introduced in 2.6.4). An example of this is the brand new script, cvs2includes, in the support dir: http://rsync.samba.org/ftp/unpacked/rsync/support/cvs2includes This script creates .cvsinclude files out of the CVS/Entries, and you just need to tell rsync to include it in each directory, using a command like this: cd src/dir cvs2includes rsync -avC -f ': .cvsinclude' . to/ That's not as convient as having rsync understand the files directly, though.