You should not include the .env
file in a commit you're going to push, because if you do the .env
file will go along with the rest of the commit; the way git stores data, it is fundamentally impossible to avoid that.
So, if you want to store .env
in your local repo, you need to do it in a different way, so that it isn't stored as part of a commit you're going to push. I'll walk through an example, but realize this could get to be more trouble than it's worth. Also, I can't guarantee it will avoid accidental sharing of the .env
file, if git were to become "too clever" with its handling of pack files.
That is, you may just want to find a way to keep track of the .env
file outside of the repo.
Sanitizing your history: First things first - you say that if you put .env
in .gitignore
, it will be removed from your local repo as well. That's not exactly right. It's more correct to say, if you want .gitignore
to do any good, you must also remove .env
from your local repo. If you have an existing history, that's a bit easier said than done. Probably you'd use something like
git filter-branch --index-filter 'git rm --cached --ignore-unmatch .env' -- --all
Note that this is a history rewrite, so if these branches have been pushed, anyone else who has them will need to recover. What you really want is, you delete the remote, do the rewrite, recreate the remote, and everyone else throws away their local clone and re-clones from the new remote. Because otherwise, they still have your sensitive .env
file. The truth is if you've already pushed anything, and anyone else has access to your remote, then it's too late. You need to treat all credentials and sensitive information in the file as compromised, and avoid pushing the new credentials you create to replace them.
When all that's taken care of, add .env
to a .gitignore
file which you check in to each branch.
Adding .env to your local repo: You can add a file directly to the database in your local repo, without including it in any commit, by saying
git hash-file -w .env
This will store the content (not the path or filename) of .env
, and it will print out a string of 40 hex characters. For example
$ git hash-object -w xyzzy.txt
58e2592d61bc45e8d8f6f7a046f30c09c7ec3e1a
That hex is the object ID for the added file. You can confirm that it was written correctly with
git cat-file -p 58e2592d
(substituting a prefix of the object ID from your .env
file).
But this new object is "unreachable", which means git gc
(which runs automatically from time to time) is going to think it should be thrown away. To protect it, you need to tag it.
git tag my-env-file 58e2592d
Again you can test that all is well with
git cat-file -p my-env-file
Now git should keep track of your file locally, but normal pushes shouldn't include the file unless you go out of your way to push it (so don't do that). Again, I can only say this should be the case; if for whatever reason git were to transmit an existing pack file that includes your file over creating a custom pack file for a push, it might end up transmitting your file even though it wasn't "needed" for the history of the pushed branch(es). I don't think it ever does this, but I know no reason it couldn't start "optimizing" pack generation in the future if someone thought it were a good idea. So YMMV.
Of course, this isn't quite the same as committing .env
.
.env
won't be automatically restored when you check out a new work tree. You can restore it with
git cat-file -p my-env-file >.env
You could go as far as to put a script in source control that runs this command, though of course it will be unclear to anyone else what this script is for (since it won't work for them unless they create their own my-env-file
tag).
Also, .env
isn't versioned. You can, of course, store as many versions of .env
in the database as you want; and you could store the object ID for the "correct" version of .env
in the commit (possibly even in the form of a script that restores the correct version, since
git cat-file -p 58e2592d >.env
also works, bypassing the tag to grab the specific file). Again, those object ID's won't mean anything to other users of the repo, so it's not necessarily the best idea to include them in the shared commits.