I've been meaning to switch from CVS to Subversion for quite a while. It seemed hard, but it actually took me only a couple of days to get it installed and configured for the whole development team.
This article describes the differences between CVS and Subversion and explains how to install Subversion and migrate an existing CVS repository. It also describes how to configure Subversion in a Windows environment, explains a basic Subversion project structure, and introduces the main Subversion clients. Finally, it shows ways to use Subversion with Ant and how to get connected to the repository via JavaSVN and ColdFusion.
Subversion Versus CVS
Subversion acts a lot like CVS, but fixes the flaws and addresses the shortcomings in the popular Concurrent Versions System (CVS). The following features either fix CVS flaws or improve on existing CVS features and were the main reason for switching from CVS to Subversion:
If you're feeling lazy and prefer an automated install, you can use the "svn1clicksetup" project from Tigris. Svn1ClickSetup takes you through all the steps necessary to install the Subversion command-line utilities and TortoiseSVN as well as creating a repository and initial project.
There are several installation options for Subversion. I preferred the Apache installation. SVN Server together with Apache is the installation used most often and provides authentication, path-based authorization, and basic repository browsing.
I was advised never to use the Berkeley database so I selected a file system for our repository. After the Subversion installation I was searching for a tool to import content from CVS to the new Subversion repository. It should preserve commits, authors, commit messages, and the dates of commits and also convert CVS branches and tags to SVN branches and tags.
The tool of choice was the Polarion "SVN Importer," a command-line utility that transfers data from other version control systems to SVN. It also supports the version control systems PVCS, VSS, ClearCase, and MKS. All I had to do was modify the configuration file "config.properties," specifically the sections "SVN AUTOIMPORT OPTIONS" and "CVS PROVIDER CONFIGURATION." Then I had a long coffee break because the repository to migrate was very large. After five hours everything was imported without a single warning.
Configuration
I was happy to learn that Subversion supports directory and file properties. There are certain built-in properties, but you can also specify your own properties. Our existing files included the CVS keywords $Id$ and $Log$ in the comments at the top of the file.
Subversion supports $Id$, but not the $Log$ keyword. Subversion developers haven't included a $Log$ keyword (expands to list all of the log messages) because in their opinion all this extra stuff in the source files gets in the way of reading the code. For Subversion to recognize things like $Id$ in source files, you have to tell it to do this explicitly by updating the "svn:keywords" property.Changes such as this are versioned just like any other changes to the files so you'll have to commit after running this command for it to take effect.
To set the property automatically on files matching certain patterns, add lines such as this to your subversion/config file:
### Section for configuring miscellaneous Subversion options.
[miscellany]
enable-auto-props = yes
### Section for configuring automatic properties.
[auto-props]
Both svn:keywords and svn:eol-style are file properties. svn:keywords is needed to add the keywords to the file; svn:eol-style determines the line ending character on a file.
I also thought about using the folder property "tsvn:logminsize," which would set the minimum length of a log message for a commit, but changed my mind.
The previous CVS installation used SSPI (integrated Windows authentication), so we needed something similar for Subversion. Subversion provides the SSPI module "mod_auth_sspi.so." Within the Apache httpd.conf file the following modules must be setup in order:
# Windows authentication module
LoadModule sspi_auth_module modules/mod_auth_sspi.so
# subversion modules
LoadModule dav_svn_module "C:/Program Files/Subversion/bin/mod_dav_svn.so"
LoadModule authz_svn_module "C:/Program Files/Subversion/bin/mod_authz_svn.so"
I also added the authentication lines to the Location Tag:
<Location /svn>
DAV svn
# All repos subdirs of d:/svn_repos
SVNParentPath d:/svn_repos
# authentication
AuthName "Subversion Authentication"
AuthType SSPI
SSPIAuth On
SSPIAuthoritative On
SSPIUsernameCase lower
SSPIOmitDomain On
SSPIDomain MUC
SSPIOfferBasic On
Require valid-user
# authorization
AuthzSVNAccessFile "d:/svn_repos/authorization.conf"
</Location>
A simple "authorization.conf" file would contain only these two lines:
[/]
o = rw
This means that all users can read and write. Please consult the documentation for more advanced configuration options. If your Subversion repository is being served up through the Apache HTTP Server you can point any Web browser to your Subversion repository and navigate your way through the latest revision of your repository.
Subversion Project Structure, Clients and IDE Integration
The Subversion project officially recommends the idea of a "project root," which represents an anchoring point for a project. A "project root" contains exactly three subdirectories: /trunk, /branches, and /tags. These naming conventions are only a suggestion, but commonly used.
Trunk represents the main line of development, release Branches represent working code that differs from trunk. Tags (read-only) are significant events in a project's lifecycle.
A repository may contain only one project root or a number of them. Subversion versions the repository, not individual projects.
When you commit a change to the repository, make sure your change reflects a single purpose like fixing a specific bug, adding a new feature, or some particular task.
Our development team uses several IDEs like Homesite, Dreamweaver, or Eclipse (with the CFEclipse plug-in). In the past the preferred CVS Client was WinCVS.
After switching to Subversion, Homesite users installed the Tortoise SVN and were happy with the Windows shell extension. This extension let them execute SVN actions inside their IDE. CFEclipse users installed the Subclipse plug-in, which let them access the Subversion repositories inside Eclipse.
The Subversive project is a new Eclipse plug-in that provides Subversion support.
Ant Scripts
SvnAnt is an Ant task that provides an interface to Subversion revision control system. SvnAnt uses Javahl (a Java interface for the Subversion API) or the experimental svn command-line interface. SvnAnt supports most of the major Subversion commands. A sample Ant target with SvnAnt would read like this:
<!- define svn taskdef ... ‡
<target name="checkoutLatest">
<svn>
<checkout url="${svnant.latest.url}" revision="HEAD" destPath="src_latest" />
</svn>
</target>
After several tries and connection problems I finally gave up and used the Ant exec task instead. Sample code from build.xml:
<!-- svn-settings -->
<property name="svn_root" value="SVN ROOT" />
<property name="svn_username" value="SVN USER" />
<property name="svn_password" value="SVN PASSWORD" />
<property name="svn_revision" value="HEAD" />
<!-- exports the ${module} from svn and puts it into the ${workdir}/svn_checkout -->
<target name="checkOut">
<exec executable="svn">
<arg line="export ${svn_root} ${workdir}/svn_export -r
${svn_revision} --force --username ${svn_username}
--password ${svn_password}"/>
</exec>
</target>
Using JavaSVN
The JavaSVN Open Source library is
used in several projects for interaction with Subversion. Projects that
use JavaSVN include Subclipse, SmartSVN, and Atlassian JIRA. JavaSVN is
a pure Java Subversion client library.
In the following example I use JavaSVN to access the Subversion repository from a ColdFusion application. It achieves a very simple task: It reads the latest revision from a file in the repository called "test.htm."
The JavaSVN library must be accessible to ColdFusion so I copied javasvn.jar to the Directory "C:\CFusionMX7\wwwroot\WEB-INF\lib\."
Example: getLatestRevision
First we have to initialize the library:
<!--- initialize the library to work with a repository for DAV (over http and https) --->
<cfset CreateObject
("java", "org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory").setup()>
The configuration part is easy; we define the URL to the repository, the user credentials, and the file path:
<!--- configuration --->
<cfset sRepUrl = "http://rocket/svn/projects/trunk">
<cfset sUser = "">
<cfset sPasswd = "">
<cfset sFilePath = "test.htm">
<cfset oSVNURL = CreateObject("java", "org.tmatesoft.svn.core.SVNURL").parseURIEncoded(sRepUrl)>
Next we create a repository driver object and authenticate the user:
<!--- create an SVNRepository driver object --->
<cfset oSVNRepository = CreateObject("java",
"org.tmatesoft.svn.core.io.SVNRepositoryFactory").create(oSVNURL.parseURIEncoded(sRepUrl))>
<cfset oAuthManager = CreateObject("java",
"org.tmatesoft.svn.core.wc.SVNWCUtil").createDefaultAuthenticationManager(sUser, sPasswd)>
<cfset oSVNRepository.setAuthenticationManager(oAuthManager)>
Finally we get the file using the method getFile() and dump the latest revision number for this file:
<cfset oSvnFileprops = CreateObject("java", "java.util.HashMap")>
<cfset oBaos = CreateObject("java", "java.io.ByteArrayOutputStream")>
<cfset oSVNRepository.getFile(sFilePath, JavaCast('long', -1), oSvnFileprops, oBaos)>
<cfset latestRevision = oSVNRepository.getLatestRevision()>
<cfdump var="#latestRevision#">
Please consult the JavaSVN documentation, it contains several other excellent Java samples.
Conclusion
The switch from CVS to Subversion was
quite easy because of the excellent tools and documentation available.
I hope that this article contains some useful information for
developers wanting to switch from CVS or some other version control
system to Subversion. Maybe it will help to convince your boss that
Subversion is the right choice for your team.
Resources