How to Use git-crypt to Store Secrets Safely in Git
What it is
git-crypt lets you keep secrets in your Git repository while only decrypting them for authorized users.
- Plaintext in the working tree is stored in Git as encrypted blobs.
- Authorized collaborators can automatically decrypt files after checkout.
- Everyone else sees ciphertext only.
Why use it
- API tokens, credentials, and service configs in version control
- Shared environment templates and deployment secrets
- Team workflows where full-file encryption is too heavy for ad-hoc secret management
Install
brew install git-crypt # macOS
sudo apt install git-crypt # Debian/Ubuntu
Initialize and set up a repo
git init
git-crypt init
git-crypt init creates cryptographic keys in .git/git-crypt and starts tracking repository-wide encryption state.
Configure encrypted files
Use .gitattributes to mark paths for encryption:
echo "secrets/*.env filter=git-crypt diff=git-crypt" >> .gitattributes
echo "config/prod.json filter=git-crypt diff=git-crypt" >> .gitattributes
Commit the attribute file:
git add .gitattributes
git commit -m "Track sensitive files with git-crypt"
Add authorized users
GPG recipients (most common)
git-crypt add-gpg-user "[email protected]"
git commit -m "Add git-crypt recipient"
git-crypt add-gpg-user requires that the target public key is already available in the local GPG keyring (import the key before running it).
Included benefits of GPG
GPG is the practical default for git-crypt teams because it ties access to a real identity you already manage in your keyring.
- New developers can start decrypting secrets as soon as their GPG key is approved; no shared team secret has to be copied around.
- Access is easier to reason about than a single symmetric key because you can add and remove users without reworking everyone’s local setup.
- Rotation is safer: remove a key or replace a recipient instead of rewriting all secrets around one shared password.
- Auditing is cleaner because you can trace who got access via key approval history and repository commits.
Symmetric key (single/team-owned)
git-crypt export-key ./key.txt
Prefer GPG recipients whenever possible; symmetric keys are harder to rotate and audit.
Distribute the exported key file securely; never edit.git-cryptinternals manually.
Encrypted status and file handling
- Files in matching
.gitattributespaths are automatically encrypted on commit. - To force re-encryption after changing patterns:
git-crypt status -f
git commit -m "Re-encrypt tracked files"
If the repo is locked or using a symmetric key, ensure it is unlocked first (git-crypt unlock [<keyfile>]) so status -f can stage encrypted versions.
To check status:
git-crypt status
Unlock in a new clone
After cloning:
git-crypt unlock
With GPG recipients configured, unlock uses your local keyring automatically when your private key is available.
With a symmetric key, use:
git-crypt unlock /path/to/keyfile
Common gotchas
- Ensure
.gitattributesis committed before sensitive files, or they may already be in history as plaintext. - Keep
.git-crypt/metadata out of the repo root (it is internal; do not edit manually). - Rotate/adjust access when team membership changes, and re-encrypt current files:
git-crypt add-gpg-user "[email protected]"
git-crypt lock
git-crypt unlock
git add -u
git commit -m "Re-encrypt after recipient change"
git-cryptdoes not provide aremove-gpg-user/del-gpg-usercommand, so there is no built-in recipient revocation. This applies to both GPG and symmetric workflows.git-cryptdoes not rewrite past commits, so removing access cannot retroactively protect data already in history. Ensure no sensitive plaintext was ever committed before.gitattributesmatched those paths.
Useful references
- Official project: https://github.com/AGWA/git-crypt
man git-crypt(if installed)
