We are currently using a somewhat complicated deployment setup that involves a remote SVN server, 3 SVN branches for DEV, STAGE, and PROD, promoting code between them through pa
I work with a similar situation to that which you currently have. I was tasked with finding a ‘better’ solution and it ran something along the lines of the following.
The live branch represents the servers in their current state.
Any development work should be done in a branch that is taken from live. This could be a one person half hour job or a year long multi team project. As often as is liked changes to live can be merged into these development branches.
Before a piece of work goes live, changes from live are merged again and it is tagged as a potential release. This release is tested on the staging environment and if it passes testing the new live is taken from the tag.
It is possible to merge several pieces of work into one release if that works better.
This means that it is fairly simple to keep development branches up to date with live and if a piece of work in development is dropped there is minimal tidying up to do.
To change from working on one project to another a developer can simply svn switch their local working environment to a different branch.
One of the problems we have had with the system as you describe is that DEV can get out of date with PROD fairly quickly, so you are not developing against the live and it is not easy to spot cross dependencies until stage. The above solution solves these issues while still remaining fairly lightweight.
When i worked in a small dev team (small meaning me, another programmer and the boss), it was quite the chaotic mess. However we found that Assigning a "gatekeeper" type of process worked for us.
The gatekeeper was the person who had done the most work on the app (in this case, i had 2 projects i developed from the ground up, he had like 4).
Basically, whenever he had to work on my projects, he'd notify me that he was doing work, i'd make sure the repository was up-to-date and buildable, then he would pull down, make his changes, then commit. He would inform me that it was done, i would pull down, build and deploy. If there were DB changes we had a DB Change folder with all the scripts that would correct the DB.
It's obviously got a lot of holes in it, but the process worked for us, and kept us from building over each other.
Three branches just sounds like extra work.
Environmental differences can be handled by having different versions of the relevant files in the trunk. i.e. database.yml & database.yml.prod. The deployment process should be environmentally aware and simply copy the per-environment files over the default ones.
I highly recommend the book (currently in rough cuts) Continuous Delivery, which describes a full process for managing software delivery, based on continuous integration principles (among others).
I strongly dislike the branch and merge approach, as it can get very messy, and is pretty wasteful since you end up spending time on activities which don't actually deliver any new value. You've already developed, tested, and fixed your code once, why create a situation (copying the code to another branch) which requires you to redo this work?
Anyway, the way to avoid branching and merging is to build your deployable artefacts from trunk, and promote the built artefacts (rather than source) as it passes test, staging, etc. This way you are 100% sure that the thing you're putting into production is the same thing you've tested.
If you've got different features which may need to be released on different schedules, changing your approach to how you implement (make functionality configurable, or better yet modular) can help you keep a single development trunk.
I personally work locally (development), adding/fixing features and when I think it's ready I commit to trunk (production). On production server I just do an svn update.