This is a commonly recurring issue in past project I've worked on. There are several approaches, but they all have their drawbacks:
- Git ignore
Simply put a default file on the Git repo, so that developers can check out the default file. However, developers should ignore changes to this file and never check them in.
Pro: Really simple and I think the commonly preferred option.
Con: Prone to developer error, can lead to needing to fix the repo.
- Environment variable
I hadn't considered this yet but you did raise an interesting possibility. However, I'm not a fan of this approach though.
Pro: It works.
Con: It makes it harder to start developing on a new machine + setting up environment variables is a chore.
There are other ways to achieve a similar thing (see 5.) that do not involve environment variables, so I suggest steering clear of environment variables. They're an unwanted dependency.
The machine.config file was created specifically to use machine-specific settings. However, there are some drawbacks that make it a less desirable approach.
Pro: It works, sort of.
Con: Your application's config file takes precedence over the machine.config, which leads to undersirable consequences: Either your server (production environment) has to also use a machine.config for its settings, or you have to change the config setup between dev and prod. Neither is a good option.
As far as I'm aware, there is no way to make the machine.config take precedence over the web.config (similar to e.g.
!Important in CSS). If there is a way to do this, then this approach becomes more viable. However, I'm not sure if this is going to cause conflicts for developers who are working on more than one project on that machine, as you'd be relying on the same machine.config for all projects.
- My preferred approach:
I tend to create two files. default.config and web.config (or app.config). Feel free to use other names.
- default.config is registered in the git repo, and it contains the actual default config file.
- web.config is not registered in the git repo. Developers simply save the default.config file as a (newly created) web.config file, and can then make adjustments as they see fit.
- The default.config file is "just a file" in the Git repo.
- The VS solution is set up to use the web.config file.
- If a developer ends up adding new config keys for a change they're committing, they are expected to add these keys to the default.config and commit those to Git.
This has a few benefits that, in my opinion, make it worthwhile. To me, the most important benefit is that if someone commits a change that adds/deletes config keys, everyone automatically checks out the new keys (so they are aware of the update), but the added/removed keys does not immediately affect their local config file.
Pro: What I just said.
Con: Developers need to manually synchronize settings between the two config files. In my experience so far, that usually amounts to a 30 second copy/paste job so it's not an excessive hassle. However, it's not uncommon for a developer to commit a change and forget to update the default.config, which can lead to other developers running into issues after doing a pull.
- (untested) Custom config composition
This is something a coworker suggested, which, like your environment variables, is an interesting idea. But I haven't used this yet.
The idea would be to programmatically compose the config file. Just like how you can add a reference in your web.config to a secondary config file, you can add this reference programmatically. The benefit of doing it via code is that you can decide the second config gile's name dynamically (e.g. based on the username).
Additionally, you can disable this additional loading behavior by e.g. using a config switch, which means that you can ensure only using your basic config file in production.
This means that you could effectively have a separate config directory with
USERNAME.config files which override specific settings of the web.config file. All of these files can be checked in, and it would even make it possible for one developer to use another developer's config settings (e.g. when trying to reproduce an issue).
Note: instead of developer-specific config files, you could do the same for a hardcoded "localDevOverride.config" file, but then you can't check in that local file. I'd prefer to check in those files, so that if a dev needs to work on another machine (e.g. if their old one dies), they don't lose their settings.