Subversion Techniques

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-release-branch.

From the beginning of the release process for R-x.y.0 the two versions work towards


Version      Name                 Branch
---------------------------------------------
R-x.(y+1).0  r-devel           [none]
R-x.y.z      r-release-branch  R-x-y-branch
The "Branch" column refers to the Subversion branch name. The logic is that all releases (R-x.y.z, z>=0) are made from the branch named "R-x-y-branch".

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 the release 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=~ #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 release branch

(aka "r-release-branch")

cd $RTOP
svn co $REPOS/branches/R-2-4-branch r-release-branch/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-4-branch

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-release-branch

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. However, for a simple changeset we can use a simpler notation, -c 140. (This requires svn >= 1.4.0.)

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


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

cd $RTOP/r-release-branch/R
svn merge -c 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'

To back out a simple changeset, use a negated number, e.g. svn merge -c -140 ...

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-4-branch

cd $RTOP/r-devel/R
svn merge -c 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 change r140 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.

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

Release procedures

This is now handled almost automatically by various scripts, which can be found on the developer page. Briefly, there are two build scripts, one for pre-releases and one for the final build. The former are run every morning during the run-in period by a cron job. Two auxiliary scripts set up the new relelase branch (needed for x.y.0 releases) and the intermediate version changes.