SVN getting started

The complete reference for SVN is the svn red book.

Basics

SVN is used from a terminal program and allows you to checkout a repository of code for use and editing locally on your machine. If you prefer a GUI you might try Cornerstone.

If you are simply using a repository without making any changes, you should at least be familiar with using the commands: checkout and update.

If you are making changes, then you should be familiar with the commands: commit, status, log, diff, add and delete.

Checkout

To first checkout a repository, you will have used svn checkout, for example:

svn checkout http://gru.brain.riken.jp/svn/mgl/trunk mgl

This will create a directory containing all the files in the repository on your local machine. You may use and edit this repository as much as you like without affecting others. Note that you can put the repository into any directory name that you want, for example:

svn checkout http://gru.brain.riken.jp/svn/mgl/trunk mymgldir

Update

To get updates from the repository, you can do:

svn update

You can choose to update the whole repository by using the above, or individual directories or files:

svn update filetoupdate.m

Status

To see what you have changed in your working copy of the repository, you do:

svn status

This will give you a list of files that are changed, it will look something like this:

?      task/someFileNotInTheRepository.m
M      mgllib/modifiedFile.m

The ? means that the files is not in the repository. The M means that you have modified the file. These are the most common codes you will see, but there are other codes as well, to see them you can do (Note that you can get help on all commands this way):

svn status --help

If you want to get what changes have been made in the repository as well as your own changes in your working directory (i.e. this will let you know what files will be modified when you do an svn update):

svn -u status

Diff

To see what your modifications are, you can do a diff between your version and the version in the repository:

svn diff modifiedFile.m

This will list all modifications – I find it hard to read, but lines beginning with “-” are lines that are removed in your version and line beginning with “+” are lines you have added.

Commit

If you want to commit your changes to the repository (this will make them available to all others using the repository (or if you are the only one using the repository, will save that as a version that you can always retrieve):

svn commit

This will bring up whatever editor you have specified in your environment. It appears on MAC OS X it looks at the variable VISUAL (though one would think it should be EDITOR):

setenv VISUAL /Applications/Emacs.app/Contents/MacOS/Emacs

You can also commit without bringing up the editor by specifying the message in the commit command:

svn commit -m "My commit message"

Log

To see a log of everything that has happened to a file, you can do:

svn log filename.m

Add

To add a file to the repository:

svn add newFilename.m

Note that after you run this command, if you want the file to actually be added, you will have to svn commit.

Delete

To delete a file from the repository:

svn delete filenameToDelete.m

Again, svn commit to make the actual change. Note that it is possible to retrieve a deleted file from the repository if for some reason you need it later. SVN will take care of deleting the file in your directory as well, so no need to rm the file.

Resolving conflicts

File conflicts

These happen when two people edit the same file and try to commit and svn does not know how to merge the changes (this only happens when changes in the text are in conflict with each other, for edits that are far away in the file, svn usually can merge the changes without conflict). If it can't you have to go into the file and edit which version you want. Look for areas with:

<<<<<<< filename
your changes
=======
code merged from repository
>>>>>>> revision

and edit it so only the version you want exists.

Tree conflicts

local delete, incoming edit upon update

These happen when you are deleting/moving files and there is a conflict with another file. You might get something like this:

D     C filename.m
      >   local delete, incoming edit upon update

It means that you are trying to delete a file that someone else has updated and svn does not know what to do. In this case, you might (after copying your local version somewhere else if you want to make sure to have a copy), try

svn revert filename.m

Which reverts all local changes to a status before you did anything. THen svn update and try doing the delete again if necessary.

working copy locked

Sometimes if you crash out while doing an svn commit or update, you can get “stale locks” with the message “working copy locked”. To fix this, run:

svn cleanup

Using FileMerge to resolve conflicts

You can use FileMerge to visually resolve conflicts. To set this up, you need to do the following:

  1. Install the script below somewhere in your path and call it fmmerge
    #!/bin/sh
    
    #
    # Wrapper script to use FileMerge as a merge-tool-cmd in Subversion
    #
    
    FM="/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge"
    FMDIFF="$(basename $0)"
    GN="/usr/local/bin/growlnotify"
    
    while [ $# != 0 ]; do
    echo $1
            case $1 in
                    -*)
                            echo "Unknown option: $1" 1>&2
                            exit 1
                    ;;
                    *)
                            if [ -z "$ancestorfile" ]; then
                                    ancestorfile="$1"
                            elif [ -z "$leftfile" ]; then
                                    leftfile="$1"
                            elif [ -z "$rightfile" ]; then
                                    rightfile="$1"
                            elif [ -z "$mergefile" ]; then
                                    mergefile="$1"
    #                       else
    #                               echo "Too many files to start merge" 1>&2
    #                               exit 2
                            fi
            esac
            shift
    done
    
    if [ -z "$ancestorfile" ] || [ -z "$leftfile" ] ||
              [ -z "$rightfile" ] || [ -z "$mergefile" ]; then
            echo "Usage: $0 [options] oldfile yourfile myfile outputfile" 1>&2
            exit 2
    fi
    
    echo Starting FileMerge... 1>&2
    [ -x "$GN" ] && "$GN" -a FileMerge -n "$FMDIFF" -m "$mergefile" "Starting FileMerge"
    
    exec "$FM" -left "$leftfile" -right "$rightfile" \
            -ancestor "$ancestorfile" -merge "$mergefile"

    This is a slightly modified version of the original which did not work for me since svn mysteriously called it with five input arguments.

  2. Edit your ~/.subversion/config file to have the following line (I think it can be anywhere in the file, but you may want to put at the end of the [helpers] section).
    merge-tool-cmd = /usr/local/bin/fmmerge

    Make sure to change the path correctly to the location of the function you created above.

  3. When you get a conflict, you will see the following
    Select: (p) postpone, (df) diff-full, (e) edit,
            (mc) mine-conflict, (tc) theirs-conflict,
            (s) show all options: l   

    Choose l (launch) and it will now run FileMerge!

  4. If you are happy with the changes that you have made in FileMerge, save and quit and then you will see
    Select: (p) postpone, (df) diff-full, (e) edit, (r) resolved,
            (mc) mine-conflict, (tc) theirs-conflict,
            (s) show all options: r

    Choose r (resolve) and you are done. You will need to commit your changes.

Create a repository

To create a repository, go to the svn directory on the server:

ssh -l justin gru.brain.riken.jp
cd /Library/WebServer/svn

Then make the repositiory

svnadmin create repositoryName

Then make sure it has permissions that are readable by the web server (you may need to be root to do this):

chown -R www repositoryName

That's it. To checkout the repository on another computer, do:

svn checkout http://gru.brain.riken.jp/svn/repositoryName

Move a repository

To move a repository, you first move the repository on the server side. If you are just changing names or the directory of the repository, simply mv the repository. If you are moving from one server to another you dump the contents to a temporary file, create the new repository and restore the contents from the temp file:

svnadmin dump /path/to/repository > repository-name.dmp
cd /path/to/new-repository
svnadmin create repository-name
svnadmin load repository-name < repository-name.dmp

After you have moved the repository, you will need to update any checked out repositories with the new path:

svn switch --relocate oldRepositoryAddress newRepositoryAddress

To make sure that the switch above worked you can either test it (modify file and try to commit), or get info:

svn info

Which will tell you the repository root (which should reflect the new repository location).

SVN branch & merge

To create a branch, you use the copy command. For all of our projects we have a trunk directory (main development – this is the branch everyone is using, so be very careful when making changes here) and a branches directory (temporary development, good for when you want to make some local changes without affecting anyone else). If you want to make yourself a new branch, then you can issue an svn copy command (change dev to a name of your choice):

svn copy https://cbi.nyu.edu/svn/mrTools/trunk https://cbi.nyu.edu/svn/mrTools/branches/dev

Note the https, rather than the http. For some reason, for copies, you must use the https secure site, and it will ask you to accept a certificate. You should accept it permanently. Also, you will need to be a developer with write privileges (ask Valerio for mrTools).

Once you have made a copy, check it out (again replace dev with the name of your choice)

svn checkout https://cbi.nyu.edu/svn/mrTools/branches/dev mrTools-dev

Now you can use this local repository like any other repository. Make edits, update and commit.

When you are done making and committing your changes, you should merge the development branch back to the trunk (the main version of the repository). You do this by issuing an svn merge command. First cd to your local version of trunk (i.e. main development branch of mrTools that everyone is using). The merge command will then take all of your changes in the dev branch, compare them to what is in the trunk repository and merge them into your local working copy of the trunk:

cd ~/proj/mrTools
svn merge https://cbi.nyu.edu/svn/mrTools/trunk https://cbi.nyu.edu/svn/mrTools/branches/dev .

Note that the command takes the main trunk version of the repository, then the changes that you want to apply from your development repository and then finally the local repository where you want the changes to be applied. You should see something like this:

U    mrLoadRet/mrGlobals.m

If you had changed the mrGlobals.m file, for example. Your changes have not been committed yet though. They are still local changes. To commit them you simply do a commit

svn commit

But, if you decide something very bad happened, and you don't want to merge your changes in after all, you can always revert your local trunk repository (this will delete all of your local changes – be careful! If you had other changes in your mrTools main repository that you wanted to keep, those will be lost):

svn revert -R .

Finally, when you are done with your branch, you can delete it:

svn delete https://cbi.nyu.edu/svn/mrTools/branches/dev

Binary files

SVN should handle binary files just fine. However, sometimes the wrong property can be set on a binary file which causes the file to get munched. Usually this is because svn wrongly has the “eol-style” set. This should only be set for text files, it handles differences in EOL characters between PC, UNIX and Mac files, but will cause problems on binary files. To check whether it has been set, you do:

svn proplist binaryfile.mexmac

If it looks like this, you are good:

Properties on 'binaryfile.mexmac':
  svn:executable
  svn:mime-type

But, if it looks like this, you will need to svn delete/commit and then add/commit back the file:

Properties on 'binaryfile.mexmac':
  svn:keywords
  svn:eol-style

Retrieving deleted or old version of files

First you need to go find what version, you want. Probably easiest is to go look at the log:

svn log

and then note which revision (rxx) number you want. Once you know that you can look at (but this won't add the version back!) a copy of that file, by doing e.g. (if you wanted revision 32):

svn update -r32 fileToGetOldVersionOf.m

Note that as soon as you update again (svn update) that local old copy will be removed and you will revert back to the latest version. To retrieve the file permanently, you will need to copy it from the repository:

svn copy -r32 http://gru.brain.riken.jp/svn/mgl/trunk/mgllib/mglOpen.m mglOpen.m

Then you will need to commit the changes.

Retrieving a single file

If you just want to get a single file out of the repository (this will not allow you to check the file back in):

svn export http://gru.brain.riken.jp/svn/matlab/filename

SVN Setup

svn vis ssh setup

In .ssh/config, add the following:

host yoyodyne
  Hostname localhost
  Port 7777
  ForwardAgent no
  ForwardX11 no

To checkout over ssh:

svn co svn+ssh://gru.brain.riken.jp/Library/WebServer/svn/mgl/trunk mgl

To checkout over http:

svn co http://gru.brain.riken.jp/Library/WebServer/svn/mgl/trunk mgl

To checkout from file:

svn co file://gru.brain.riken.jp/Library/WebServer/svn/mgl/trunk mgl

SVN setup

Add this line to load the svn module in httpd.conf

LoadModule dav_svn_module libexec/apache2/mod_dav_svn.so

And these lines to set up the svn hosting in /etc/apache2/httpd.conf

<Location /svn>                                                                                                                             
  DAV svn                                                                                                                                   
  SVNParentPath /Library/WebServer/svn                                                                                                      
  # how to authenticate a user                                                                                                              
  AuthType Basic                                                                                                                            
  AuthName "Subversion repository"                                                                                                          
  AuthUserFile /Library/WebServer/svn/.htaccess                                                                                             
                                                                                                                                            
  <LimitExcept GET PROPFIND OPTIONS REPORT>                                                                                                 
    Require valid-user                                                                                                                      
  </LimitExcept>                                                                                                                            
</Location>     

To test, go and make a repository in /Library/Webserver/svn:

svnadmin --fs-type fsfs create deleteme
chown -R www deleteme

Then try to check it out:

svn checkout http://gru.brain.riken.jp/svn/deleteme

HTTP service update on server

Sometimes mac software updates overwrite files relate to http and make svn malfunctioned. Last time, svn didn't work after the updating with giving an error as following,

 >svn update grubin
 svn: OPTIONS of 'http://gru.brain.riken.jp/svn/grubin':​ 200 OK (​http://gru.brain.riken.jp)​

In this case, simply edit /etc/apache2/httpd.conf file as superuser. You will find that all svn set to “off”, so change “off” to “svn”

DAV off —> DAV svn

and restart http service by following command as superuser (or with sudo).

 >/usr/sbin/apachectl restart

Passwords for SVN

Make a password file somewhere:

htpasswd -cm .htaccess justin

Subsequent passwords get added without the -c flag:

htpasswd -m .htaccess user2