Subversion repository with WordPress external

I use subversion (SVN) version control for web development and maintenance. There are other options out there but SVN has never let me down. This post is intended as a bit of a self-tutorial because I don’t set up repositories like this all that frequently, even though I work in them daily.

Please note some assumptions

1. You are familiar with WordPress and LAMP development in general

2. You have LAMP up and running on your development computer

3. You are comfortable working in a command shell

New to SVN or version control?

If you are new to SVN or version control in general, you should become familiar with a good SVN manual.

SVN runs as a client/server system, and for this tutorial we will use a local svn server. If you don’t have SVN on your computer get it from subversion.tigris.org. Or, if you work on a Mac like I do, open up Terminal.app and install the Darwin Port (requires the Darwin Ports package manager for managing Linux packages):

$ sudo port install subversion

Install via YUM or another package manger on Linux systems:

$ yum install subversion

Now setup a SVN repository with a WordPress external

For WordPress projects I use the WordPress public SVN repository to get the latest stable release of all the WordPress code. I do this as an svn:externals repository so that my own project files are independently version controlled, but the whole project can still reside in one tree for ease of setting up development, testing, and production sites. Basically, I have a repository for my files (theme directory, plugins, .htaccess, SQL dumps, and other non-WordPress files) and use the svn:externals property to manage the WordPress part of the project tree.

Here’s the basic procedure:

1. Create your project repository, I have a folder called ‘svn/repos’ in my home directory to put each project repository in:

$ svnadmin create /Users/your_home_dir/svn/repos/your_project

2. Go to your development web server root folder and check out a working copy of your new empty repository

$ cd /Users/your_username/Sites/
$ svn co file:///Users/your_home_dir/svn/repos/your_project

3. Now change directories to your working copy to save some key strokes for the next steps

$ cd your_project/

4. Use the svn:externals property to setup the external reference to the WordPress SVN repository

$ svn propedit svn:externals .

The dot (.) at the end is important, it means the current directory. This is how SVN references properties like svn:externals when you issue update/export and other commands. The above command opens an editor — most likely vi — to let us set external repositories that we want to include in the current directory.

5. In the editor we need to type (1) a directory name in our tree to hold the files we check out from the external repository and (2) the URL for external repository to use. Since I’m already in my working copy root directory, and I want my WordPress external folder to be called “wp” I type:

wp http://core.svn.wordpress.org/tags/2.9.1/

NOTE: The most recent (stable) release of WordPress at the time of this post is tagged as version 2.9.1. Older (and eventually newer) stable release tags are publicly available at http://core.svn.wordpress.org/tags/ .

6. Now we can do an update on our working copy, to fetch any changes from the repository (which will be everything since this is the first time we are going to update)

$ svn up

Fetching external item into 'wp'
A    wp/wp-pass.php
A    wp/wp-rss.php

... many more files ...

A    wp/wp-admin/themes.php
A    wp/wp-feed.php

Fetching external item into 'wp/wp-content/plugins/akismet'
A    wp/wp-content/plugins/akismet/akismet.gif
A    wp/wp-content/plugins/akismet/akismet.php
A    wp/wp-content/plugins/akismet/readme.txt

Updated external to revision 195905.
Updated to revision 12776.

Updated to revision 0.

Whoa! notice that? WordPress themselves are using svn:externals for the akismet comment spam plugin. Nice!

So where do we put our files?

Now we have to make a place in our project tree to put all the files we are going to work on, and more importantly keep a revision history of (that’s the whole point right?). A few of the files we need to work on are in the WordPress part of the tree, so we will make use of symbolic links so the development server (the local web server we’re working on) will find our files. Here’s how:

1. Create the directories we want for our files:

First check that we are at the top of our working copy tree, “beside” our wp directory that contains the WordPress external files.

$ pwd
/Users/your_home_dir/Sites/your_project

$ ls
wp

These are the folders I generally use on most projects:

$ mkdir site
$ mkdir site/wp-content
$ mkdir site/wp-content/themes
$ mkdir site/wp-content/themes/your_project_theme
$ mkdir site/wp-content/plugins
$ mkdir site/wp-content/uploads
$ mkdir tools
$ mkdir tools/design
$ mkdir tools/sql

2. Now create the symlinks so we can stay out of the WordPress part of the tree.

$ pwd
/Users/your_home_dir/Sites/your_project

$ cd wp/wp-content/themes/
$ ln -s ../../../site/wp-content/themes/your_project_theme your_project_theme
$ cd ..
$ ln -s ../../site/wp-content/uploads uploads
$ chmod 775 ../../site/wp-content/uploads

3. It is also handy to put the WordPress config file out in our part of the tree.

$ cd ..
$ cp wp-config-sample.php ../site/wp-config.php
$ ln -s ../site/wp-config.php ./wp-config.php

4. Now edit our copy of wp-config.php to put in the settings we need to install WordPress. This is usually just your DB_NAME, DB_USER, and DB_PASSWORD. I use TextMate as my main editor, and the “mate” command launches TextMate for me, instead of using vi.

$ mate ../site/wp-config.php

TextMate opens with the contents of wp-config.php for editing:

wp-config opened in TextMate

wp-config opened in TextMate

Save your changes to the 3 DB settings WordPress needs.

5. Now we’ll add and commit our directories and files to our repository, and we have a complete project tree ready in SVN to start working in.

$ pwd
/Users/your_home_dir/Sites/your_project/wp

$ cd ..

$ ls
site	tools	wp

$ svn add site/ tools/
A         site
A         site/wp-config.php
A         site/wp-content
A         site/wp-content/plugins
A         site/wp-content/themes
A         site/wp-content/themes/dufferin
A         site/wp-content/themes/dufferin/dufferin
A         site/wp-content/uploads
A         site/wp-content/uploads/uploads
A         tools
A         tools/design
A         tools/sql

$ svn ci site/ tools/
Adding         site
Adding         site/wp-config.php
Adding         site/wp-content
Adding         site/wp-content/plugins
Adding         site/wp-content/themes
Adding         site/wp-content/themes/dufferin
Adding         site/wp-content/themes/dufferin/dufferin
Adding         site/wp-content/uploads
Adding         site/wp-content/uploads/uploads
Adding         tools
Adding         tools/design
Adding         tools/sql
Transmitting file data ...
Committed revision 1.

That’s basically it. Now you can start your own theme in site/wp-content/themes/your_project_theme/ or just copy the any themes you like into site/wp-content/themes/

The rest of the WordPress installation and theme development is the same as if you worked directly in the WordPress part of the project tree.

What about when WordPress releases a new stable version?

Since we took all the trouble to set up our project repository with WordPress as an external, we can easily switch to the next stable release when it becomes available by using SVN’s “switch” command:

$ cd wp
$ svn sw http://core.svn.wordpress.org/tags/2.9.2/
$ cd ..
$ svn propedit svn:externals .
wp http://core.svn.wordpress.org/tags/2.9.2/

How about migrating to staging or production servers?

When we’re done developing our theme and other code, we can commit the files then export to a staging server for release testing:

$ ls
site tools wp

$ cd ~/a_temp_dir_for_exports/
$ svn export file:///Users/your_home_dir/svn/repos/your_project
[output]

$ rm -rf your_project/tools

This gives us a clean export of our entire project from all three repositories: our own, WordPress (external), and Akismet (external-external). Now we can copy the exported tree to our staging server for release testing and ultimately the production server.

$ pwd
/Users/your_home_dir/a_temp_dir_for_exports/

$ ls
your_project

$ tar -czf your_project.tgz your_project
$ scp your_project.tgz your_username@some.staging.or.production.server:
[password/output]

$ ssh your_username@some.staging.or.production.server
[password/output]

user_server_prompt$ cd /path/to/your/staging/or/production/site/
user_server_prompt$ su
[password]

root_server_prompt$ tar -xzf ~/your_project.tgz
root_server_prompt$ chown -R your_username:apache your_project
root_server_prompt$ chmod -R 755 your_project
root_server_prompt$ chmod -R 775 your_project/site/wp-content/uploads
root_server_prompt$ exit

user_server_prompt$

That’s it. Now you can keep your project’s version history and work in a team environment on the same project. Also you don’t have worry about putting WordPress directly in your repository, and can easily upgrade to the latest stable WordPress release at any time. Happy version-ing!

Further Reading

I have to mention three tutorials that I referenced in the past that helped me nail down my own exact process described in this post:

1. http://technosailor.com/2007/05/09/customized-wordpress-svn-externals/

2. http://josephscott.org/archives/2009/02/installing-wordpress-as-a-subversion-checkout-or-external-in-a-subdirectory/

3. http://blog.boringguys.com/2008/02/using-subversion-externals-property-for.html