1

I am developing on my Mac system and have created local git repository which I then publish to remote repository. I have .env file for every project which includes some sensitive data also. Ofcourse, I have to save this .env file in my local repository to avoid recreation in case I have to move to another system. But I have read in many online documentation that .env should be added to .gitignore to avoid sharing it publicly. If I add this file in my .gitignore then it will also be removed from my local repository.

What is the best way or possibility to have this .env file to only be ignored while publishing to remote repository?

codelearner
  • 1,354
  • 1
  • 16
  • 32
  • 1
    Git pushes commits to the remote repositories, not files. A Git commit is a snapshot of the project. There is no way to have a file in the local repo and not send it to the remote repos. Your problem can be easily solved by putting a template of the configuration file in the repo and add the real file to `.gitignore`. The template should contain default values when it is possible and empty/dummy values for sensitive information (passwords, f.e.). – axiac Apr 23 '18 at 10:18
  • 1
    Possible duplicate of [What is the best practice for dealing with passwords in github?](https://stackoverflow.com/questions/2397822/what-is-the-best-practice-for-dealing-with-passwords-in-github) – phd Apr 23 '18 at 11:07

1 Answers1

2

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.

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
  • I was expecting something like `.gitignore-remote` that will be used _only_ when pushed to remote repository. :) – codelearner Apr 23 '18 at 16:16
  • @codelearner - No such luck. While that user interface would seem simple, the technical details of actually providing that functionality are not simple at all – Mark Adelsberger Apr 23 '18 at 16:36