To deploy my application, I use a collection of bash scripts known lovingly as explode. At its core, explode uses rsync to copy my source tree exactly as it appears on my laptop up to the production server:
project="myproject" src_dir="~/code/myproject" target_dir="~/myproject-deploy" ssh "$server" " /etc/init.d/$project stop; cd $target_dir; git commit -am 'pre-deploy commit'; " rsync "$src_dir/" "$server:$target_dir/code/" ssh "$server" " cd $target_dir; git commit -am 'post-deploy commit'; /etc/init.d/$project start; "
Now, at this point you're probably thinking:
- Doesn't that mean that your deploy could contain files which aren't in source control?
- What if you forget to pull before you deploy?
And those are definitely real problems.
But I've found that the popular alternative, deploying from the project's source control repository, has two significant drawbacks when deployments to environments other than production (staging, testing, demos, etc) are considered:
- Pushing quick, experimental changes is annoying when a full commit to source control is required. You can often tell when a project deploys from source control because the commit log will contain clusters of commits with messages like "trying foo", "nope, that didn't work, trying bar", ... etc.
- If the deploy script doesn't verify that there are no uncommitted changes to the local source code before deploying, the deployed code will be different from the local code... And if it does, it can make quick deploys frustrating.
Obviously these are not insurmountable problems, but I've found it easier to base my deployments on rsync and add sanity checks around production deployments ("working tree contains uncommitted changes... are you sure you want to deploy?") than it is to base my deployments on source control and add workarounds for deployments to non-production environments.
Now, to be clear: deplying with rsync isn't the be-all-and-end-all... It definitely has problems: rsyncing a source tree is significantly (significantly!) slower than a git push, and it's no where near as reproduceable as pulling from master. But it works well for me :)
Oh, and the git commit that's part of the deployment? While not necessarily related to rsync, I think it's worth mentioning too: the deployment's git repository contains the entire environment, including the Pyhton virtual environment! So if, for just about any reason, a deploy fails, git checkout HEAD^ will restore the deployment to a working state (the repository doesn't contain logs, the database, user data, though... As much fun as that would be, it would also be slightly impartial).
tl;dr: rsync makes it super easy to deploy to non-production environments, and deploying to production can be reasonably safe if a few sanity checks are performed.