we use the following workflow for our PHP based websites.
Users commit their work to Subversion. We don't allow developers to manually deploy code to Staging and Live. Why not to staging? Because we want it to closely simulate Live.
Deployments are done via Webistrano, which is a web frontend to the well-known and powerful Capistrano deployment tool. We've created so-called recipes that script the deployment. It does approximately the following:
- Webistrano logs into the server via ssh as user 'deploy'
- It updates a remote working-copy cache
- It copies the resulting working-copy to a releases// folder, using hardlinks (to save diskspace and for speed).
- Symlinks customer-data (i.e. files not stored in subversion) to the proper locations.
- The new release is chmodded to 775 to give the group write permissions.
- If all the above steps succeeded it changes the 'current' symlink to /releases// folder.
- It performs an 'apache2ctl graceful' to flush any caches (such as php's realpath() ) that are still caching the previous release.
- If more than a certain number of releases are stored, the oldest one is purged.
The webserver is configured so the docroot of the virtual host points at the 'current' symlink, so during the deployment the old site is visible, and after successful deployment the new site appears instantly.
Code is owned by deploy:deploy but customer-data directories are owned by deploy:upload and have their SGID bit set at creation.
Apache's www-data user is a member of groups 'deploy' and 'upload'. Developers have personal scp accounts on the server and are members of group 'upload'. This setup works very well for us, since developers can't interact with the code except via Webistrano. It prevents 'live quickfixes' except by admins and has reduced accidents tremendously. Webistrano's built-in rollback feature makes it quick to revert a faulty deployment.
Developers are given write access to the customer-data dirs (because of the upload group), so they can upload placeholder content or help the customer prefill the site. After all, no customer content is stored in svn. The SGID bit on the directories make sure that only the user ownership of uploaded files is set to the user doing the uploading (providing a bit of accountability). The group ownership remains set to 'upload' by the SGID, so that Apache or other developers can still read-write the files and directories created.
The clear Webistrano interface has proven very useful, and since Capistrano comes with most of the above functionality built-in, our deployment recipes are only two dozen lines. Most of that is overriding Ruby-on-Rails specific defaults.