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.
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.
(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.