Blog Post

How to Never Accidentally Commit Secrets to Git Again

A practical guide to preventing accidental secret commits: .gitignore patterns, pre-commit hooks, secret scanning tools, and automated protection strategies.

|7 min read
git secretsaccidental commit envgitignore secretsprevent secret leak git

It happens faster than you think. You are in the flow, staging files with git add ., writing a quick commit message, and pushing to remote. Twenty minutes later, GitHub sends you an email: "We found a secret in your push." Your AWS access key is now in your public commit history. Even if you delete the file, the secret lives in git's history forever.

This guide covers every layer of defense you should have in place so this never happens to you.

Layer 1: A Bulletproof .gitignore

Your first line of defense is making sure sensitive files are never tracked in the first place. Every project should have a .gitignore that covers these patterns:

bash
# Environment files

.env

.env.*

.env.local

.env.development

.env.staging

.env.production

!.env.example

# Credentials

*.pem

*.key

*.p12

*.pfx

credentials.json

service-account.json

google-credentials.json

# IDE and OS

.idea/

.vscode/settings.json

.DS_Store

# Build artifacts that might contain embedded secrets

.next/

dist/

build/

The !.env.example line is important: it tells git to track .env.example even though all other .env* files are ignored. This file should contain placeholder values and serves as documentation for your team.

Pro tip: Run git status before every commit. If you see a file you did not expect, investigate before staging it.

Layer 2: Pre-Commit Hooks

Even with a perfect .gitignore, mistakes happen. Someone renames a file. Someone creates a new config file that is not covered by existing patterns. Pre-commit hooks catch these mistakes before they enter your git history.

Using detect-secrets

detect-secrets by Yelp is one of the best tools for catching secrets in staged files:
bash
# Install

pip install detect-secrets

# Create a baseline (marks existing known secrets)

detect-secrets scan > .secrets.baseline

# Install the pre-commit hook

# In .pre-commit-config.yaml:

repos:

- repo: https://github.com/Yelp/detect-secrets

rev: v1.4.0

hooks:

- id: detect-secrets

args: ['--baseline', '.secrets.baseline']

Using git-secrets by AWS

AWS Labs' git-secrets specifically catches AWS access keys and other common credential patterns:

bash
# Install

brew install git-secrets # macOS

# Register AWS patterns

git secrets --register-aws

# Install hooks for this repo

git secrets --install

# Now any commit containing an AWS key will be blocked

Using gitleaks

gitleaks scans for a wide range of secret patterns and supports custom rules:
bash
# Install

brew install gitleaks # macOS

# Scan staged changes before committing

gitleaks protect --staged

# Add as a pre-commit hook

# In .pre-commit-config.yaml:

repos:

- repo: https://github.com/gitleaks/gitleaks

rev: v8.18.0

hooks:

- id: gitleaks

Layer 3: CI/CD Secret Scanning

Pre-commit hooks protect individual developers, but CI/CD scanning protects the entire team. If someone bypasses their local hooks (or has not set them up), the CI pipeline catches the mistake.

GitHub Secret Scanning

If you use GitHub, enable "Secret scanning" in your repository settings under "Security." GitHub automatically scans every push for known secret formats (AWS keys, Stripe keys, database URLs, etc.) and alerts you immediately.

GitHub also partners with service providers. If your Stripe key is detected, GitHub notifies Stripe, and the key can be automatically revoked.

GitLab Secret Detection

GitLab offers built-in secret detection as part of its CI/CD pipeline:

yaml
# .gitlab-ci.yml

include:

- template: Security/Secret-Detection.gitlab-ci.yml

Layer 4: The Nuclear Option — git filter-branch

If a secret has already been committed, deleting the file is not enough. The secret exists in your git history and can be recovered with git log or git reflog. You need to rewrite history.

bash
# Using BFG Repo-Cleaner (faster than filter-branch)

# Download bfg.jar from https://rtyley.github.io/bfg-repo-cleaner/

# Remove a specific file from all history

java -jar bfg.jar --delete-files .env

# Remove specific strings

echo "sk_live_abc123" > secrets-to-remove.txt

java -jar bfg.jar --replace-text secrets-to-remove.txt

# Clean up and force push

git reflog expire --expire=now --all

git gc --prune=now --aggressive

git push --force

Important: After rewriting history, rotate every secret that was exposed. Rewriting git history removes the secret from future clones, but anyone who already cloned the repository still has it.

Layer 5: Stop Having Secrets in Files at All

The best way to prevent committing secrets to git is to not have secret files in your working directory in the first place.

With ConfigShield, secrets live in an encrypted vault and are pulled on demand:

bash
# Pull secrets when you need them

configshield pull --project my-app --env development

# The .env file is created locally and already in your .gitignore

# When you are done, delete it

rm .env

Since secrets are always available via configshield pull, you never need to keep .env files around permanently. They are ephemeral: pulled when needed, deleted when not.

The Checklist

Use this checklist for every new project:

  • Add comprehensive .env patterns to .gitignore
  • Install a pre-commit hook (detect-secrets, gitleaks, or git-secrets)
  • Enable secret scanning in your Git hosting platform
  • Store secrets in a manager instead of local files
  • Rotate any secret that has ever appeared in a commit

It takes 15 minutes to set up all five layers. The alternative is explaining to your CTO why your production database was exposed on GitHub.

Start managing secrets securely with ConfigShield →
ConfigShield

Secure Your Secrets Today

Free forever for solo developers. AES-256 encryption, audit trails, and CLI access in 30 seconds.

ConfigShieldStart Free