In a project I am working on, we have an ongoing discussion amongst the dev team - should the production environment be deployed as a checkout from the SVN repository or as
I deploy it as a copy. Not manual, of course.
I use 'make' and 'checkinstall'. I create a small Makefile which uses the system command 'install' to copy all the needed files to the appropriate directories on the web server, and I have preinstall and postinstall shell scripts that will be run on the server.
When time for deployment comes, I just run 'checkinstall' which creates a package (RPM, DEB or TGZ, depending on which Linux distribution I target). I install it using regular tools provided by a Linux distribution package manager (rpm, dpkg, pkgtool). Of course, if you want to track dependencies as well, you can use yum, apt-get, etc.
It makes it really easy if you want to distribute a new version of your web app. to multiple target servers. And stuff like uninstall, reverting to an older version, etc. are very easy because you have a ready to use package for each version you deployed.
This might not fit your 'push often' strategy though if you use some stuff that needs compiling. However, for scripting stuff (like PHP that I do), creating a package (of about 300+ PHP files) takes about 20 seconds on my machine. And about as much to install it on any target system.
To separate the code 'for release' from the 'in-development' code, I use branching. With Git, it's really easy, since branching is cheap and fast.