Subversion on Mac OS X

My workplace is switching from CVS to Subversion for source-code version control so I need to pick up Subversion rather quickly. It took me awhile to get comfortable developing with CVS and now I need to learn stuff all over again. I even have scripts setup to help with the deployment of my project using CVS -- now they need to be modified to work with Subversion. Oh well, I'm sure its for the best.

I've been reading the awesome, and free, Subversion book a lot lately and it has really helped with my understanding of how Subversion works. Since Subversion is not installed on OS X by default, we need to install it before using it from the command line. I downloaded the easy-to-install Subversion .dmg distributed by Martin Ott.

After running the .pkg-installer I was able to run svn help from the command line to confirm it was installed properly. If that command doesn't work after installing, you may need to add this line to the .profile file (in your home directory):

export PATH=$PATH:/usr/local/bin

Now you should be able to run all the SVN commands from your Mac OS X command line. If you prefer a GUI interface to SVN, check out svnX. I do all my development from within Eclipse, so I'm using an SVN plugin for Eclipse called Subversive. I prefer it over the more commonly known Subeclipse plugin because Subversive has a friendlier, and seemingly more configurable, interface.

Checking out a project from the command line over SSH is really simple, however while searching Google I was unable to find this "simple" answer. If I had found the free Subversion book before searching for this answer, I probably wouldn't be writing this:


svn checkout svn+ssh://svn.dev82.org/projects/myproject

That's it! The syntax for checking out a project is very similar to CVS, however SVN has the concept of "URLs" to specify the location and type of connection to your repository. If you have SSH Client Keys setup, you can run SVN commands over SSH without the password prompt (which is necessary for the deployment scripts I use).

Moving a CVS 1.12 repository to CVS 1.11

Over the weekend I moved my entire CVS repository from my home server to a domain hosted on the dedicated web server for my web hosting company. From what I read online, it was as simple as copying all the files to the new location. This appeared to work, but when I tried to create a new project and share it to the repository using Eclipse, I received the following error:

CVS Error

Hmm, unrecognized keyword 'UseNewInfoFmtStrings'. I tried searching Google and although I didn't find very much in the way of a solution, there were hints to the error possibly relating to differences in CVS versions. So I checked my home server version: CVS 1.12.13. Then I checked the version of CVS on my web server: CVS 1.11.17. Ah ha!

My next thought was to upgrade CVS on my web server. But then I discovered my web server (CentOS 4) doesn't have the CVS 1.12 package available because only stable packages are supported. I decided it was best to keep the server stable and starting looking for a way to "downgrade" the 1.12 repository to make it compatible with 1.11.

My eventual solution was to backup /home/dev82/cvsroot/CVSROOT/history, which contains the history information for all the files in the repository, and then delete the /home/dev82/cvsroot/CVSROOT/ directory. After this, I simply ran the following command to recreate CVSROOT and make it compatible with CVS 1.11:

root@web# cvs -d /home/dev82/cvsroot/ init

With the fresh CVSROOT directory in place, I copied the history file back to /home/dev82/cvsroot/CVSROOT/, overwriting the existing one that the cvs init command created.

My biggest worry with doing this was possibly losing history information or somehow being unable to restore files, etc. However, I was able to successfully, create, commit, and restore files from the history. I also had no errors creating new projects and sharing them with the CVS repository.

If anyone knows of a better solution, or has any information on what potential problems following this procedure might have, please leave a comment and let me know!

IMPORTANT UPDATE: I discovered any new files I committed to my repository were being saved to the ./Attic directory. The ./Attic directory is used by CVS for files that have been deleted. If someone checks out a version of the code where that file existed, CVS will pull the file out of the Attic and allow it to be checked out. The funny thing was that my newly committed file still checked out normally even though it only existed in the Attic on the server.

Eventually, I concluded the trouble of moving a 1.12 repository to a server running CVS 1.11 wasn't worth the trouble. I checked out the latest versions of all my projects, deleted the CVS meta-data from them (Eclipse allows you to do this automatically when you disconnect a project from a CVS repository), and then created a new clean repository and checked all the projects back in. My history information is gone, but if I ever discover I really need an old version of a file, I still have a copy of the original repository on my home server.

Using rsync to Mirror two CVS Repositories

I have two personal Linux servers, named Mercury (located in Lowell, MA) and Pluto (located in Cambridge, MA). Monday through Friday I stay in my Cambridge apartment to be close to work and on the weekends I go back to Lowell.

I've been storing all of my projects, both work and personal, in a CVS repository on Mercury. A few weeks ago, however, there was a power outage in Lowell during the middle of the week and Mercury didn't turn back on (probably because I don't have the "PWRON After PWR-Fail" BIOS option set to Former-STS, if it even has that option). So, since the computer wasn't on, I wasn't able to commit or sync any of the projects I was working on. This would normally not be a problem, however I have several staging scripts setup on Mercury which I use frequently to test my work -- so basically I was dead in the water.

After this incident, I realized I needed to mirror my CVS repository to prevent anything like that from happening again. This mirror would not only allow me to access the same CVS repository in the event that I was unable to reach one of my servers, but it would also act as a backup in case I somehow lost all the data on one of the servers.

After a little research using Google, I found this site which basically explains the -a option for rsync:

By far the most useful option is -a (--archive). This acts like the corresponding option to cp; rsync will:

* recurse subdirectories (-r);
* recreate soft links (-l);
* preserve permissions (-p);
* preserve timestamps (-t);
* attempt to copy devices (if invoked as root) (-D);
* preserve group information (-g) (and userid, if invoked as root) (-o).

Using that info, I ran the following command from Mercury (l.rd82.net is the DNS address I have mapped to it's public IP, and c.rd82.net is mapped to Pluto's public IP)

rsync -a /home/cvs [email protected]:/home

That's it! After waiting a few minutes (it took several minutes the first time) my entire CVS repository was copied to Pluto, my Cambridge Linux server. Of course, before I ran that command I had to create the CVS repository on Pluto first by running cvs init /home/cvs. After the rsync command completed, I added a CVS repository for c.rd82.net in Eclipse and confirmed that all my projects were there.

The only thing left to do is to setup a cron job to run the command every night. Of course, I'll need to setup SSH keys so the rsync command can run without user input, but thats easy.