How to have local versions of tracked config files in git
This is a fairly common question, and there isn't a One True Answer.
These are the most common techniques:
If you can modify your application
- Modify your app such that, before loading its config from e.g.
config.ini, it first looks for e.g.
config.mine.ini, and loads it instead if it exists. Track a standard
config.iniin your repo, but if you need to override the values in it, copy it to
config.mine.iniand modify. Then configure git to ignore
- Modify your app such that it first loads e.g.
config.ini, but then attempts to load e.g.
config.mine.ini, and if it exists, uses keys from
config.mine.inito override those obtained from
config.ini. This is similar to the first approach, but means that
config.mine.inineeds to specify only options that you want to override. Thanks to shrugger for this one.
- Have your app look at environmental variables for its config, before using the values from its config file (or hardcoded defaults). Then set those variables as appropriate (e.g. in your
.bashrcfor shell scripts, or somewhere in your webserver's config for web apps). Only works if your app doesn't need much config, but can be a useful behaviour for simple apps, and is particularly useful for things like API keys.
If you can't modify your application
- Have your app just look for e.g.
config.ini, but don't track this file. Instead create and track e.g.
config.sample.ini. Tell git to ignore
config.ini. Everyone who clones the repo has to copy
config.ini, but they can modify
config.inias much as they want.
- Use some gitattributes clean/smudge magic as suggested by SethRobertson, see the other file in this gist.
- Use a local configuration branch. This is a more complex setup, but allows the config files to be stored within, and tracked by, git.
- Not recommended: If all of the previous suggestions won't work for some reason, look at the "assume unchanged" section in man git-update-index. Anyone who's tried this normally ends up hating it.
If your local config must be committed, e.g. for deployment to Heroku
If you follow one of the above suggestions -- where tracked and untracked config are stored in different files, with the latter ignored -- but need to commit the untracked config for deploying to somewhere, consider an extra deployment step that does something like the following:
# Assume the remote we're deploying to is called 'heroku', although this isn't heroku-specific # We'll create a commit on master containing the normally-untracked config, merge that into heroku/master, push, then remove the commit from master # Require a clean working directory, possibly using `git diff-index --quiet HEAD --` to check for uncommitted stuff git fetch heroku git checkout <branch_to_deploy_from> # e.g. master in git-flow # Add our normally-untracked confing git add -f <normally_untracked_config_file> # Create a deploy commit on master git commit -m "Deploy: Some useful commit message" # Checkout the branch we're going to push to, and merge that deploy commit in # We avoid having to have a local version of the heroku/master branch by detaching the HEAD git checkout -q heroku/master git merge --no-ff -m "Merge deploy commit" <branch_to_deploy_from> # Push our deploy commit+merge to heroku git push heroku HEAD:master # Checkout <branch_to_deploy_from>, and remove the deploy commit git checkout <branch_to_deploy_from> git reset --mixed HEAD^
This creates a nice visual history, with a set of merges from
heroku/master (if you need to roll back), but master branch doesn't have a record of the deployments.