What has worked best for us on Stack Overflow (and meets point 2 of the Joel Test) is a continuous integration solution, allowing one-click building of our production sites, as well as automated builds of our developer tier upon new code check-in.
I prefer deploys which are automated and repeatable. You'd definitely want to start with a source control tag so you know exactly what you deployed and can re-deploy it anytime. Then use scripts to push that to the server, something along the lines of Capistrano, or just a homemade bash script or something.
For sites that use compiled code, if the testing servers match the production servers it's probably best to compile the code once, and push that same compiled version to production once it's been tested.
I use custom scripts. For static (HTML based) websites I use double directories with new and installed versions, then the script runs a recursive diff on the new and installed versions and uploads only the files which have changed.
I use git with a couple of customized hooks for deployment. This even has the advantage that I can run several branches for dev/test/beta/production sites and do some CI. For urgent patches, git always allows to cherry-pick specific commits from one branch into the next.