While working for a previous employer I was tasked with developing a new company “intranet” site. Changes rolled out at an aggressive rate and the process of deploying updates via FTP quickly turned into a tedious task.

After a while I decided to spend some personal time thinking of ways to make whole process a bit smoother. A few of days passed as I tossed around various ideas in my head, then it hit me…

Why not just checkout a working copy of the project onto the production server itself?

Subversion Deployment Work Flow

So simple! All I’d have to do is use the production server’s subversion client to add, update, and remove any changes – deployment becomes as simple as: $ svn up.

Setting Up The Environment

As is the case with most ideas there ended up being a few issues that needed to be worked out before moving forward.

Subversion’s .svn/ Directories

A working copy of a subversion repository is riddled with hidden .svn directories. This is a security risk as, by default, these directories and their contents are publicly accessible. To fix this issue we need to deny access by adding the following lines of code to either the Apache Global Config file, the site’s <VirtualHost> block, or the .htaccess file in the site’s root directory.

<Directory ~ "\.svn">
    Order allow,deny
    Deny from all
</Directory>

See Apache Tips & Tricks: Deny access to some folders for more information.

Development vs. Production Configuration Files

More than likely the development and production config files will contain very different settings. That’s an issue because if we run the command $ svn up on the production server the development config file will overwrite the production server’s config file – not a good thing.

Note: If your config file is Environment Aware feel free to skip this subsection.

First we need create a new directory named something along the lines of /defaults. Once created we copy over default versions of our config files and then add & commit the directory to the repository. This ensures that skeleton versions of our config files will be available when checking-out a working copy from the repository.

Now that we have our default config files stored safely away in the /defaults directory we remove the site’s config file(s) from revision control and commit the change to the repository. Notice the use of the --keep-local flag to prevent the file from being deleting.

$ svn remove --keep-local wp-config.php
$ svn commit -m "Removing wp-config.php from revision control."

Finally we take advantage of Subversion’s property list to ignore the file(s) we just removed from revision control. Ignoring a file or directory will prevent it from being included in commands such as $ svn status and $ svn add. It will also prevent other subversion clients (such as those found in Eclipse or NetBeans IDEs from automatically adding the files during a commit.

In the example below we…

  • Change the PWD to the directory containing our config file.
  • Create a hidden file named .svn_files_to_ignore and populate it with a file name pattern we want ignored by subversion.
  • Add the .svn_files_to_ignore file to revision control.
  • Instruct subversion to ignore all files in the current directory that match the pattern(s) contained in the .svn_files_to_ignore file.
  • Commit the local changes to the repository.
$ cd /path/to/config_file/directory
$ echo "wp-config.php" > .svn_files_to_ignore
$ svn add .svn_files_to_ignore
$ svn propset svn:ignore -F .svn_files_to_ignore .
$ svn commit -m "Added svn:ignore property and related .svn_files_to_ignore file."

If your project has more than one file that needs to be ignored you can add the file patterns (one per line) to the .svn_files_to_ignore file – see The propset Documentation for more information.

The Final Product

At this point we’ve taken care of the major environment issues and have checked-out a working copy of the repository into the DOCUMENT_ROOT path for the site.

Development

  • Add/Update/Delete files while working in the site’s development environment.
  • Commit the changes you’ve made to the project’s subversion repository.

Deployment

  • SSH into the production server.
  • Change your PWD to the site’s DOCUMENT_ROOT directory.
  • Run $ svn update
  • That’s it! You’ve now deployed all changes you’ve made locally to the production server without even opening up an FTP client.

Rollback

Below is a quick rollback scenario where we’ve …

  • checked, and noted, the current revision number of the production server’s working copy,
  • proceeded to updated the production server’s working copy to the latest revision,
  • but we realized there was an unknown error occurring after the update,
  • so we decided to rollback the working copy to the last stable revision.
$ cd /path/to/site/document_root
$ svn info
> ...
> Revision: 17
> ...
$ svn up
> At revision 19.

Oops! An unknown error is occurring on the site!

$ svn up -r 17
> ...
> Updated to revision 17.

Summary

It’s important to keep in mind that this technique is more of an alternative/geeky way of deploying commits you’ve made in your subversion repository to the production server.

I’d also like to note that if you do not have a fast connection from your production server to your subversion server running $ svn update could take some time depending on the combined size of the files that need to be transferred.

The examples shown in this post do not reflect “proper” subversion repository structuring. Rather, I attempted to relay a proof on concept that can be applied or adapted to almost any repository structure.

If you have any thoughts or ideas on this process please let me know!

Tail Multiple Logs with Capistrano

Here’s a quick and easy way to tail log files from multiple hosts using Capistrano and the Foreman gem.Capistrano TaskFirst you’ll need to make sure the fore... Continue reading

Add Eloquent ORM Tab to PHP Debug Bar

Published on August 30, 2015

Doctrine 2 PDO Object

Published on August 17, 2015