pythongitmergeenvironment-variablesgit-branch

How to have branch specific variables in GIT and python


I have 2 different branches, master and test. Those branches are exact replicas except for the database string which is different for master and test. Everytime I merge test to master, the database string in the master gets replaced by the test database string.

I have heard about using branch specific variables, so I don't need to worry about the database string getting changes on merge as .env variables will take care of it.

Please let me know how do I do that.


Solution

  • as .env variables will take care of it.

    You could generate the right .env file.
    And rename the current .env into .env.master and .env.test

    In each branch, you would then generate .env, with the right content in it, from one of those files, depending on the current execution environment.

    The generation script will determine the name of the checked out branch with:

    branch=$(git rev-parse --symbolic --abbrev-ref HEAD)
    

    Finally, you would register (in a .gitattributes declaration) a content filter driver.

    smudge (image from "Customizing Git — Git Attributes", from "Pro Git book")

    The smudge script, associated to the .env.branch file, would generate (automatically, on git checkout or git switch) the actual .env file by looking at values in the right .env.branch value file.
    The generated actual .env file remains ignored (by the .gitignore).

    See a complete example at "git smudge/clean filter between branches".


    In your case, your project would look like:

    repo/
    ├── .env.master         # Contains production DB configuration
    ├── .env.test           # Contains test DB configuration
    ├── .env.default        # (Optional) Contains default settings for other branches
    ├── .env                # Generated on checkout, ignored via .gitignore
    ├── .gitattributes      # Contains: .env filter=envfilter
    ├── scripts/
    │   └── smudge_env.sh   
    └── README.md           # Documentation for the setup
    
    

    Your smudge script smudge_env.sh would then be:

    #!/bin/sh
    # scripts/smudge_env.sh
    branch=$(git rev-parse --abbrev-ref HEAD)
    case "$branch" in
      test)
        cat .env.test
        ;;
      master)
        cat .env.master
        ;;
      *)
        echo "Unknown branch: $branch. Using .env.default." >&2
        cat .env.default
        ;;
    esac
    

    Then:

    chmod +x scripts/smudge_env.sh
    
    git config --local filter.envfilter.clean cat
    git config --local filter.envfilter.smudge './scripts/smudge_env.sh'
    
    echo ".env filter=envfilter" >> .gitattributes
    git add .gitattributes
    git commit -m "Add .env gitattributes declaration for envfilter"
    

    So, addressing mikibok's comment:

    Am I supposed to cp the contents of the branch file to the filter?

    Not exactly.
    Instead of performing an explicit file copy, the smudge script should simply output (e.g., using cat) the contents of the appropriate file (like .env.master or .env.test). Git uses the output of the smudge filter to create or update the .env file.
    That is effectively the same as copying the file's content... but without having to run a separate cp command.

    Should I have the same smudge script in both branches?

    Yes. It is best practice to have one smudge script (stored under version control) that lives in a common location (for example, in a scripts/ directory).
    That way, regardless of the branch you are on, the same script will run, detect the current branch (using a command like git rev-parse --abbrev-ref HEAD), and output the appropriate configuration content.