Keeping development from getting messy is a matter of keeping it always clean. Try to work in small projects so that what's checked into the head of development is always theoretically good to go to production. Push it to production regularly because it is easier to test many small releases than a few big ones. If you absolutely must do a bigger project, create a branch for it then merge that back into the main tree when it is done.

The amount of code is a non-issue. Suppose that you have a hundred thousand lines of code. What is that, 8 MB, plus maybe another 10 MB if you have a bunch of images. I think modern disk drives can handle that much code!

The bit where I was talking about installing version X of Foo on machine Y was a case where Foo was an external module (eg from CPAN) which is not part of your source control. Such as a DBD driver that you need.

What do we do during an install process? Lots! Here are some of the steps:

Check out the tagged version to a local machine.

Re-run tests.

Copy code to the machines where it needs to go.

Restart webservers.

Install crontabs. (Everything that is critical to your application should be in source control!)

Send an email to various people saying that we pushed to production, and summarizing what was pushed. (That summary is pulled automatically from version control commit messages.)

My point being that there are lots of things that you want to have happen, and they simply won't happen reliably if you don't automate. (In fact if you don't automate, they mostly won't happen.)

While having a separate test server is a Good Thing, you can (if necessary) live without it. If you've set things up so that all paths in your application are relative to the application root (which can be made findable in various ways - an environment variable is a convenient one), then there is no problem having multiple copies of your codebase on one machine. (Hint: It helps to have a configuration module that allows per user instances to run on different ports.)

Assuming that you've done that, all that you need to do is select a developer machine and say that it is also the test machine. Create a test user, set up ssh keys so that all developers can easily ssh into that machine as that user, and put your test codebase in that user's home directory. (One way to identify a test codebase is to have a revision tag, eg stg, which is the version of the code that is currently in QA. The test codebase keeps checked out whatever has been tagged stg.)

Now even though you don't have a test machine, you have a standardized test environment. Is it as ideal as a real test machine? Of course not! But it is a heck of a lot better than nothing!