How to manage configuration files when collaborating?

GitConfiguration FilesGitignore

Git Problem Overview


I'm writing a short script with a few simple variables at the top of the page. I want to work on them with a friend, but we aren't sure how to manage the variables needing to be changed after pulling each time for one of us, adding unnecessary junk to git status. I thought about just creating different named branches for each of us, and then the master will just have example usernames set, but it seems silly to have to do all that extra work merging. We could have the variables passed to the script as options, but that isn't desired, nor is separating it out to another separate configuration file. It would be great to have something like a .gitignore but for only ignore a few lines in a file.

How can this be elegantly managed? How is this problem usually managed?

Git Solutions


Solution 1 - Git

You can't easily just ignore changes to particular lines of a file, I'm afraid, so you're probably stuck with having a separate configuration file. Below I've listed two typical ways of dealing with this, and one slightly more exotic one:

Have a sample configuration file in git

Here, you would keep a file config.sample in git as an example, but the application would actually use the values in a file config which is in .gitignore. The application would then produce an error unless config is present. You have to remember to change values in the sample file when you add new configuration variables to your personal config file. In this case it's also a good idea to have your application check that all the required configuration variables are actually set, in case someone has forgotten to update their config file after changes to the sample.

Have a file of default values in git

You keep a file config.defaults in git, which has sensible default configuration values as far as possible. Your application first sources configuration from config.defaults and then from config (which is in .gitignore) to possibly override any of the default values. With this method, typically you wouldn't make it an error for config not to exist, so the application can work out of the box for people who haven't bothered to create config.

Using a single configuration file with --assume-unchanged

A third possibility, which I wouldn't recommend in this case, personally, would be to have a single configuration file which is committed in git, but to use git update-index --assume-unchanged <FILE>, to tell git to ignore changes to it. (This is described further in this useful blog post.) That means that your local changes to the configuration file won't be committed with git commit -a or show up in git status.

Solution 2 - Git

Python/Django-specific solution is to have a shared settings.py files that is checked into the repository, and a local settings_local.py imported at the end of settings.py, that overrides some of the settings with machine-specific values.

Solution 3 - Git

In my case, I have "config" variables in a separate (small) file as do all the other developers on the team. Things like my database location etc. are kept there. We put the name of this file in our .gitignore so that it's not version controlled but checkin a "sample_config" file so that newcomers can make a copy and use it for their own purposes.

Solution 4 - Git

Other options (not elegant but may be helpful):

  • Use git stash and git stash pop for your config file
  • Have a branch named, say, config which has your local config file changes and then use git checkout config <your config file>

Second option is good if you need to keep the local config changes in the repo (somewhere).

Solution 5 - Git

I have a couple of short scripts like this and instead of creating a separate configuration file, I create a separate setenv.sh (or setenv.bat) file. I move the few, simple variables to this new file, and call the setenv.sh file in the main script. Variables that will not change per user remains in the main script. Depending on how small this setenv.sh script is, I will either write documentation on how to create this setenv.sh, or will commit a setenv.sh.sample to be used as a template.

A variation to this is not to create or call a setenv.sh, and let the user set environment variables used in the main script. The main script will complain if the variables don't exist.

Some short scripts grow into big scripts or become full-fledged applications. When this happens, I go the way of configuration files. We have an application that manages configuration files called Config, at http://www.configapp.com. Config has the concept of environments and instances. In your example, you have 1 Local environment and 2 instances. Common variables go into Local environment and machine specific variables (you and your friend) go into the instances. This is a little too much for small scripts but works well for applications.

Solution 6 - Git

Nowadays I use ENV vars for example in python/django, you can also add defaults to them. In the context of docker I can save the ENV vars in a docker-compose.yml file or an extra file which is ignored in version control.

# settings.py
import os
DEBUG = os.getenv('DJANGO_DEBUG') == 'True'
EMAIL_HOST = os.environ.get('DJANGO_EMAIL_HOST', 'localhost')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGitterView Question on Stackoverflow
Solution 1 - GitMark LongairView Answer on Stackoverflow
Solution 2 - GitTomasz ZielińskiView Answer on Stackoverflow
Solution 3 - GitNoufal IbrahimView Answer on Stackoverflow
Solution 4 - GitMick KellyView Answer on Stackoverflow
Solution 5 - GitBienvenido DavidView Answer on Stackoverflow
Solution 6 - GityvessView Answer on Stackoverflow