I’ve mentioned this a few times in conversations, so I’ve been meaning to do a blog post on this for a while, but I really wanted to tidy up the theme before I got back into posting more, so now that I’ve done that, here goes…
This is an example of how to use the “externals” feature of Subversion in order to simplify the maintenance of your software project when it contains references to other libraries or projects that are hosted on their own repositories, and you want to keep them all updated from their respective sources without having to do any tedious copying / exporting, etc.
This particular long, rambling example will use a somewhat typical WordPress installation, with a couple minor organizational tweaks to keep things simple and clean.
Working Backwards
I’ll start by laying out what the end result will look like, and then walk through the steps of how to get there.
The goal in this case is to have a single SVN repo (under your control) which you can use to manage your complete package (in this case a WP install), but internally have it contain your own stuff but also pull from several different “external” SVN repositories (WP core + various separate plugin and theme repos) that you don’t need to manage or copy things from.
The obvious benefit here is that you end up with a single SVN source that you can put on your server(s) with a single svn co http://your.repo.url
and keep updated with a simple svn up
or svn switch http://your.repo.url/tags/1.2.3
if you use tags to manage your releases (which I recommend, but that’s a topic for another post).
Basic Directory Structure
This is the part that may be a bit different than you’re used to, but I find this structure to be much easier to work with when doing stuff like this, and recent versions of WordPress have supported this (moving wp-content and wp-config.php somewhere other than their standard locations) for quite a while.
So assuming we’re starting with a blank directory that is a local checked out copy of your trunk/ directory, here is what the end result will look like once we’re done (just so you’re ready). Assuming we’re under something like /var/www/yoursite/, you’d have three items in that directory:
*NOTE: See this comment below about making sure you start with an empty dir, and that the local target dirs you reference in externals do not exist before SVN creates them by loading the external.
core/
wp-content/
wp-config.php
Where
- core will be a copy of the WordPress core files, linked via an svn:externals reference to the latest tagged release of WordPress, and fetched automatically from their servers. This is the dir that your apache vhost should map to as its root.
- wp-content is where all your themes and plugins (among other things) will go. This will contain a mix of plugins and themes from other sources (via svn:externals) plus whatever themes and plugins we add to this repo itself.
- wp-config.php This will be a copy of your WordPress config file. I usually keep it on it’s own out here, and exclude it from the subversion repository by adding it to svn:ignore. That’s perhaps another post for another time, but I just don’t add it to the repo since my local and server passwords are different, and I don’t want either sitting out in a repo that I may or may not want to make public at some point. Also it helps to stick to the rule that you don’t need to modify any files (other than .htaccess) under the core directory.
OK, so far so good. If you are not cool with that project layout, it’s possible to use other structures, but I wouldn’t recommend it, and won’t answer any questions supporting it.
Step by Step – How To Get There
So, starting in a blank directory (checked out copy of your trunk, which should be empty at this point), first you want to set your SVN_EDITOR if you haven’t already.
export SVN_EDITOR=vi
, substituting vi for your text editor of choice.
Step 1 – Core WP files
Within this directory, type the following command to add the first external reference to WordPress itself:
svn propedit svn:externals .
and add the following (single) line of text:
core http://svn.automattic.com/wordpress/tags/2.8.2
then save and close the file.
To get a preview of the magic now at work, go ahead and check in your changes and then update:
svn ci
svn up
You should notice that when your local copy goes to update from your SVN repo it now also knows to go pull down the contents from the Automattic WP repo you linked to and put them in a directory called “core”.
Step 2 – wp-content
Now that we have the core dir handled, we want to make a wp-content dir, under which we’ll put all of our custom content, in addtion to other external plugins and themes.
Again assuming you are in the same directory as above (which should now only contain the “core” directory, issue the following command to get a clean copy of the wp-content that was retrieved from WP:svn export core/wp-content wp-content
* Do not just do a normal copy here, because that will copy the SVN info from the dir as well, which will screw you up.
Now we’ll add a couple themes from other external repos. svn propedit svn:externals .
and append the following two lines of text (after the existing core line):
wp-content/themes/redoable-lite http://svn.automattic.com/wpcom-themes/redoable-lite
wp-content/themes/sandbox http://sandbox-theme.googlecode.com/svn/trunkthen save and close the file.
svn ci
svn up
and we will see that those two themes right where they belong inside of our wp-content directory.
I could make this post even longer by illustrating linking to additional external plugins, etc., but it would work the same way as what I just did for themes. I’m sure you’ve got the hang of that by now.
All your other changes within this wp-content directory (your own themes and plugins, etc.) will be handled just like you’re used to with SVN; it’s just that now you’ll also have other content in there that you don’t need to manage yourself.
Step 3 – wp-config
This step isn’t strictly related to the svn:externals thing, but you’ll need it in order to follow the structure I laid out above.
cp core/wp-config-sample.php wp-config.php
This is now your official config file, and you’ll need to edit it as normal to point it at your database, etc.
WP is smart enough to find this file here (assuming you don’t have one under the core dir), but you’ll also just want to add an entry in that wp-config file to tell it to use the alternate wp-content directory we were working with in step 2, instead of the one under the core directory. In wp-config, add the line:
define( 'WP_CONTENT_DIR', '/var/www/yoursite/wp-content' );
Depending on your configuration, you may or may not also need to add an entry for ‘WP_CONTENT_URL’, but I wouldn’t bother with that unless you find you need it. You may also want to add Alias /wp-content /var/www/yoursite/wp-content
to your Apache vhost config as well.
Upgrading – AKA The Payoff
I should start by clarifying that I do not use the built in WP updating mechanisms for core WP or plugins, because I prefer to manage everything from SVN this way.
I find it easier to work with anyway, and it also has the added benefits of supporting more restrictive file permissions on the server, as well as allowing you to work with and test a local copy that you know is exactly the same combination of core files, plugins, etc. as what you will eventually put on your server, because you are pulling it all from the same place: your SVN repo.
Let’s say WP releases 2.8.3. You will simply svn propedit svn:externals .
and change the URL reference for the core dir to point to the 2.8.3 release:
core http://svn.automattic.com/wordpress/tags/2.8.3
then save and close the file. You can also change any other externals refs (plugins & themes) to their latest versions.
svn up
will then update your local copy with all the latest references from your external sources. Test everything out locally, and then once you are happy svn ci
and your latest config is checked in, ready to be updated on your server, via svn up or svn switch.
Closing Remarks
If you’re more of a hands on learner and want to follow along but also explore a reference, here is the trac view of the trunk of the repo I was using as a demo for this article, and the corresponding SVN repo itself as well.
Thanks for taking the time to read this (assuming anyone got this far). Any questions?