Subversion Techniques

NB: These instructions are not well tested. Use them with care!

This info is for reference to the core developers. Use of anonymous Subversion for outsiders is not explicitly covered here, but for now and as long as the load on the server remains manageable, will be identical, with the exception that only core developers can commit changes.

We assume that Subversion is installed and basic Subversion techniques are understood; for background information, Version Control with Subversion provides an excellent reference. One of its authors has also put together The Top Ten Subversion Tips for CVS Users which is very helpful.

Preliminaries

There are two main development branches for R. For reference, we call them r-devel, and r-patched.

After the release of R-x.y.z the two versions work towards


Version      Name            Branch
-----------------------------------------
R-x.(y+1).0  r-devel         [none]
R-x.y.(z+1)  r-patched       R-x-y-patches
The "Branch" column refers to the Subversion branch name. The logic is that patch releases (R-x.y.z, z!=0) are made from the branch named "R-x-y-patches", whereas normal releases (R-x.y.0) are made from the "trunk".

NB: In contrast to what we did under CVS, under Subversion we will do the following:

  1. Where possible, develop all changes on the trunk, even bug fixes, and commit them there first.
  2. When a change meets the development guidelines for inclusion in r-patched, port it from the trunk to the branch.

In what follows, I use the reference names also as directory names. All developers are encouraged to use the same names, to provide us with a common reference.

Checking out a development branch

(By a development branch, I mean either the trunk or patch branch.)

I shall assume the bash shell in the following, for simplicity, and create the three development directories under $RTOP.


export REPOS=https://svn.r-project.org/R
export RTOP=~/R-devel #adjust as necessary

The trunk revision

(aka "r-devel")

cd $RTOP
svn co $REPOS/trunk r-devel/R

The checked out directory will be called "$RTOP/r-devel/R". Change the "r-devel/R" argument to call it something else.

Current patch branch

(aka "r-patched")

cd $RTOP
svn co $REPOS/branches/R-2-0-patches r-patched/R

Checking out a specific release version

Release versions are labeled with a tag of the form R-1-2-3. (For obscure reasons, non-patch versions up to R-1.3.0 were labeled R-1-3 and not R-1-3-0. This was changed starting with R-1.4.0.). You can check out an old version simply with

svn co $REPOS/R/tags/R-1-2-3 R

Notice that release versions are under the tags directory, not the branches directory. You should not change a released version and commit the changes back, but unlike CVS, Subversion will not prevent you from doing this. If you do it accidentally, please undo your change immediately.

Updating

To update a source tree with the latest changes, just go to the relevant top-level directory (e.g. $RTOP/r-devel/R) and say

svn up

If you have uncommitted changes that conflict with other updates, you will need to fix the conflicts and call svn resolved to tell Subversion that they are fixed before you'll be able to commit that file.

If you want to make completely sure that the files come from a given branch, use svn switch https://svn.r-project.org/R/branches/somebranch.

If you are on a slow connection, you can also use the switch command instead of doing a new checkout, e.g.

svn switch $REPOS/R/branches/R-2-0-patches

To switch to the trunk revision from a branch revision, use

svn switch $REPOS/R/trunk

I do not know if Subversion is capable of getting things wrong, e.g. if interrupted in the middle of an update.

Committing

To put your modified versions back in the repository, just say svn commit -m'describe change' FILE1 FILE2 ...

or just

svn commit

in which case all changes in the current working directory will be committed, and you'll be asked for a change comment.

Notice that commits work on the trunk, branch and tag revisions, but they should never be made on the tags. Tags represent the status of the files at a given time in the past and should not be changed.

Porting patches from r-devel to r-patched

Almost all changes should be made on the r-devel trunk first. After testing and committing them there, bug fixes and some other minor changes should be ported to the r-patched branch. Make note of the revision number of your commit to the trunk. For example,


$ commit -m'Sample commit'
Adding         tests\added.file
Sending        tests\minitab.R
Transmitting file data ..
Committed revision 140.
was revision 140. The changeset you want is -r 139:140, i.e. the changes between r139 and r140.

Change to the r-patched directory, merge your changes, check and fix any conflicts, and commit.



export REPOS=https://svn.r-project.org/R
export RTOP=~/R-devel #adjust as necessary

cd $RTOP/r-patched/R
svn merge -r 139:140 $REPOS/trunk
svn status # Look for C, indicating a conflict

	# fix conflicts... (remember to use svn resolved for each)

svn commit -m 'ported r140 (sample changes to tests) from trunk'

Updating from r-patched to r-devel, specific changes

If revisions are made on the r-patched branch that should have been made to r-devel, then just follow the same procedure as above, but merge the changes in the opposite direction. Assuming r140 was made to the branch instead of the trunk:


export REPOS=https://svn.r-project.org/R
export RTOP=~/R-devel #adjust as necessary
export TAG=R-2-0-patches

cd $RTOP/r-devel/R
svn merge -r 139:140 $REPOS/branches/$TAG
svn status # Look for C, indicating a conflict

	# fix conflicts... (remember to use svn resolved for each)

svn commit -m 'merged r-patched changes r139:140 into the trunk'

Updating from r-patched to r-devel, entire tree

This procedure should never be necessary, and is not safe, in that the last-patch-update tag is not normally maintained.

Making releases

Dot-release (x.y.0)


REPOS=https://svn.r-project.org/R
MAJOR=2
MINOR=1
PL=0
NEWMAJOR=2
NEWMINOR=2
TAG=R-$MAJOR-$MINOR-$PL
BRANCHTAG=R-$MAJOR-$MINOR-patches
REL=R-$MAJOR.$MINOR.0
OREL=R-2.0.1
echo -e "TAG=$TAG\nREL=$REL\nOREL=$OREL"

## FIXME: use RTOP=...; BASEDIR=$RTOP/r-devel and get rid of "BASEDIR/.."
BASEDIR=/usr/local/src/pd/r-devel
SRCDIR=$BASEDIR/R
BUILDDIR=$BASEDIR/BUILD-dist

DISTDIR=$HOME/public_html/R-release

umask 0022

cd $BASEDIR
rm -rf $SRCDIR $BUILDDIR
svn checkout $REPOS/trunk $SRCDIR
	#-- set/check version number and release status:
cd $SRCDIR
tools/rsync-recommended
echo $MAJOR.$MINOR.$PL > VERSION

# FIXME aclocal/autoconf *still* do not work with SuSE
#aclocal
#autoconf

# FIXME There's no suitable javac on SuSE
touch doc/html/search/*.class 

mkdir $BUILDDIR
cd $BUILDDIR
$SRCDIR/configure --enable-maintainer-mode --prefix $BASEDIR/$REL
make && make check-all && make install 

cd $SRCDIR
svn update # watch out for merges!
svn commit -m 'preparing for release'

svn cp -m'Creating build tag' $REPOS/trunk $REPOS/tags/$TAG
svn cp -m'Creating patch branch' $REPOS/tags/$TAG $REPOS/branches/$BRANCHTAG

cd $BASEDIR/..
rm -rf r-patched
mkdir r-patched
cd r-patched
svn checkout $REPOS/branches/$BRANCHTAG R

cd $BUILDDIR
make dist
cp $REL.tar.gz $DISTDIR
cd $SRCDIR
cp README INSTALL NEWS ONEWS OONEWS COPYING COPYING.LIB $DISTDIR

cd $DISTDIR
rm *split* # Don't keep these around forever...
split -b 1400k $REL.tar.gz $REL.tar.gz-split.
ln -f $REL.tar.gz R-latest.tar.gz # webserver needs hard link

#	-- set release numbers on release and devel. versions

cd $SRCDIR
echo $NEWMAJOR.$NEWMINOR.0 "Under development (unstable)" > VERSION
svn commit -m 'prepare for next version' VERSION

cd $BASEDIR/../r-patched/R
echo $MAJOR.$MINOR.0 "Patched" > VERSION
svn commit -m 'prepare for next version' VERSION

# Finally, update the developer homepage with new version info
# Make announcement on R-announce
# ------------ All done --------------

Dot-dot release (x.y.z)


	# Exec the following and check carefully:

REPOS=https://svn.r-project.org/R
MAJOR=2
MINOR=0
PL=1
        # This works for PD on "turmalin"
DISTDIR=~/public_html/R-release
RPATCHED=/usr/local/src/pd/r-patched
SRCDIR=$RPATCHED/R
BUILDDIR=$RPATCHED/BUILD-dist

OPL=$[PL-1]
VERSION=$MAJOR.$MINOR.$PL
OVERSION=$MAJOR.$MINOR.$OPL
TAG=R-$MAJOR-$MINOR-$PL
REL=R-$VERSION
OREL=R-$OVERSION
DIFF=R-$OVERSION-$VERSION.diff
echo -e "TAG=$TAG\nREL=$REL\nDIFF=$DIFF"

	# go to the patched directory and clean up
cd $RPATCHED
rm -rf $SRCDIR $BUILDDIR
svn checkout $REPOS/branches/R-$MAJOR-$MINOR-patches R
cd $SRCDIR
tools/rsync-recommended
	#-- set/check version number and release status
echo $MAJOR.$MINOR.$PL  > VERSION
autoconf

mkdir $BUILDDIR
cd $BUILDDIR

($SRCDIR/configure --enable-maintainer-mode --prefix $RPATCHED/$REL ;\
make &&  make check-all && make install) | tee make.log

cd $SRCDIR
svn update # Hopefully, no changes at this point...
svn commit -m "prepare for release $REL"

#---- at specified time:

svn update  # watch out for last minute merges - make check if necessary!
cd $SRCDIR
svn cp -m "Tag version $REL" $REPOS/tags/$TAG

cd $BUILDDIR
make dist
cp $REL.tar.gz $DISTDIR
cd $SRCDIR
cp README INSTALL RESOURCES NEWS ONEWS $DISTDIR

cd $DISTDIR
split -b 1400k $REL.tar.gz $REL.tar.gz-split.
ln -sf $REL.tar.gz R-latest.tgz

#---- Setup for patch tree

cd $SRCDIR
echo $MAJOR.$MINOR.$PL Patched  > VERSION
svn commit -m "setup for patched versions"

# Finally,
#    Update the developer homepage with new version info
#    Make announcement on R-announce
# ------------ All done --------------

Handling experimental branches

Suppose you want to have a branch to hold your volatile changes, let's say R-Tk. We'll keep a file recording when we did merges from the trunk, but the information is all available in the log if this file gets lost.

(A) Creating the branch
    ===================

export REPOS=https://svn.r-project.org/R

mkdir r-experimental
cd r-experimental
svn cp  -m'Create R-tk' $REPOS/trunk $REPOS/branches/R-Tk >R-Tk-updates
cat R-Tk-updates   # Keeps a record of revision numbers when your branch was last in sync with the trunk

svn checkout $REPOS/branches/R-Tk/R R

(B) Hacking on the branch
    =====================

Just like on the release branch:

svn update
#..hack, hack, hack....
svn commit -m'hacked blah'

(C) Updating from r-devel (aka "main trunk")
    ========================================

tail -1 R-Tk-updates   # Find when we did our last merge, e.g. r141
svn log -r HEAD $REPOS   # Find the HEAD revision, e.g. r143

svn merge -r 141:143 $REPOS/trunk
# resolve conflicts if any
svn commit -m 'ported r141:143 from main'
echo merged to r143 >>R-Tk-updates   # Save the revision number, for the next merge

(D) Merging the hack back into r-devel
    ==================================

head  R-Tk-updates  # look up the revision number when we created the branch, e.g. r141
cd ~/r-devel/R
svn info # find the current revision number of the repository, e.g. r143
svn merge -r 141:143 $REPOS/branches/R-Tk # resolve conflicts if any
svn commit -m'merged Tk branch r141:143 into trunk'

(E) All done, so clean up
    ==================================

svn delete -m'Deleting R-Tk' $REPOS/branches/R-Tk

(F) Oops, more work to do on R-Tk: resurrect it
    ==================================

svn log -v $REPOS/branches | grep -B 2 R-Tk # look up when it was deleted (in r144)

svn copy -m'Resurrecting R-Tk branch' -r 143 $REPOS/branches/R-Tk $REPOS/branches/R-Tk