Skip to content

Latest commit

 

History

History
517 lines (346 loc) · 15.8 KB

File metadata and controls

517 lines (346 loc) · 15.8 KB

Use Cases - git-crypt

Last Updated: 2026-03-30 by Keming He based on git-crypt v0.8.0 release

Platform

Important

This guide is for macOS / Linux users with POSIX-compatible shell (sh, bash, zsh).

For Windows users: See AGWA/git-crypt - INSTALL.md - Experimental Windows Support.

Transparent file encryption in Git repositories using GPG keys.

Table of Contents

Why Use git-crypt?

  • Transparent encryption: Encrypt files automatically on commit, decrypt on checkout - no manual steps
  • AES-256 encryption: Industry-standard symmetric encryption for file contents
  • Works with existing workflows: Use normal git commands - clone, pull, push, diff all work seamlessly
  • GPG-based access control: Grant access using GPG public keys - no shared secrets to manage

↑ Back to Table of Contents


Prerequisites

Important

GPG key required. git-crypt uses GPG keys to encrypt the repository's symmetric key. You need a GPG key with an encryption-capable subkey.

If you don't have a GPG key, see Use Cases - GPG Commit Signing to generate one.

Verify your key has encryption capability:

gpg --list-secret-keys --keyid-format=long

Look for [E] (Encrypt) capability in the output:

sec   rsa4096/ABCDEF1234567890 2026-02-06 [SC] [expires: 2029-02-05]
      1234567890123456789012345678901234567890
uid                 [ultimate] Your Name <your-email@example.com>
ssb   rsa4096/FEDCBA0987654321 2026-02-06 [E] [expires: 2029-02-05]

The ssb line with [E] indicates an encryption-capable subkey. If missing, you need to add one with gpg --edit-key YOUR_KEY_ID then addkey.

↑ Back to Table of Contents


Install git-crypt

macOS:

brew install git-crypt

Ubuntu/Debian:

sudo apt-get install git-crypt

Verify installation:

git-crypt --version

Expected output: git-crypt 0.8.0 (or similar version number).

↑ Back to Table of Contents


Initialize Repository

Note

Initialize git-crypt in an existing Git repository. The repository must have at least one commit.

Initialize git-crypt:

git-crypt init

This creates a random AES-256 key stored in .git/git-crypt/keys/default.

Add yourself as a trusted user:

# Using email (from uid line)
git-crypt add-gpg-user your-email@example.com

# Or using long key ID (from sec line, after rsa4096/)
# git-crypt add-gpg-user ABCDEF1234567890

# Or using full fingerprint (40-character line below sec)
# git-crypt add-gpg-user 1234567890123456789012345678901234567890

Any identifier that uniquely matches your GPG key works. See your Prerequisites output for these values.

Tip

This command automatically commits .git-crypt/ files to the repository. These files contain the encrypted symmetric key - one copy per authorized GPG key.

Verify setup:

ls .git-crypt/

You should see keys/ directory with your GPG-encrypted key file.

↑ Back to Table of Contents


Configure Encryption Patterns

Warning

Security: .gitattributes tampering risk. git-crypt cannot be used securely unless the entire repository is protected against tampering. An attacker who can mutate your repository can alter the .gitattributes file to disable encryption. Use Git signed tags or commits to protect repository integrity.

Encryption patterns are defined in .gitattributes using Git's filter and diff attributes.

Basic Syntax

PATTERN filter=git-crypt diff=git-crypt

Where PATTERN is a gitignore-style glob pattern with one critical exception: specifying only a directory path like /dir/ does NOT encrypt files beneath it. You must use dir/** to encrypt entire directory trees.

Pattern Examples

# Encrypt all files in secrets/ directory
secrets/** filter=git-crypt diff=git-crypt

# Encrypt specific file types
*.key filter=git-crypt diff=git-crypt
*.pem filter=git-crypt diff=git-crypt

# Encrypt environment files
.env filter=git-crypt diff=git-crypt
.env.* filter=git-crypt diff=git-crypt

# Encrypt files with specific naming
**/credentials.json filter=git-crypt diff=git-crypt
**/secrets.yaml filter=git-crypt diff=git-crypt

Critical: Exclusion Rule Order

Important

Exclusion rules MUST be at the END of the file. Git attributes use last-match-wins semantics. If you need to exclude files from encryption, place those rules after the encryption rules.

Correct order:

# Encrypt everything in secrets/
secrets/** filter=git-crypt diff=git-crypt

# EXCEPTION: Do NOT encrypt the README (must be LAST)
secrets/README.md !filter !diff

Incorrect order (README would be encrypted):

# This exclusion is overridden by the rule below - WRONG
secrets/README.md !filter !diff
secrets/** filter=git-crypt diff=git-crypt

The .gitattributes file itself should never be encrypted - it must be readable to determine which files to decrypt.

↑ Back to Table of Contents


Working with Encrypted Repos

Clone and Unlock

When you clone a git-crypt repository, encrypted files appear as binary data until unlocked.

git clone git@github.com:username/repo.git # via SSH
# git clone https://github.com/username/repo.git # via HTTP
cd repo

# Unlock with your GPG key
git-crypt unlock

git-crypt automatically finds your GPG key if you were added as a trusted user.

Check Encryption Status

# List all files and their encryption status
git-crypt status

Output shows which files are encrypted:

    encrypted: secrets/api-key.txt
    encrypted: .env
not encrypted: README.md
not encrypted: .gitattributes

Verify Encryption

Test that files are actually encrypted in the repository:

# Lock the repository (re-encrypts files in working directory)
git-crypt lock

# View an "encrypted" file - should be binary garbage
cat secrets/api-key.txt

# Unlock to restore readable content
git-crypt unlock

Verify encryption in git history:

# Show raw blob content (should be encrypted)
git show HEAD:secrets/api-key.txt | head -c 100 | xxd

Encrypted content starts with \x00GITCRYPT.

↑ Back to Table of Contents


Key Management

Export GPG Key for Backup

Important

Back up your GPG private key. If you lose access to your GPG key, you lose access to the encrypted repository. There is NO recovery mechanism.

Export your private key for secure backup (e.g., password manager, offline storage):

# Export private key (includes encryption subkey)
gpg --armor --export-secret-keys YOUR_KEY_ID > private-key-backup.asc

# Export public key (for sharing with collaborators)
gpg --armor --export YOUR_KEY_ID > public-key.asc

Store private-key-backup.asc securely. After importing to your backup location, delete the exported file:

# macOS (BSD) - best-effort overwrite on traditional disks
rm -P private-key-backup.asc public-key.asc

# Linux (GNU) - best-effort overwrite on traditional disks
shred -u private-key-backup.asc public-key.asc

Warning

Secure deletion limitation: Overwrite-based deletion (rm -P, shred) does not guarantee secure erasure on modern SSDs or journaled/copy-on-write filesystems (APFS, Btrfs, ZFS, ext4). Blocks may be remapped, retained in snapshots, or bypassed by TRIM operations. For sensitive key material: export directly to encrypted volumes (FileVault, LUKS), use tmpfs/RAM disk for temporary files, or avoid writing to disk entirely by piping to password managers.

Adding Collaborators

To grant repository access to another user:

  1. Obtain their GPG public key:

    # They export their public key
    gpg --armor --export THEIR_KEY_ID > collaborator-public.asc
    
    # You import it
    gpg --import collaborator-public.asc
  2. Add them to git-crypt:

    git-crypt add-gpg-user THEIR_KEY_ID
  3. Push the changes (auto-committed by git-crypt):

    git push

The collaborator can now clone and git-crypt unlock using their GPG key.

Removing Access

Important

git-crypt has no revocation mechanism. Once someone has access, they can decrypt ALL historical commits forever. Removing their .git-crypt/ key file only prevents future unlocks from new clones. Any user with an old clone and the old key can still decrypt all historical commits, even after re-initialization.

To truly revoke access requires rotating all secrets:

  1. Rotate all secrets in the repository (API keys, passwords, certificates, etc.)
  2. Re-initialize git-crypt with a new symmetric key
  3. Re-add only authorized users
  4. Force-push the new history (destructive operation)

Even after re-initialization, anyone with the old key can still access all historical commits in old clones. This is why secret rotation is critical, not just key rotation. See Known Limitations for more details.

↑ Back to Table of Contents


Encrypt Existing Files

If you add .gitattributes patterns for files already tracked in the repository, they are not automatically re-encrypted. You must force re-encryption.

Force re-encryption of all files:

git-crypt status -f

This re-stages files that should be encrypted based on current .gitattributes patterns.

Commit the re-encrypted files:

git add -A
git commit -m "chore(security): encrypt existing files with git-crypt"

Previous commits still contain unencrypted content - see Known Limitations about retroactive encryption.

↑ Back to Table of Contents


Multi-Branch Workflows

When working with multiple branches, encryption status can become inconsistent if branches have different .gitattributes configurations.

Best practice: Update .gitattributes on your main/default branch first, then rebase feature branches.

If encryption patterns changed on main:

# On your feature branch
git fetch origin
git rebase origin/main

If files need re-encryption after rebase:

# Remove files from index (keep working copy)
git rm --cached path/to/file

# Re-add to trigger encryption
git add path/to/file

# Commit the re-encrypted version
git commit --amend --no-edit

For complex Git workflows, see Use Cases - Git.

↑ Back to Table of Contents


Troubleshooting

Unlock Fails with GPG Error

Symptom:

Error: no GPG secret key available to unlock this repository

Causes and fixes:

  1. GPG key not imported:

    gpg --list-secret-keys --keyid-format=long

    If your key is missing, import your backup: gpg --import private-key-backup.asc

  2. GPG agent not running:

    gpgconf --kill gpg-agent
    gpg-agent --daemon
    git-crypt unlock
  3. You were never added as a trusted user: Contact the repository owner to run git-crypt add-gpg-user YOUR_KEY_ID.

Files Not Being Encrypted

Symptom: git-crypt status shows files as "not encrypted" that should be encrypted.

Causes and fixes:

  1. Pattern not matching: Check .gitattributes syntax. Test with:

    git check-attr filter path/to/file

    Should output path/to/file: filter: git-crypt.

  2. Files committed before pattern was added: Force re-encryption:

    git-crypt status -f
    git add -A
    git commit -m "chore: re-encrypt files"
  3. Exclusion rule overriding encryption: Check rule order in .gitattributes - see Critical: Exclusion Rule Order.

Merge Conflicts in Encrypted Files

Symptom: Merge shows binary conflict markers in encrypted files.

Fix: Resolve by choosing one version entirely:

# Keep our version
git checkout --ours path/to/file
git add path/to/file

# Or keep their version
git checkout --theirs path/to/file
git add path/to/file

Manual merge of encrypted content is not possible - you must choose one side or re-create the file after unlocking.

↑ Back to Table of Contents


Known Limitations

Limitation Description Mitigation
No retroactive encryption Encrypting a file does not encrypt its history. Previous commits remain unencrypted. Retroactively encrypt files with git-crypt-retro (new), or rewrite history with git-filter-repo (mature), or start fresh.
File paths visible Only file contents are encrypted. File names and paths are visible to anyone. Use generic names like secrets/config.enc instead of secrets/aws-credentials.json.
Metadata leakage File sizes, modification times, and commit metadata are not hidden. Accept this limitation or use a different solution for high-security needs.
No revocation Removing a user's key file does not prevent access to previously cloned repositories. Anyone with old clones and old keys can decrypt all historical commits forever. Rotate all secrets when removing users. Re-initialization only prevents future access, not historical access.
Binary diffs Encrypted files show as binary - git diff is not useful. Run git-crypt unlock before reviewing changes.
GUI incompatibility Does not work reliably with some third-party Git GUIs like Atlassian SourceTree and GitHub for Mac. Files may be left unencrypted. Use command-line Git or verify encryption status after GUI operations with git-crypt status.
Patch application Encrypted files cannot be patched with git-apply unless the patch itself is encrypted. Use git diff --no-textconv --binary to generate encrypted patches, or apply plaintext patches outside Git using the patch command.

↑ Back to Table of Contents


Related Guides

↑ Back to Table of Contents