Django Best Practice:How to deal with settings.py in Git
NOTE: After writing this article several months ago, I gradually realized that despite this solution works, it is error-prone, and too verbose. I'll write a new article explaing how I deal with it now.
When I started wirting my blog, one thing that confused me is different versions of settings.py
. As we know, different settings.py
should be kept for developement and deployment, however when it comes to using Git, things get messy. The main difficulties lies on two things:
- Should I upload
settings.py
from developement environment to Git server? If I did, does that mean I have to change the file every time after doingGit pull
on deployment server? - If I choose not to upload
settings.py
, there is a risk of losing data.
My purpose is to keep different versions of settings.py
. Here's what I did:
- First, on the computer I do developing,
commit
andpush
everything as you normally do, includingsettings.py
. - Create a new branch called
deploy
on Github. - Then, on deployment server,
git pull
from branchmaster
. - checkout
deploy
branch, Modifysettings.py
for deployment, e.g. setDEBUG=False
, changeMEDIA_ROOT
,STATIC_ROOT
, etc. The ONLY file you should change issettings.py
, DO NOT TOUCH OTHER FILES ! commit
andpush
to branchdeploy
.- Back to developing environment, type this command:
bash git update-index --assume-unchanged my_blog/settings.py
Done :)
The key part is step 5. First you should understand what git update-index --assume-unchanged
is doing, basically it assumes that the file does not change. From git-scm:
--[no-]assume-unchanged
When these flags are specified, the object names recorded for the paths are not updated. Instead, these options set and unset the "assume unchanged" bit for the paths. When the "assume unchanged" bit is on, Git stops checking the working tree files for possible modifications, so you need to manually unset the bit to tell Git when you change the working tree file. This is sometimes helpful when working with a big project on a filesystem that has very slow lstat(2) system call (e.g. cifs).This option can be also used as a coarse file-level mechanism to ignore uncommitted changes in tracked files (akin to what .gitignore does for untracked files). Git will fail (gracefully) in case it needs to modify this file in the index e.g. when merging in a commit; thus, in case the assumed-untracked file is changed upstream, you will need to handle the situation manually.
So next time you commit
your work, though settings.py
may has been changed, those changes won't get uploaded to Git server, which means there is no confict when you pull
from master branch on deployment server no matter how many times your settings.py
has been edited there. You could also achieve this by adding my_blog/settings.py
to .git/info/exclude
.
Finally, workflow is like this:
Coding, Push to master
—> On deployment server, pull from master
Edit settings.py
on deployment server (if needed) —> Push to deploy
Be careful, NEVER push to branch master
from deployment server.
Now you've pushed some new commits to Github and want to apply it on your server. Here are the steps:
# step 1
make sure you're on master branch, if not, git checkout master
# step 2
$ git pull
# step 3
$ git checkout deploy
# step 4
$ git rebase master
# step 5
$ git push origin deploy
I'm open to changes and suggestions, if you have better ideas, feel free to comment.
comments powered by Disqus