It's pretty clear that CVS has become the standard for code versioning and control in the open source community. The core PHP developers even use it to control who can check in code, and to see what changes occurred and who made those changes.
CVS isn't just for hardcore software developers. I'm finding that it is really useful for developing PHP web sites (or really any HTML site). Since I have multiple machines in multiple locations across the US, it's super-convenient for me to store all my code in my main CVS tree in West Des Moines, IA and access from my desktop in SunnyVale, CA and my laptop before I jump on a plane.
Many current Linux OS installations will include CVS as part of the install. If not, simply download it, compile it, and install it. I installed using defaults (RTFM), then set up a CVSROOT on my box in Iowa:
[tperdue@myserver tperdue] $ cvs -d /fireball/cvs init
I also had to make an entry in /etc/inetd.conf to map port 2105 to the CVS server app. That allows other machines to connect to my new CVS server.
#CVS pserver
pserver  stream  tcp     nowait  root    /usr/bin/cvs cvs -b /usr/bin pserver
"; And in /etc/services:
cvspserver      2401/tcp     #CVS pserver
CVS inherently communicates using clear text, even when sending your password. If you're the type of developer who has deactivated telnet and ftp and POP mail because of that, you won't be satisfied with the security that CVS offers on the server side. One approach (the one I took), is to create a file called passwd in your $CVSROOT/CVSROOT directory. That file can contain a username/encrypted password combination similar to /etc/passwd. The username in that file should be a user that does not exist on your machine. If someone were to intercept the clear-text password, they could not telnet to your box. However they could commit junk code to your CVS tree and make life generally miserable. There are ways to incorporate secure communication with CVS, but it looked like a hassle and I avoided it. The best policy is frequent, offsite-backups that are kept eternally (my personal policy). For more info, check here.
So your CVS tree is initialized and you are using a passwd file. Now you should login to CVS. Since my CVS server is a different box than the one I'm on, I need to use a long, drawn-out -d option to specify the server:
[tperdue@db columns] $ cvs -d login
OK, you're logged in. CVS just stored your password in an easily-hacked file in your home directory.
All of my existing code was stored on my sexy little VAIO laptop, so I had to import it.
[tperdue@db columns] $ cd ..
[tperdue@db] $ cvs -d import -m "start" x a
The -m option attaches a message ("start"). is the directory to create under the CVSROOT. "x" is a "vendor tag", which is required here, but not referenced. "a" is the release version.
That command imported everything that fell beneath my directory (everything on this site) into the tree.
Now I want to blow out my local directory and start checking out from the tree (back up first).
[tperdue@db] $ cd ..
[tperdue@db docs] $ rm -rf
[tperdue@db docs] $ cvs -d checkout
Now the tree is recreated on my local drive and I can begin editing and committing changes. I want to create a 1.0 version of the entire site and commit that to the tree. I no longer have to use the -d option, since the server info is stored within my local tree.
[tperdue@db docs] $ cd
[tperdue@db] $ cvs update   #not really necessary here
[tperdue@db] $ cvs commit -r 1.0
Now if you make changes, commit them, and then regret it, you can always come back to version 1.0.
[tperdue@db] $ cvs update -r 1.0 #or use "cvs checkout -r 1.0"
How's that for cool? You're all set up, and you even have the building blocks to allow multiple developers to work safely against the same cvs tree.
Updating the web server
Now what if you want to automate the updating of your website? I wrote a script that does this. Once you have committed all of your code and you're confident that everything works fine, you can run a script to automate the process.
First, of course you need to know where the DOCUMENT_ROOT of your server is. Mine is at: /fireball/share/ I then created a directory next to share, called share-update. I keep a checked-out version of my site in that directory.
[tperdue@mybox] $ mkdir /fireball/share-update/
[tperdue@mybox] $ cd /fireball/share-update/
[tperdue@mybox share-update] $ cvs -d /fireball/cvs checkout
So now I have a directory on my webserver that is similar to my "real" web server directory, and I can update it using CVS, then move it over to the live server directory.
#    go to the update directory
cd /fireball/share-update/
#    use CVS to update that directory with the latest code
cvs update
#    clear out the "real" web server directory
rm -rf /fireball/share/*
#    move the updated files over to the "real" web server directory
cp -R /fireball/share-update/* /fireball/share/
#    go to the live web server directory
cd /fireball/share/
#    recursively delete all the directories called CVS
find . -type d -name CVS -exec rm -fr {} \;
#    make sure it's all readable by the server
chmod -R 755 *
There, now you know how to import your source code and access it from anywhere, and just as importantly, you can now automate the updating of your live webserver.

Before you go...

Other useful cvs commands include cvs add file.php3 and cvs rm file.php3. I won't go into details on using compares and merges, as that's fairly sophisticated and I personally never use it in my work. Needless to say, the CVS doc at is extremely useful and will provide more details than I can here. For additional info, you can also visit Cyclic Software.
I hope you find CVS as powerful and useful as I do. I'm now using it to control all of my personal docs like spreadsheets, word processor docs, etc, etc. Please let me know how you use CVS and I may include it in a future revision of this article.