We use the ExpressionEngine CMS (php) to create websites. For each site, we set up a subversion repository and commit the EE installation as well as any custom templates, images
A lot of the configuration options could be dealt with by switching on $_SERVER['HTTP_HOST'].
For example
switch ($_SERVER['HTTP_HOST']) {
case 'developement.domain.com':
$api_key = "dev environment api key";
break;
default:
$api_key = "live environment api key";
}
Then for .htaccess issues you can set an alternate .htaccess file in your vhost definition using the AccessFileName directive:
<VirtualHost *:80>
ServerName sitename
AccessFileName .htaccess-dev
</VirtualHost>
We deal with this by maintaining a config-specific directory.
So, for instance if you have different .htaccess and config.php files between dev and production they would be maintained in /trunk/config/{environment}/
We use ant/nant scripts to create release packages, and the scripts have a build task for each environment. Those tasks pick up the config specific files.
--
Another commenter suggests to switch on HTTP_POST. Unfortunately I can't comment directly (not a high enough rep). Using HTTP_POST to determine environmental configuration has potential security issues since the value of this comes from the client.
Another alternative is to branch the configuration files once, into a release branch, and then mark them as edited on the destination, and then use a merge script that remember how to do a three-way merge. If the configuration changes on the source, then it will likely generate a conflict, which is a good thing, because you probably need to do similar changes on the destination.
Thus, you keep two trees going for the lifetime of the project: development, and release. As things mature in development, you integrate them over to release. You can have a third, QA, tree as well, if you have a more involved release process.
When you pull a new release, you copy from the working area to the "release" area (as a merge/integration), rather than pull a brand new branch. If you also want a snapshot-in-time of the release tree at that point, then make a separate branch/copy/tag that you use only for archival purposes.
Btw: this is one of the areas where Perforce shines -- it remembers what you already merged, and won't ever attempt to merge twice.
I deal with this problem by adding configuration file to Subversion ignore list. It was already addressed here on Stackoverflow: see question #149485
Basically, I only keep setup.default.php
in SVN, and in every installation I manually copy it to setup.php
which is on ignore list. This prevents the file to be checked back in to the repo. There are rarely changes to this file and can be handled as the requirement occurs.