When developing a template alongside your app, it's easy to accidentally commit app-specific code to the template repo:
- API keys and secrets
- Production configuration
- Customer-specific business logic
- "TODO: remove before template" comments
- Environment files
This pollutes the template and creates security risks.
geet includes a pre-commit hook that checks for configurable patterns before allowing commits to the template repo.
Patterns are defined in .mytemplate/template-config.env as pipe-delimited strings:
# Prevent committing files matching these patterns (pipe-delimited regex)
PREVENT_COMMIT_FILE_PATTERNS=".*\\.env.*|.*secret.*|.*\\.key$|config/production\\..*"
# Prevent committing content matching these patterns (pipe-delimited regex)
PREVENT_COMMIT_CONTENT_PATTERNS="API_KEY=|SECRET_KEY=|password:\\s*[\"'].*[\"']|TODO.*remove.*template|CUSTOMER_ID=|stripe_live_key"filePatterns - Regular expressions matched against file paths:
.*\\.env.*- Matches any .env file.*secret.*- Matches files with "secret" in nameconfig/production\\.json- Specific file path
contentPatterns - Regular expressions matched against file contents:
API_KEY=- Literal string matchpassword:\\s*[\"'].*[\"']- Password with quotesTODO.*remove.*template- Reminder comments- Case-sensitive by default
On every geet commit:
- Pre-commit hook reads patterns from config
- Checks each staged file against
filePatterns - Checks content of each staged file against
contentPatterns - If matches found, blocks the commit with helpful error
Example error:
❌ [pre-commit] Found patterns that may indicate app-specific code:
FILE: config/production.json matches pattern: config/production\..*
CONTENT: src/auth.ts:45 matches pattern: API_KEY=
→ 45:const apiKey = process.env.API_KEY="sk-live-1234567890"
CONTENT: src/db.ts:12 matches pattern: password:\s*["'].*["']
→ 12: password: 'my-secret-pass'
These patterns suggest implementation-specific code that shouldn't be in the template.
To bypass this check: git commit --no-verify
To fix: Remove the matched patterns or update .mytemplate/.geet-template.env
If you're certain the code should be committed:
geet commit --no-verify -m "Add intentional example"Use sparingly! The patterns exist for a reason.
{
"filePatterns": [
".*\\.env.*",
".*\\.pem$",
".*\\.key$",
".*secret.*",
".*credential.*"
],
"contentPatterns": [
"API_KEY=",
"SECRET_KEY=",
"PRIVATE_KEY=",
"password:\\s*[\"'].*[\"']",
"Bearer\\s+[A-Za-z0-9\\-_]+",
"sk-[A-Za-z0-9]+"
]
}{
"filePatterns": [
"config/(production|staging)\\..*"
],
"contentPatterns": [
"DATABASE_URL=.*production.*",
"STRIPE_LIVE_KEY=",
"CUSTOMER_ID=",
"TENANT_ID="
]
}{
"contentPatterns": [
"TODO.*remove.*template",
"FIXME.*before.*publish",
"HACK.*replace",
"XXX.*app.?specific"
]
}{
"contentPatterns": [
"// Customer-specific",
"// ACME Corp only",
"// This is specific to",
"@internal"
]
}Escape special characters:
.→\\.(literal dot)*→\\*(literal asterisk)[→\\[(literal bracket)
Common patterns:
.*- Any characters\\s+- One or more spaces[\"']- Single or double quote(foo|bar)- Foo OR bar^start- Line starts withend$- Line ends with
Case-insensitive matching:
Use (?i) prefix:
"contentPatterns": [
"(?i)api.?key",
"(?i)password"
]Temporarily:
geet commit --no-verifyPermanently for a template:
Remove the preventCommit section from geet-config.json:
{
"name": "mytemplate",
"desc": "My template"
// preventCommit section removed
}For specific files:
Add to .geetinclude only what should be in the template.
The hook only checks staged files.
- Requires
jqto be installed (gracefully skips if missing) - Only checks text files (skips binaries)
- Regex can have false positives (use
--no-verifywhen needed) - Can't detect all app-specific logic (some requires human judgment)
-
Start strict, relax as needed
- Begin with conservative patterns
- Add
--no-verifyexceptions when justified
-
Document your patterns
- Add comments in geet-config.json explaining why each pattern exists
-
Review regularly
- Update patterns as you discover new app-specific markers
- Remove patterns that cause too many false positives
-
Combine with code review
- Patterns catch obvious mistakes
- Human review catches subtle app-specific logic
-
Use descriptive pattern names
"contentPatterns": [ "API_KEY=", // Catch hardcoded API keys "TODO.*remove", // Catch developer reminders "STRIPE_LIVE_KEY=" // Production payment keys ]
(Note: JSON doesn't support comments, but you can document in README)
- File promotion - Auto-promote README and other files
- Publishing a template - Template publishing workflow
- Multi-layered repos - Managing multiple templates
The preventCommit patterns are a safety net, not a security guarantee:
✅ Good for:
- Catching accidental commits of secrets
- Enforcing team conventions
- Preventing obvious mistakes
❌ Not a substitute for:
- Proper secret management
- Code review
- Security audits
- Developer training
Use it as one layer in a defense-in-depth strategy for keeping templates clean and generic.