Working with Subversion

Here are some tips for developing GeoNetwork with Subversion, a.k.a. SVN. This is not a guide to Subversion or to version control in general.

Getting the source

If you're starting from scratch and just want to get the latest version of the trunk, make yourself a working directory and change into it. Then run:

svn co https://geonetwork.svn.sourceforge.net/svnroot/geonetwork/trunk

Go to HowToCompile.

Local Subversion mirror

Serious developers, particularly those working in a team, who want to make non-trivial contributions to GeoNetwork may wish to create their own local SVN mirror.

This will enable you to do checkouts, diffs, etc., very cheaply.

Warning: this will take a fair amount of time to do, and there are many opportunities to make mistakes. This really is for serious developers only!

Creating your local mirror

You'll need SVN version 1.5 or later. Follow the instructions in the file svnsync.txt in the SVN source distribution (also viewable at  http://svn.collab.net/repos/svn/trunk/notes/svnsync.txt). For the source repository (i.e., where the instructions refer to http://svn.example.org/source/repos), use http://geonetwork.svn.sourceforge.net/svnroot/geonetwork.

Once your local mirror is set up, run svnsync sync as needed. (For example, you might run this overnight as a cron job.) The beauty of a local mirror is that the revision numbers in your mirror will match the revision numbers of the source SVN repository. For this reason, never ever commit to your local mirror!

Browsing your local mirror

Sourceforge supports browsing the GeoNetwork SVN repository. You can have the same functionality on your local mirror if you install  ViewVC. And of course, once you have installed your own copy of ViewVC, you can customize it as you wish.

Checkouts from the local mirror

You can check out the trunk from your local mirror with:

mkdir /path/to/my/working/directory
cd /path/to/my/working/directory
svn co file:///..../trunk

Checking out a branch works the same way. Once again, never ever commit to your local mirror!

But I want to commit to my local mirror

No you don't. What you can do is to make a mirror of your mirror. Then check out from and commit to that mirror. That way, your main mirror will stay clean.

Is there another way?

Alternatively, use  Git to make a clone of your local SVN mirror, and do your development with Git. This makes it much easier to track upstream development.

Git version 1.5.5.1 or later is recommended. Follow the instructions in the "BASIC EXAMPLES" section of the git-svn man page. In particular, you will probably want to follow the instructions about making an initial Git clone, then cloning the clone to make a working area. Then you will have:

  1. Your local SVN mirror, synchronized with Sourceforge using svnsync but to which no commits are done
  2. A first Git clone of your SVN mirror, synchronized using git svn rebase but to which no commits are done
  3. A working area per developer, each of which is a Git clone of the first Git clone, also synchronized with git svn rebase and to which commits are done.

But note one very important gotcha when using Git in this way. The GeoNetwork source code tree contains a number of empty directories. As of 2008-08-25 they are as follows:

csw/lib/.gitignore
gast/setup/templates/iso19115/.gitignore
jetty/log/archive/.gitignore
src/org/fao/geonet/apps/common/.gitignore
src/org/fao/geonet/schedules/.gitignore
web/geonetwork/WEB-INF/db/data/.gitignore
web/geonetwork/WEB-INF/db/log/.gitignore
web/geonetwork/images/logos/.gitignore
web/geonetwork/xml/codelist/external/thesauri/discipline/.gitignore
web/geonetwork/xml/codelist/external/thesauri/stratum/.gitignore
web/geonetwork/xml/codelist/external/thesauri/temporal/.gitignore
web/geonetwork/xml/codelist/external/thesauri/theme/.gitignore
web/geonetwork/xml/codelist/local/thesauri/discipline/.gitignore
web/geonetwork/xml/codelist/local/thesauri/place/.gitignore
web/geonetwork/xml/codelist/local/thesauri/stratum/.gitignore
web/geonetwork/xml/codelist/local/thesauri/temporal/.gitignore
web/geonetwork/xml/codelist/local/thesauri/theme/.gitignore
web/geoserver/data/validation/.gitignore
web/geoserver/logs/.gitignore
web/geoserver/preview/.gitignore
web/intermap/WEB-INF/classes/.gitignore
web/intermap/WEB-INF/data/tmp/.gitignore
web/intermap/log/.gitignore

Git does not track empty directories, so if you want to run GeoNetwork from your Git working area, you need to create those directories. You might like to try the following:

touch csw/lib/.gitignore
touch gast/setup/templates/iso19115/.gitignore
touch jetty/log/archive/.gitignore
touch src/org/fao/geonet/apps/common/.gitignore
touch src/org/fao/geonet/schedules/.gitignore
touch web/geonetwork/WEB-INF/db/data/.gitignore
touch web/geonetwork/WEB-INF/db/log/.gitignore
touch web/geonetwork/images/logos/.gitignore
touch web/geonetwork/xml/codelist/external/thesauri/discipline/.gitignore
touch web/geonetwork/xml/codelist/external/thesauri/stratum/.gitignore
touch web/geonetwork/xml/codelist/external/thesauri/temporal/.gitignore
touch web/geonetwork/xml/codelist/external/thesauri/theme/.gitignore
touch web/geonetwork/xml/codelist/local/thesauri/discipline/.gitignore
touch web/geonetwork/xml/codelist/local/thesauri/place/.gitignore
touch web/geonetwork/xml/codelist/local/thesauri/stratum/.gitignore
touch web/geonetwork/xml/codelist/local/thesauri/temporal/.gitignore
touch web/geonetwork/xml/codelist/local/thesauri/theme/.gitignore
touch web/geoserver/data/validation/.gitignore
touch web/geoserver/logs/.gitignore
touch web/geoserver/preview/.gitignore
touch web/intermap/WEB-INF/classes/.gitignore
touch web/intermap/WEB-INF/data/tmp/.gitignore
touch web/intermap/log/.gitignore
git add csw/lib/.gitignore
git add gast/setup/templates/iso19115/.gitignore
git add jetty/log/archive/.gitignore
git add src/org/fao/geonet/apps/common/.gitignore
git add src/org/fao/geonet/schedules/.gitignore
git add web/geonetwork/WEB-INF/db/data/.gitignore
git add web/geonetwork/WEB-INF/db/log/.gitignore
git add web/geonetwork/images/logos/.gitignore
git add web/geonetwork/xml/codelist/external/thesauri/discipline/.gitignore
git add web/geonetwork/xml/codelist/external/thesauri/stratum/.gitignore
git add web/geonetwork/xml/codelist/external/thesauri/temporal/.gitignore
git add web/geonetwork/xml/codelist/external/thesauri/theme/.gitignore
git add web/geonetwork/xml/codelist/local/thesauri/discipline/.gitignore
git add web/geonetwork/xml/codelist/local/thesauri/place/.gitignore
git add web/geonetwork/xml/codelist/local/thesauri/stratum/.gitignore
git add web/geonetwork/xml/codelist/local/thesauri/temporal/.gitignore
git add web/geonetwork/xml/codelist/local/thesauri/theme/.gitignore
git add web/geoserver/data/validation/.gitignore
git add web/geoserver/logs/.gitignore
git add web/geoserver/preview/.gitignore
git add web/intermap/WEB-INF/classes/.gitignore
git add web/intermap/WEB-INF/data/tmp/.gitignore
git add web/intermap/log/.gitignore
git commit -m "Add empty .gitignore files for otherwise empty directories"

Then add the following to your top-level .gitignore or .git/info/exclude:

# To not ignore .gitignore files,
# we use xxx/[^.]* instead of just xxx/*

# Directories that are otherwise empty in the upstream SVN respository

csw/lib/[^.]*
gast/setup/templates/iso19115/[^.]*
jetty/log/archive/[^.]*
src/org/fao/geonet/apps/common/[^.]*
src/org/fao/geonet/schedules/[^.]*
web/geonetwork/WEB-INF/db/data/[^.]*
web/geonetwork/WEB-INF/db/log/[^.]*
web/geonetwork/images/logos/[^.]*
web/geonetwork/xml/codelist/external/thesauri/discipline/[^.]*
web/geonetwork/xml/codelist/external/thesauri/stratum/[^.]*
web/geonetwork/xml/codelist/external/thesauri/temporal/[^.]*
web/geonetwork/xml/codelist/external/thesauri/theme/[^.]*
web/geonetwork/xml/codelist/local/thesauri/discipline/[^.]*
web/geonetwork/xml/codelist/local/thesauri/place/[^.]*
web/geonetwork/xml/codelist/local/thesauri/stratum/[^.]*
web/geonetwork/xml/codelist/local/thesauri/temporal/[^.]*
web/geonetwork/xml/codelist/local/thesauri/theme/[^.]*
web/geoserver/data/validation/[^.]*
web/geoserver/logs/[^.]*
web/geoserver/preview/[^.]*
web/intermap/WEB-INF/classes/[^.]*
web/intermap/WEB-INF/data/tmp/[^.]*
web/intermap/log/[^.]*

# Files created as a result of building GN

gast/gast.jar
web/geonetwork/WEB-INF/lib/geonetwork.jar
web/geonetwork/WEB-INF/lib/oaipmh-lib.jar
web/intermap/WEB-INF/lib/intermap.jar

# Files created or updated as a result of running GN

gast/log/gast.log*
web/geonetwork/WEB-INF/data/*
web/geonetwork/WEB-INF/removed/*
web/geonetwork/schematronCache/????????-????-????-????-????????????.*
web/geonetwork/xml/repositories.xml
web/geonetwork/xml/schema-mappings.xml