Subversion on OS X

I wrote this as an aide-memoire, as I use subversion, but not quite enough for it to become totally instinctual - and I found myself having to look stuff up multiple times. The bulk of this article should work for any install of subversion, the detail about starting a local repository is OS X specific, as is the bit about upgrading.

What is Subversion?

Subversion is a programme for managing files. When you create a project, which could be programming, writing or anything, you will make changes. Sometimes your changes will be bad and you will want to 'roll them back'. Sometimes you will want to work on a project with someone else. Subversion allows both of these things (and many more). I use subversion for my own projects so that if I mess up, I can go back to a previous working copy.

All changes in a subversion repository are stored - so it keeps your working copies tidy without loss of information.

Getting Subversion

Subversion is already installed on OS X, to upgrade it follow these instructions. You may prefer to do this after playing with the installed version first.

All of these relies on using the terminal utility, which you can find in your applications folder.

Subversion can be installed on windows too, and there are graphical clients for those who like that sort of thing.

Setting Options

Edit the file ~/.bash_profile ( ~ is a shortcut for /Users/YOURUSERNAME ) and add the following line:

[sourcecode language="bash"] export SVN_EDITOR=/usr/bin/vi [/sourcecode]

Of course, you may prefer a different editor, such as nano or vim. This is the default editor which subversion will launch as and when you need to edit something. This is not necessarily the editor you'd use to edit the project day to day.

Checking it works

The quickest way to test is to 'check out' a repository. This means to create your own local copy. To test this, check out a copy of the latest development release of wordpress.

[sourcecode language="bash"] svn co http://core.svn.wordpress.org/trunk/ test [/sourcecode]

This will create a folder called 'test' and then download to it. To remove the folder, use the following but be careful, if you issue the rm command in the wrong place, you could blitz your files. The change of directory command is important.

[sourcecode language="bash"] cd test # Change directory so you're in 'test' ls # verify you are in the right place - you should see lots of files with wp- prefixes. If you don't then stop now rm -rf * # DO NOT ENTER THIS UNLESS YOU KNOW WHAT YOU ARE ABOUT TO DO rm -rf .* # This removes hidden files (e.g. .svn ) cd .. rmdir test [/sourcecode]

Note, if you want to see the hidden files, including those that help subversion do its thing, type ls -la

Updating

To update your local files, go to the directory and type

[sourcecode language="bash"] svn up [/sourcecode]

This will go to the server, look for differences and download all the changes. It's a good idea to do this often on multi-user projects to help avoid conflicts and merging difficulties, and from time to time on single user projects, as it'll mean that typing 'svn log' will give an up to date logfile.

Creating a repository

You could use subversion to keep up to date with, or help contribute to, a shared project. Or you may want to just use it to manage your own projects, to protect you against yourself. You won't edit the repository directory directly once it has been created. To do so may corrupt the data (however, if you've a checked out copy, you could use that to start a new repository).

Note, though you can have several repositories, different projects can share one repository - see the information on branching or this link for more.

One might create a repository like this:

[sourcecode language="bash"] cd ~ svnadmin create SVNrepo [/sourcecode]

A folder and structure will be created. Remember, don't edit this folder directly.

Now, decide where you'll be working. Usually in ~/Documents. Create some files there and add them to the repository - replace 'USERNAME' with your own username.

[sourcecode language="bash"] cd ~/Documents mkdir myproject touch myproject/firstfile.txt svn import myproject file:///Users/USERNAME/SVNrepo/myproject -m "Initial import" [/sourcecode]

You will see:

Adding         myproject/firstfile.txt

Committed revision 1.

Checking Out

Checking out is when you make your local copy of files from a repository. This is what you edit before 'committing' your edits to the repository.

You don't have to check out a whole repository, you can check out a subfolder, this can be very useful indeed (see branching, below).

Let's remove the original files - maybe we wiped them by mistake?

[sourcecode language="bash"] cd ~/Documents/myproject rm -rf * # ONLY do this if you're sure you're in the correct directory rm -rf .* cd .. rmdir myproject [/sourcecode]

Now, we only have the repository

[sourcecode language="bash"] svn co file:///Users/USERNAME/SVNrepo/myproject myproject # Checks out one folder of the project [/sourcecode]

or

[sourcecode language="bash"] svn co file:///Users/USERNAME/SVNrepo/ . # Checks out the whole project - include the full stop [/sourcecode]

Presto! You're back. You can edit your files as per normal, and use the repository to remember all the changes. You no longer need to worry about where the repository is.

Status and ignoring

Go to your checked out folder and type

[sourcecode language="bash"] touch testfile [/sourcecode]

This creates a file called 'testfile'.

To see what you have changed in your checked out repository, type

[sourcecode language="bash"] svn status [/sourcecode]

You should see a list of files. Those with ? have not been placed under version control, testfile being one of them (probably the only one).

?       testfile

You have three options. The first is to add them to the repository with

[sourcecode language="bash"] svn add testfile [/sourcecode]

The second option is to leave it and live with a mucky status report (not nice when you end up with more of these files).

The third is to add them to the ignore list. To do this, navigate to the directory the file, or subdirectory, is in and type

[sourcecode language="bash"] svn propedit svn:ignore . [/sourcecode]

The full stop is important. Your text editor will open (for me, I use vi, you might have chosen something else - see above for how to change). Add the name of the file or subdirectory. You'd use the same command to unignore a file. You can use * as a wildcard, so you can ignore all files like test_file1, test_file2 etc with test_*

Note, I've found that this will not work for subdir/testfile - to ignore a file in a subdirectory, either ignore the whole subdirectory, or navigate to that directory and then follow the instructions above.

Save.

Try another status report and it should be much tidier.

Note also that if you've already added the file to your repository, this won't work. This could happen if you create a subdirectory, put a file to be ignored in it, and then add the subdirectory to the repository (which'll add the contents). This won't happen if you add the file to a subdirectory AFTER you've placed that directory under version control. If you find that you cannot ignore a file, what you need to do then is to copy the file(s) - a regular copy using 'cp' (not svn copy). Do svn remove (see below), then move the copied version back into the original position.

Adding a file or directory

If you just create a file, it will not be added to the repository. You need to tell subversion to keep an eye on it.

[sourcecode language="bash"] touch testfile svn add testfile svn status [/sourcecode]

The first command creates the file 'testfile', then it is added to the repository, then we use status to check it will be added. (Note, the file has not yet been committed to the repository).

Removing a file or directory

To remove a file or directory, type

[sourcecode language="bash"] svn remove filename [/sourcecode]

Note, the file is not removed from the repository until you commit to the changes. Also, the file isn't gone for good - it can be restored from the repository.

Copying or moving a file or directory

To move a file:

[sourcecode language="bash"] svn move filename1 filename2 [/sourcecode]

To move a file:

[sourcecode language="bash"] svn copy filename1 filename2 [/sourcecode]

Note, that this will copy/rename maintaining the history on that file. If you want to make the copy appear as a brand new file:

[sourcecode language="bash"] cp filename1 filename2 svn add filename2 [/sourcecode]

Committing your changes

Any changes you've made are local changes, they have not affected the repository. Committing updates the repository. The mantra is to commit often

If you're working on a multiple-user project, it's good practice to update your local copy before committing. This prevents conflicts arising at the time of committal.

Update your local copy with 'svn up'. You may have to merge conflicts - if you're doing this, you should know enough to look this stuff up elsewhere - this is beyond the scope of this post. I'm mentioning this as even if you're on a single user project, and you know nobody else has made changes, it's good practice, and being in the habit of typing 'svn up' prior to a commit will help you later. On a multi-user project it's a good idea to update often, as otherwise the 'merging' will be very tough.

To commit your changes type

[sourcecode language="bash"] svn commit [/sourcecode]

You will then be dropped into your editor to write a message saying what the changes are. It is important to do this. Really, really, important.

For small changes type:

[sourcecode language="bash"] svn commit -m "message goes here" [/sourcecode]

You may want to type 'svn up' immediately so your local log file is up to date, typing 'svn log' will show you the changes.

Reversion

Reversion is when you roll back to an earlier copy of the your project, or even to an earlier copy of a file in your project. Aran has a post, as does robozen telling you you to do this. It is really useful if the log files are up to date - see above.

Some Subversion naming conventions are downright lousy. For instance, “svn revert” reverts your code to some older revision, right? Well that’s what you think, my sensible friend, and you’re wrong! All it does is it reverts your working file to the latest version in the repository, the same thing that can be accomplished with a simple delete and svn update.

So to actually revert to an older version in the repository, you have to issue this madness:

[sourcecode language="bash"] svn merge -rhead:123 http://my/svn/repository ./workingcopy [/sourcecode]

Where 123 is the number of the old revision to which you want to revert.

svn revert will revert local changes back to the checked out copy. This'll undo your work (which may be a good thing) - but not restore an earlier version

Trunk and branch

As I mentioned above, you can choose only to check out part of a repository. This allows you to use 'branches'. The main line of development is called the 'trunk'

Suppose that you are working on a big edit within a project, but you don't want to stop minor bugfixes going into the main line of development. You would create a 'branch'.

[sourcecode] svn copy trunk mybranch [/sourcecode]

This copies all of 'trunk' into 'branch'. You can then work on your branch before merging back into the trunk down the line.

Big projects often branch like this

Project \- Trunk \- Branch 1 \- Branch 2 etc.

You can check out all the repository, or just one folder.

For example, the WordPress people work on 'trunk' and from time to time they stabilise 'trunk' to create a release version. This is branched into a 'version'

To create the (currently non existing) version 2.9.7, they'd type this:

[sourcecode] svn copy trunk 2.9.7 [/sourcecode]

It's a good idea to do this whenever you have a version which is 'good enough' - it doesn't add many bytes to the repository, and it gives you an easy to find stable copy to return to.

For example, to download WordPress version 2.9.1 (a list of versions can be found here) into a folder called 'stable', and then immediately change to version 2.9.2 you'd these commands:

[sourcecode] mkdir stable cd stable svn co http://core.svn.wordpress.org/tags/2.9.1 . svn sw http://core.svn.wordpress.org/tags/2.9.2/ . [/sourcecode]

In the same way, one repository could hold multiple projects. For more on the branching issue, see this article.

Big projects such as WordPress often have a special type of branch called a 'tag' - these are not actively developed, they're a snapshot. As far as subversion is concerned, they're all the same, but for the humans - develop the branch folder, don't touch the tag folder. Of course, any project group can do as it pleases!

Summary

As I said at the start, I wrote this for me. If it's useful to someone else, that's a bonus. I hope it was useful for you.