Apache Subversion (SVN)

Subversion (SVN) is a powerful, centralized version control system that stores source code and allows changes to it to be tracked over time. It largely replaced the earlier Concurrent Versions System (CVS) and was highly popular at the time most of the e-Labs were first developed, though as of 2017 SVN itself has been overtaken in popularity by Git.

The best source for general information on SVN is the book Version Control with Subversion written by its creators. The link given is for version 1.7; search around if you need a different version.

You can determine what version of SVN you have installed with
$ svn --version

Developer's Quick Reference

Repository web interface

Initial checkout
$ svn co svn+ssh://p-quarknet@cdcvs.fnal.gov/cvs/projects/quarknet/(branches | trunk | tags)

Show changes to working copy
$ svn status

Update working copy with changes to repo
$ svn update

Commit changes to repo
$ svn update
$ svn commit -m "brief explanatory message" (one/edited/file another/edited/file)

Installing SVN

See the Local Setup Guide: Installing SVN

Using SVN


The single official version of the source code for the e-Lab webapps is stored on a server at Fermilab in the form of an SVN repository. This source code is open and public: anyone can browse it, and anyone can download the full code.

The SVN command for the public to checkout a working copy of the repository is

$ svn checkout http://cdcvs.fnal.gov/subversion/quarknet/(branches | trunk | tags)

This is what the deployment script internal-deploy-from-svn uses. Code checked out via this URL cannot be re-committed to the repo, however! Obviously, we don't want the public to be able to change our source code.

Instead, developers with Kerberos/SSH access to the project should use (after $ kinit !)
$ svn co svn+ssh://p-quarknet@cdcvs.fnal.gov/cvs/projects/quarknet/(branches | trunk | tags)

(co is identical to checkout, just shorthand). Using this URL will download a working copy of the repository (or that portion of it that you specify in the URL) to your current working directory, and it will allow you to commit your changes to that working copy back to the repo later. For example, if you want to check out the most current development branch (as of Jan 2017), you would use
$ svn co svn+ssh://p-quarknet@cdcvs.fnal.gov/cvs/projects/quarknet/branches/4.0-ND-dev

When you checkout code from the repository, SVN remembers the URL so that you don't need to specify it when you issue svn commands from within your local working copy. If you do need to refer to the repo URL in an svn command, you can use a caret ^ in place of the URL root http://cdcvs.fnal.gov/subversion/quarknet/ or svn+ssh://p-quarknet@cdcvs.fnal.gov/cvs/projects/quarknet/. Thus,

would become
for short.


The command
$ svn status
shows a list of all files in your working copy that you've modified (M) or which have certain irregularities (?).

The command
$ svn update
takes the updated files in the repository and applies these changes to your working copy if and only if these changes don't affect any files you've edited. If another developer has altered a repository file that you've also edited in your working copy, the output of $ svn update will alert you to this, and you'll typically have to resolve the conflict manually.

If you have edited code in your working copy that's ready to be uploaded into the repository, you can commit it with the command

$ svn commit -m "brief explanatory message"

The -m flag indicates a message that explains what you're changing and which will be recorded with your commit. SVN requires you to submit a message; if you don't, it will usually throw an error as it attempts to open a text editor for you to do so. The message is enclosed in double quotes.

If you only want to commit certain files, you may add their filepaths relative to the current directory as additional arguments (any number of them) after the message. If you don't, SVN will commit every file that you've modified.

Always update before you commit. If you don't, you might overwrite another developer's work in the repository. Get into the habit of updating regularly while working with SVN repositories.

ELabs Repository Structure

The /trunk /branches /tags layout of the root directory is conventional with SVN. In principle, the main version of the code is stored in the trunk, while branches contain provisional repositories for various stages of development.

Somewhere along the line, though, we stopped using the trunk and work instead only with branches, with the main production branch (what would ordinarily be the trunk) as branches/4.0-ND-prod as of Jan 2017. Rather than trying to restore a standard SVN repository structure, though, I (Joel) plan to just move the whole thing to Git sometime in 2017.

There are many branches in the repository. Most are unused. For example, you'll see

  • 3.0-rollout
  • 3.0-rollout-test
  • 3.0-test
  • 3.1
  • 4.0-ND-dev
  • 4.0-ND-prod

The 4.* group are the current primary branches (2017), created by Edit for deployment to the ELabs servers at Notre Dame. 4.0-ND-dev is for deployment to the development machine i2u2-dev.crc.nd.edu, while 4.0-ND-prod is for deployment to the production machine i2u2-prod.crc.nd.edu.

The test branch is also occasionally used.

The 3.* group was for deployment to ELabs servers at Argonne. 3.0-test was for deployment to the development machine www13.i2u2.org, now retired. 3.0-rollout and 3.0-rollout-test were for deployment to the production machine www18.i2u2.org (retired Jan 2016).

Branches 3.0 and prior are legacy code. There's no reason for you even to check them out to your local working copy. We haven't deleted them mostly because disk space is cheap and Fermilab's problem.

The other branches were Edit's.

Nonstandard tasks in SVN

Revert a file

If you need to change a file back to an earlier form, use a reverse merge. Say the current revision is N and you want a file example.jsp instead to have the same content it had at revision M, M<N. From the root directory of your working copy,
$ svn update
$ svn merge -r N:M ^/repository/filepath/example.jsp ./working/copy/filepath/example.jsp

For example,
$ svn update
$ svn merge -r 8706:5800 ^/branches/4.0-ND-dev/i2u2/about-us.jsp ./i2u2/about-us.jsp
will revert a copy of about-us.jsp that's currently at rev 8706 into the form it had at rev 5800.

Always update first so that example.jsp is sure to be at revision N. The reverse merge will replace your working copy's example.jsp with that of revision M. If everything looks like you expect it to in the working copy, commit this revision to the repository:

$ svn commit -m "reverting file to rev M" ./working/copy/filepath/example.jsp

Undelete a file

When recovering a deleted file from an earlier version of the repo, you can't use a reverse merge as above because there's no target file to apply the diff to - it's been deleted! Instead, svn copy does the trick. If the file existed as you'd like to restore it in (for example) revision 5800, the command
$ svn copy ^/path/to/file/in/repo/filename@5800 ./path/to/file/in/working/copy/filename
will restore it into your working copy with its full history. As with a merge, you must commit this change once you're satisfied with it to return the deleted file to the repo proper.

Change source URL

When editing a working copy, SVN remembers the URL that you originally checked it out from. If you accidentally checked out using the "public" URL and find yourself unable to commit,

  svn switch --relocate http://cdcvs.fnal.gov/subversion/quarknet svn+ssh://p-quarknet@cdcvs.fnal.gov/cvs/projects/quarknet

should work to edit SVN's memory so that it considers the "private" URL to be the origin of the working copy. I haven't tried it, though.

Copy the repository into a local repository

Note that this is different from creating a working copy of the remote repository. The instructions here will create an entirely new repository out of the existing one. Its repository controls and versioning history and checked-out working copies will be entirely independent of the original repository.

There are a couple methods of doing this:

1) svnrdump - I couldn't get this to work

2) svn export/import

The command svn export takes a repository or a working copy of one and exports it into an ordinary directory tree filled with files; i.e., the resulting fileset is free from all repository controls and versioning history and has nothing whatsoever to do with SVN, just like any other directory in your filesystem.

Exporting from a repository and from a working copy are slightly different. To export,
$ svn export [-r revision#] <respository source URL> <destination directory>

For example, to export revision #101 of the branch /branches/4.0-ND-dev to the local (OS X) directory /Users/<username>/local-repo-files/,

$ svn export -r 101 http://cdcvs.fnal.gov/subversion/quarknet/branches/4.0-ND-dev /Users/<username>/local-repo-files

Specifying a revision (or range of revisions) using the -r flag is optional, but I think SVN exports the entire revision history if you don't, so I recommend using it. Also, note that since the output will be a non-SVN object that will never be subject to version control or committing, it's fine to use the simpler http:// checkout protocol rather than the svn+ssh:// protocol (though there should be no problem with the latter) (remember to kinit first if you try it, though).

Exporting from a working copy on your own machine is similar, except that the source is given by a directory filepath rather than the URL of the SVN server:

$ svn export -r 101 /Users/<username>/working-copy /Users/<username>/local-repo-files

where working-copy/ is the location of your working copy of the repository.

Side note: Even though the previous method exported from one local directory to another on my own computer, at one point the process hanged and eventually terminated with

  packet_write_wait: Connection to Broken pipe
  svn: E210002: Network connection closed unexpectedly is the front page of the SVN server at Fermilab. I have no idea why, but exporting local-to-local still seems to require connection to the original repository. FYI.

Now that you have an ordinary directory tree of the repository's fileset in local-repo-files/, you can svn import these files into a new repository. So, first create the repository:

$ svnadmin create /Users/<username>/local-repo

(this is just an example. You can put it anywhere you want, under any name you want.)

Importing the directory into the fresh repository happens with

$ svn import -m "introductory message" <source directory> <destination repository URL>

You're required to provide a message marking the importation of the new files, just as with a commit. For example,

$ svn import -m "Copying 4.0-ND-dev 101" /Users/<username>/local-repo-files file:///Users/<username>/local-repo

Note that the destination must be a URL. If you're importing locally, then, you should use the file:// protocol. Also, since the URL is given with reference to the root directory /, the three slashes in file:///Users/ is correct as given. You should now have a new, independent version of the original repository.

Be aware that, even after import, the file directory local-repo-files/ remains NOT a working copy and is NOT under SVN control. You can delete it, if you like. If you'd like to work with the files of the new repository in a version-controlled manner, you'll need to perform a checkout from your new repo.


-- Main.jgriffith - 2016-03-04
Topic revision: r7 - 2019-05-22, AdminUser
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback