Home DevOps .gitignore — The Missing File That Exposed Production Secrets
Beginner 3 min · July 07, 2026
.gitignore: Prevent Secrets and Bloat From Entering Your Repo

.gitignore — The Missing File That Exposed Production Secrets

A developer forgot to add .env to .gitignore.

N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Production
production tested
July 07, 2026
last updated
214
articles · all by Naren
Before you start⏱ 15 min
  • Basic programming fundamentals (variables, functions, control flow)
  • No prior devops experience needed — we start from first principles
 ● Production Incident
Quick Answer

Create a .gitignore file in your repo root. Add patterns: *.log (all log files), .env (environment file), node_modules/ (directory). Use git check-ignore -v to debug why a file is being ignored.

✦ Definition~90s read
What is .gitignore?

.gitignore tells Git which files and directories to ignore — they won't be tracked, staged, or committed. It prevents sensitive or unnecessary files from entering the repository.

Gitignore is like a 'do not pack' list when moving houses.
Plain-English First

Gitignore is like a 'do not pack' list when moving houses. You tell the movers (Git) which boxes to ignore: 'Don't pack the trash (log files), don't pack the safe (secrets files), don't pack the pantry (generated files).' Without this list, Git tries to pack everything it finds, including things you never wanted in the moving truck.

⚙ Browser compatibility
Latest versions — ✓ supported
ChromeFirefoxSafariEdge

The most common Git mistake is committing something sensitive — API keys, database passwords, .env files, or large binary files. .gitignore is the first line of defense. But it's often added reactively, after the damage is done. A single commit with a .env file means the secrets are in the repository history forever, even if you delete the file in a later commit. This guide covers gitignore patterns, the global gitignore, and the incident where a missing .env entry exposed production API keys within hours of the commit.

Gitignore Patterns: Syntax and Best Practices

.gitignore uses glob patterns: *.log ignores all files ending in .log. .env ignores .env in all directories (no leading /). /config.env ignores only the file at root. build/ ignores a build directory at any level.

Negation: !important.log overrides a previous *.log ignore. Comments: # This is a comment. Empty lines are whitespace.

Key patterns for every project: .env, .log, node_modules/, .pyc, __pycache__/, .DS_Store, dist/, build/, .idea/, .pem, .key.

git check-ignore -v <file> shows which pattern caused a file to be ignored and which gitignore file it came from. Use this to debug unexpected behavior.

01_gitignore_basics.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Create a basic .gitignore
echo '.env' >> .gitignore
echo '*.log' >> .gitignore
echo 'node_modules/' >> .gitignore
echo '.DS_Store' >> .gitignore

# Check if a file is ignored
git check-ignore .env
git check-ignore -v secrets.pem  # shows which pattern matched

# List all ignored files in the repo
git ls-files --others --ignored --exclude-standard

# See what's staged (before commit)
git status --short

# Set up global gitignore
git config --global core.excludesFile ~/.gitignore_global
cat > ~/.gitignore_global << 'EOF'
.env
.idea/
*.swp
.DS_Store
*.pem
*.key
*.log
EOF

# Pre-commit hook to prevent secrets
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
if git diff --cached --name-only | grep -E '\.env$' > /dev/null; then
  echo 'ERROR: .env file is staged! Aborting commit.'
  exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
Output
.env
.env
pattern: .env (from .gitignore:2)
.env
.DS_Store
node_modules/test.log
M .gitignore
?? src/app.py
A File Ignored by .gitignore Can Still Be Staged
If a file was already tracked (committed) before you added it to .gitignore, gitignore won't help. You must first remove it from tracking: git rm --cached <file>. Only then does .gitignore take effect. git rm --cached removes from tracking but keeps the file on disk.
Production Insight
Create a global .gitignore via core.excludesFile on every developer machine. Include .env, .pem, .key, secrets., and IDE folders. This catches the 'I forgot to create a repo-specific gitignore' mistake. On CI, add a step that runs git diff --name-only --cached | grep -E '\.env$|\.pem$|secret' and fails the build if matched. For organizations, deploy a pre-receive hook on the Git server that rejects any push containing files matching .env or secret*.
Key Takeaway
Create .gitignore before the first commit. Use global gitignore via core.excludesFile for personal exclusions across all repos. git check-ignore -v debugs ignore patterns. Pre-commit hooks prevent committing sensitive files. Git history with secrets is permanent — prevention is the only cure.
● Production incidentPOST-MORTEMseverity: high

.env Committed to GitHub — API Keys Compromised in 2 Hours

Symptom
A developer created a new project, ran git init, wrote code, and committed. The .env file with production API keys was not in .gitignore. The entire file was committed and pushed to a public GitHub repository. Within 2 hours, automated bots had scanned the repo, extracted the keys, and used them to provision cloud resources on the company's account.
Assumption
The developer assumed that if a file is not git added explicitly, it won't be committed. They didn't realize that git add . stages all untracked files in the directory, including .env.
Root cause
1. Developer set up a new project and created a .env file with production AWS and Stripe API keys. 2. They ran git init, then git add . — which staged everything including .env. 3. They committed with git commit -m 'Initial commit'. 4. Pushed to a public GitHub repository. 5. Within 2 hours, automated credential-scanning bots detected the keys. 6. The bots provisioned EC2 instances for cryptocurrency mining — $15,000 in AWS charges before the keys were rotated. 7. The keys were also used to access production data through the exposed API keys.
Fix
1. Immediately: invalidated all exposed API keys (AWS, Stripe). 2. Removed the .env file from the current commit (not enough — history still had it). 3. Used git filter-branch to remove .env from all history: git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch .env' --prune-empty --tag-name-filter cat -- --all. 4. Force-pushed the cleaned history (coordinated with team to reset local clones). 5. Added .env to .gitignore immediately. 6. Added a pre-commit hook that checks for patterns like .env, .pem, secret, password in staged files and aborts the commit. 7. Implemented a global .gitignore via core.excludesFile that excludes .env by default for all repos. 8. Added CI step: git diff --name-only --cached | grep -E '\.env|secret|\.pem' and fail if matched.
Key lesson
  • Always create .gitignore BEFORE the first commit.
  • Never use git add . without checking what will be staged.
  • Use pre-commit hooks to scan for sensitive files.
  • Set up a global .gitignore for common patterns.
  • Run git status before every commit to verify what's staged.
Production debug guideUse this when production is on fire5 entries
Symptom · 01
Prevent a file type from being tracked
Fix
Add *.log to .gitignore — ignores all .log files
Symptom · 02
Ignore a specific file anywhere in the repo
Fix
Add .env to .gitignore — ignores .env in any directory
Symptom · 03
Ignore a specific directory
Fix
Add node_modules/ to .gitignore — ignores the entire directory
Symptom · 04
Debug why a file is (not) being ignored
Fix
Run git check-ignore -v <file> — shows which pattern matches
Symptom · 05
Set global ignores for all repos
Fix
Run git config --global core.excludesFile ~/.gitignore_global

Key takeaways

1
Create .gitignore BEFORE the first commit
not after the accident
2
Never use git add . without running git status first
3
Use global .gitignore via core.excludesFile for universal patterns
4
git check-ignore -v debugs why a file is or isn't ignored
5
Pre-commit hooks prevent sensitive files from being committed
6
If a secret is committed, assume it's compromised
rotate immediately
7
Use git filter-branch or git filter-repo to remove secrets from history (last resort)
N
Naren Founder & Principal Engineer

20+ years shipping production infrastructure and CI/CD at scale. Lessons pulled from things that broke in production.

Follow
Verified
production tested
July 07, 2026
last updated
214
articles · all by Naren
🔥

That's Git. Mark it forged?

3 min read · try the examples if you haven't

Previous
Git Show: Inspect Commits, Tags, and Files in Detail
47 / 47 · Git
Next
Introduction to Docker