When you are doing development on multiple branches in parallel, a simple git checkout will update your code to match any branch you like. But unfortunately, if you’re connecting to a database whose schema is different on each branch, there’s a disconnect that causes a lot of problems.

When doing Django development, to solve this issue I maintain a unique database for each branch, and set up a git hook to make sure that I’m pointing to the right database after each branch switch.

A Detailed Approach

In my setup, settings.py imports an optional local_settings.py that is not checked into git.
The git hook script below will alter the BRANCH setting in that file to match the branch you just switched to, if the branch is master, staging, or dev. If not, it leaves it alone. (The idea here is that you don’t want to bother setting up a whole database for every throwaway branch, but you could - just remove the if from the script.)

post-checkout git hook

Place this script code in your .git/hooks/post-checkout file to set the BRANCH variable:

#!/bin/sh

# if this is a file checkout – do nothing
if [ "$3" == "0" ]; then exit; fi

newHEAD=$2
newHEADName=`git symbolic-ref --short HEAD`

if [[ "$newHEADName" =~ ^(master|staging|dev)$ ]]; then
    echo [hooks/post-checkout] Changing BRANCH to $newHEADName: sed -i "s/^BRANCH = .*/BRANCH = '$newHEADName'/" myapp/local_settings.py
    sed -i "s/^BRANCH = .*/BRANCH = '$newHEADName'/" ventus/local_settings.py
else
    echo [hooks/post-checkout] Did not change DB setting, unknown $newHEADName.
fi

settings.py imports local_settings

In the settings.py, we load in local_settings.py like so:

DATABASES = {...}

## Read local settings.  `get_additional_local_settings` lets you add settings
## in your local_settings that are a function of other settings.  I pass ENV, here,
## but if you need other variables, simply add them.  Make sure you accept
## **kwargs in your `get_additional_local_settings` in case others change the list.
def get_additional_local_settings(**kwargs):
    return {}

try:
    from .local_settings import *
except ImportError:
    pass

additional_local_settings = get_additional_local_settings(
        BRANCH=BRANCH,
        DATABASES=DATABASES
)
if additional_local_settings:
    for setting_name, setting_value in additional_local_settings.items():
        globals()[setting_name] = setting_value

local_settings.py alters database using BRANCH

Then, the local_settings.py should include this:

def get_additional_local_settings(BRANCH, DATABASES, **kwargs):
    db_name = 'mydbname_{}'.format(BRANCH, 'local')

    for k, obj in DATABASES.items():
        obj['NAME'] = db_name

    return {
        'DATABASES': DATABASES,
    }

# BRANCH will be updated by post-checkout git hook.
BRANCH = 'master'