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
Checkout
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,
svn+ssh://p-quarknet@cdcvs.fnal.gov/cvs/projects/quarknet/branches/4.0-ND-dev
would become
^/branches/4.0-ND-dev
for short.
Commit
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 131.225.108.132: Broken pipe
svn: E210002: Network connection closed unexpectedly
131.225.108.132 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.
References
-- Main.jgriffith - 2016-03-04