Home >
5 Tips For Version Controlled Site Deployments

Advanced Flash Tactics or AFTs are techniques that come from deep within the Flash Art Of War, the oldest Flash military treatise in the world. In this AFT I will go over - 5 Tips For Version Controlled Site Deployments. After relaunching my own blog I thought it would be a good idea to share some of the techniques I have used on larger sites and how they can be applied to smaller ones. Blogs and small sites are excellent times to practice version controlled deployments. This post will discuss what I have learned and recently implemented.
Preface
The following tips require command line access to your server via SSH. If you do not have SSH access you should find a better host. You will also need command line knowledge of version control. I use Git as my main vc now but you can use svn, or something else, just as easily. Hopefully you have everything you need to implement this workflow. If not, this strategy is still important to know and understand.
Tip 1: Version Control The Site
When we talk about using version control in Flash Projects, most people talk about managing your source code. No one really talks about how to handle the main site which contains the swf generated from your Flash code along with other supporting files. In larger projects the entire front end is usually under version control and the flash source is a separate project. When I want to test the full site I would copy the compiled swf over (usually with ant) to the main site. When everything looks good, I would commit the swf and support files. Your source code is maintained separately and this frees the front end deployment from being coupled to the flash source code. This is especially helpful if your site has lots of swfs and each one has it's own separate set of source code.
For FAOW I decided to make my entire WordPress source code the main project in my git repo. Along with the support files, I committed the upload, plugins, and theme directories so I could keep track of them as well. I also made sure to exclude the wp-config.php file from the repo by adding it to the .gitignore file. Since I have a different setups for each deployment of the site, I want to make sure the configuration file never gets committed especially when working in a team.
I find that git is the perfect version control system for maintaing a WordPress sites. Since git uses one central database to handle tracking files, unlike svn which uses .svn folders in every directory, it is easy to update the WordPress source code by dropping in a new copy and overwriting the existing files with the exception of the wp-contents directory. All I need to do after an upgrade is recommit the changed files and git is smart enough to understand what has been updated. Keeping the entire site in a git repo will form the basis of our deployment strategy.
Tip 2: Subdomains
I like keeping my development and testing areas separated on my server. I usually create a beta, staging, and production subdomain to handle these buckets:
- Beta is the experimental place where I code new features and fix bugs.
- Staging is the area where I QA the site and verify it will run exactly how I expect it to on production.
- Production is the live site. I NEVER work in production! Technically I don't make this a subdomain but I put it here anyways to emphasize that it is a separate location on your server, usually the root folder. I will talk about setting this a little later.
This setup helps clearly define what stage of development I am working in and avoids corrupting any of the other development areas. If you are unable to make subdomains on your server you should serously consider a new host.
Tip 3: Branch Your Code
Now that we covered the 3 development areas (beta, staging, and production), I like to create branches for each of them. It is important to note that production is the trunk of your project. So in git it would be the master and svn it is the trunch. Beta and production branch off of trunk. Once I have each branch created, check them out to the corresponding subdomains. Now lets talk about development workflow.
As I mentioned in the subdomain tips section, beta is where all my new features, experimental or bug fixes/refactoring development takes place. In my beta subdomain/branch I only commit upstream. I NEVER do any merging in this area. Once I am happy with the additions to the beta trunk, I commit and move over to the staging subdomain/checkout. Here I make sure I am in the staging branch, then do a merge with beta. Now I test that everything works until I feel it is ready to go to production. Once the staging is releasable, I switch over to the production branch (mind you I am still in the staging subdomain) and do my production -> staging merge. I do another round of quick test, then commit the merged changes. Before I deploy I switch back over to the staging branch and move over to the production area - I will talk about how this is setup in the next section. Now that I am in the production branch I simply do a pull or svn update and all of my changes go live. It is important to note again that I NEVER do any work in the trunk. I simply perform an update which in turn pushes my changes live. There are many ways to do a deploy system like this and this is the simplest way when working on a project by yourself. The next two tips will cover more complex setups.
There is one thing I didn't really talk about here but want to mention. Each checkout has it's own Database instance. If you remember from earlier I talked about not committing your config file, this is why. Once you have a separate DB for each development area you are safe to modify the site without affecting the staging or production database structure. Beta of course is the most volatile of the 3 so I keep db dumps from the live site around incase I ever have to do a major revert.
Tip 4: Symlink Production Checkout
I saved this tip for later because it is one of the most complex ones to do. This setup will work hand in hand with tag deployments in the next tip and requires you to understand a little about setting up symlinks. For your production area, Apache is usually pointed to a httpdocs folder on your server where it serves files from. This creates a dangerous scenario where you can completely overwrite a live site with little or no way to go back to the latest stable version. Version control and tags will help with this but I like to be extra safe. In the same directory as your httpdocs folder I create a new folder called deploys or git-checkouts. Inside of that I would checkout the trunk of the project into it's own folder, in this case it is simply flashartofwar since that was the name of my git repo. I now have a place to safely check out new versions of the site when I need to make a major update. The only problem is that Apache has no idea how to see these checkouts. By symlinking your httpdocs folder to the checkout you want to make live you can quickly and safely move between different checkouts. This will make way more sense after I introduce you to tagging.
Top 5: Tags Deployments
Up until this point I have told you to use the trunk as your production checkout and perform an update to deploy a site. This is great for small projects but as you begin to add new features to each new deployment you are going to want to version it. Now that you understand how to redirect Apache to a different checkouts by modifying the httpdocs symlink, I can talk about the final process, tagging. If you remember back to when I mentioned doing the final production -> staging merge I left out the following step after you are happy with the merge. Once I have tested that the production branch is stable and all of my staging changes have been committed, I tag the build. Once you have the tag, goto the git-checkout folder you made in the symlink tip and checkout the new tag to it's own folder. As an example I would have flashartofwar_v1.0.0 as a checkout. Once that tag is checked out, recreate the httpdocs symlink to point to the new checkout. Now deployments are as easy as creating a symlink that points to a new folder on your server.
Over time your git-checkout folder will contain a history of each version you have checked out and if anything gets messed up you can simply point the httpdocs symlink back to an older version. When dealing with a live sites, the last thing you want to be doing is trying to revert a checkout or merge and taking down the site at the same time. By pointing the symlink to the checkout you want to make live, you have an amazing fail safe and a clear way to revert back to an older checkout of the code. As your site evolves, remove the older checkouts and keep the folder clean.
Final Notes
This setup is a little more complex then most people may want to go through. On smaller sites it is overkill. The one suggestion I would make for cutting out additional steps is to remove the staging branch. Keep the staging subdomain but simply use a checkout of the trunk and merge changes from beta into it. Then test, tag and redeploy. I only use the staging branch as a place to manage complex merges. In a single user setup it is pointless. I hope this setup has inspired you to experiment on your own. Like all workflows, you will have to tailer it to your own specific needs and use cases. Also, repetition and standardizing your process will help insure that you stick to the deployment strategy. You should never break the main rules like not fixing a bug in the trunk on production. Even if it is a quick fix over time you will abandon the process and risk introducing bugs or take down the live site. If you have a different strategy then this or have ideas on how to improve, it please leave a comment below.




Facebook Application Development
Hi,
good article but your description of tip 3 (branch your code) is abit unclear: "In my beta subdomain/branch I only commit upstream. I NEVER do any merging in this area."
So how do you make your beta-branch stay in sync with the trunk when more than one person works on the project? Do you create another separate beta branch from the trunk for each new feature/bugfix you're working on? If you don't regularly merge the trunk changes into the branch you're working on, you'll get into merging hell when you need to merge the branch changes back into the main line (which is a common mistake when branching/merging with SVN, by the way)
A simpler (SVN) setup might be: Work in the trunk. Only commit to the trunk when all tests pass and the application compiles without any errors. If you need to work on a *complex* new feature or bugfix, create a separate branch. Continously merge the trunk changes into your branch. When you're done, all tests pass etc., merge the branch changes back into the trunk (this should be easy now!). Commit the trunk. For each release, create a tag. Deploy the tagged version to your server, similarly to the way you described it in your article...
Furthermore, your beta-subdomain may not be really useful in a project with multiple team members. How do you prevent overwriting each others (maybe unstable) changes? If you have a trunk which compiles all the time and passes all tests, then you could setup a test domain which always contains the latest trunk version (ideally checked out automatically by a continous integration server). Other testing is done locally on each team members system before committing to the trunk.
It would be interesting to know how you handle the version control/test/deployment process in a team-environment?
test
merger, you bring up a very good point. I will be doing a follow up on this based on a team environment. To address your question about what I do with my beta branch it could be handled 2 ways.
1) Each Developer has their own "beta" like branch. They all work on their own features and when a merge is ready the project lead does the merging on staging similar to how I explained in the article. This is problematic since as you had pointed out each person's beta can get out of date but it allows each developer to be 100% isolated from the major changes going on outside of their scope. If they need to get changes they can merge with another dev's branch or do a merge with the master stable branch. Once a new version is done, all devs replace their branch with the latest code from the stable branch.
2) Instead of Beta you have a branch for the next version of the application. Each developer works in that branch and upon commits, the lead works out any conflicts. Everyone is responsible for updating the branch to get changes from other devs (although this may cause breaks in their own code) and once the branch is ready to be released the lead will merge it into the staging branch and up to the master (trunk).
There are a few other ways to do this, and I will attempt to offer up my suggestions in a follow up article. I tend to never work in trunk even in a team since trunk should always be stable. When it comes to AS dev, option 2 is what I try to use the most. We each work on a new version branch, when it is ready it gets merged back down into the trunk.
Hope that clears things up a little?
Thanks for your answer and yeah, a follow up article would be a great idea.
Option 1 seems problematic since (at least in my opinion) it is not desirable to allow developers "to be 100% isolated from the major changes going on outside of their scope". If you follow the rule to always have a working trunk, developers are encouraged to update their branch regularly and always stay in synch with the main line, which makes merging the changes back and integrating new features much more painless. I think this is more or less one of the ideas of continuous integration: update/commit often, only commit tested/compiling apps, integrate frequently etc..
Hi,
Very informative article.But branching is most conceptually powerful when viewed from a project-wide or system-wide perspective; the resultant version tree reflects the evolution of an entire project or system.
huiles de poisson