Automated Git hooks that enforce commit message conventions and code quality standards.
- ✅ Commit Message Validation - Enforces Jira ticket format (CDE-XXXXX) with optional commit types
- ✅ Conventional Commits - Support for feat, fix, hotfix, docs, and more
- ✅ Code Quality Checks - Detects debug statements, TODOs, trailing whitespace
- ✅ Security Checks - Blocks commits with hardcoded credentials
- ✅ Branch Protection - Prevents direct commits to protected branches
- ✅ Configurable - All rules customizable via
.githooks-config.json
# 1. Navigate to your repository
cd /path/to/your/repo
# 2. Run the setup script
./setup-hooks.sh
# 3. Done! Hooks are now active# Copy hooks to .git/hooks/
cp hooks-templates/commit-msg .git/hooks/
cp hooks-templates/pre-commit .git/hooks/
# Make them executable
chmod +x .git/hooks/commit-msg
chmod +x .git/hooks/pre-commitEdit .githooks-config.json to customize behavior:
{
"commit-msg": {
"jira_project": "CDE",
"min_message_length": 10,
"max_subject_length": 72,
"require_type": true,
"allowed_types": ["feat", "fix", "hotfix", "docs", "style", "refactor", "perf", "test", "chore", "build", "ci", "revert", "security"]
},
"pre-commit": {
"protected_branches": ["develop", "master", "micro-qa", "micro-qa-adhoc"],
"checks": {
"conflict_markers": { "enabled": true, "blocking": true },
"debug_statements": {
"enabled": true,
"blocking": false,
"patterns": ["console\\.log", "debugger", "print\\(", "var_dump", "dd\\(", "dump\\("]
},
"todo_comments": {
"enabled": true,
"blocking": false,
"patterns": ["TODO", "FIXME", "XXX", "HACK"]
},
"large_files": {
"enabled": true,
"blocking": false,
"max_size_bytes": 5242880
},
"sensitive_data": {
"enabled": true,
"blocking": false,
"patterns": ["password", "api_key", "secret", "token", "private_key"]
},
"trailing_whitespace": { "enabled": true, "blocking": false }
}
}
}| Option | Description | Default |
|---|---|---|
jira_project |
Jira project code | CDE |
min_message_length |
Min chars after ticket | 10 |
max_subject_length |
Max subject length | 72 |
require_type |
Require commit type | true |
allowed_types |
List of valid commit types | ["feat", "fix", "hotfix", ...] |
protected_branches |
Branches to protect | ["develop", "master", "micro-qa", "micro-qa-adhoc"] |
enabled |
Enable/disable check | true |
blocking |
Block commit on failure | true/false |
patterns |
Detection patterns | Varies by check |
max_size_bytes |
Max file size | 5242880 (5MB) |
Format Required: CDE-XXXXX: type: Your commit message
Rules:
- Must start with Jira ticket (e.g.,
CDE-123:) - Must include commit type (e.g.,
feat:,fix:,hotfix:) - Minimum 10 characters after ticket and type
- Maximum 72 characters for subject line (warning)
- First letter should be capitalized (warning)
- Use imperative mood (warning)
- No period at end of subject (warning)
Commit Types:
| Type | Description | Example |
|---|---|---|
feat |
New feature | CDE-123: feat: Add user authentication |
fix |
Bug fix | CDE-456: fix: Resolve login timeout |
hotfix |
Critical production fix | CDE-789: hotfix: Fix payment crash |
docs |
Documentation | CDE-101: docs: Update API docs |
style |
Code formatting | CDE-202: style: Format with prettier |
refactor |
Code refactoring | CDE-303: refactor: Simplify auth logic |
perf |
Performance | CDE-404: perf: Optimize queries |
test |
Tests | CDE-505: test: Add auth unit tests |
chore |
Maintenance | CDE-606: chore: Update dependencies |
build |
Build system | CDE-707: build: Update webpack |
ci |
CI/CD | CDE-808: ci: Add GitHub Actions |
revert |
Revert commit | CDE-909: revert: Revert commit abc123 |
security |
Security fix | CDE-111: security: Fix XSS |
✅ Valid Examples:
CDE-123: feat: Add user authentication
CDE-456: fix: Resolve login validation bug
CDE-789: docs: Update API documentation
CDE-101: hotfix: Fix critical payment issue
CDE-202: refactor: Simplify database queries❌ Invalid Examples:
Add feature # Missing Jira ticket
CDE-123 Add feature # Missing colon
CDE-123: Add feature # Missing type
CDE-123: feature: Add auth # Invalid type (use 'feat')
CDE-123: fix: bug # Too short (< 10 chars)
CDE-123: FIX: Resolve bug # Type must be lowercaseDisable Type Requirement:
If you don't want to enforce commit types, set require_type: false in config:
{
"commit-msg": {
"jira_project": "CDE",
"require_type": false
}
}Then format becomes: CDE-123: Your commit message
Blocks direct commits to:
developmastermicro-qamicro-qa-adhoc
Solution: Create a feature branch
git checkout -b feature/CDE-123-descriptionDetects: <<<<<<<, =======, >>>>>>>
Blocking: ✅ Yes
Example Output:
✗ Merge conflict markers found in 1 file(s):
• src/app.js
Detects: console.log, debugger, print(), var_dump, dd(), dump()
Blocking:
Example Output:
⚠ Warning: Debug statements found in 2 file(s):
• src/app.js
• src/utils.py
Consider removing them before committing
Detects: TODO, FIXME, XXX, HACK
Blocking:
Example Output:
⚠ Warning: Found 3 new TODO/FIXME comment(s) in 2 file(s):
• src/app.js (2 comment(s))
• src/utils.py (1 comment(s))
Make sure they are tracked in your issue tracker
Detects: Files larger than 5MB
Blocking:
Example Output:
⚠ Warning: Large files detected (1 file(s)):
• assets/video.mp4 (10.5MiB)
Consider using Git LFS for large files
Detects: password, api_key, secret, token, private_key, aws_access_key_id, aws_secret_access_key
Blocking:
Example Output:
⚠ Warning: Potential sensitive data found in 2 file(s):
File: config.js
+const api_key = "sk_live_abc123xyz789"
File: auth.py
+password = "mySecretPass123"
Please review and remove any hardcoded credentials!
Detects: Files with zero bytes
Blocking:
Example Output:
⚠ Warning: Empty files detected (1 file(s)):
• empty.txt
Detects: Spaces/tabs at end of lines
Blocking:
Example Output:
⚠ Warning: Found trailing whitespace in 2 file(s) (5 line(s)):
• src/app.js
• src/utils.py
Run: git diff --cached --check
# 1. Create feature branch
git checkout -b feature/CDE-123-user-auth
# 2. Make changes
vim src/auth.js
# 3. Stage changes
git add src/auth.js
# 4. Commit with proper format (with type)
git commit -m "CDE-123: feat: Add JWT authentication"
# Output:
# 🚀 Running pre-commit checks...
# ✓ No conflict markers found
# ✓ No debug statements found
# ✓ All checks passed!
# 🔍 Validating commit message...
# ✓ Commit message validated successfully!
# Ticket: CDE-123
# Type: feat
# Message: Add JWT authentication# If you get warnings, you can still commit
git commit -m "CDE-456: Add feature with TODO"
# Output:
# ⚠ Warning: Found 1 new TODO/FIXME comment(s)
# ✅ All pre-commit checks passed!# Error 1: Missing Jira ticket
git commit -m "Add feature"
# Output: ✗ Commit message must start with Jira ticket format: CDE-XXXXX:
# Error 2: Missing commit type
git commit -m "CDE-123: Add feature"
# Output: ✗ Commit message must include a type
# Allowed types: feat, fix, hotfix, docs, style, refactor, perf, test, chore, build, ci, revert, security
# Error 3: Invalid commit type
git commit -m "CDE-123: feature: Add auth"
# Output: ✗ Invalid commit type 'feature'
# Allowed types: feat, fix, hotfix, docs, ...
# Fix and retry
git commit -m "CDE-123: feat: Add user authentication"
# Output: ✅ Commit message validated successfully!# Test 1: Missing Jira ticket (should fail)
git commit --allow-empty -m "Add feature"
# Expected: ❌ Rejected - Missing Jira ticket
# Test 2: Missing type (should fail)
git commit --allow-empty -m "CDE-123: Add feature"
# Expected: ❌ Rejected - Missing commit type
# Test 3: Invalid type (should fail)
git commit --allow-empty -m "CDE-123: feature: Add auth"
# Expected: ❌ Rejected - Invalid type
# Test 4: Valid format (should pass)
git commit --allow-empty -m "CDE-123: feat: Add feature"
# Expected: ✅ Accepted
# Test 5: Different types (should pass)
git commit --allow-empty -m "CDE-456: fix: Resolve bug"
git commit --allow-empty -m "CDE-789: docs: Update README"
git commit --allow-empty -m "CDE-101: hotfix: Fix critical issue"
# Expected: ✅ All accepted# Test on master (should fail)
git checkout master
git commit --allow-empty -m "CDE-123: Test"
# Expected: ❌ Blocked
# Test on feature branch (should pass)
git checkout -b feature/test
git commit --allow-empty -m "CDE-123: Test"
# Expected: ✅ Accepted# Create file with debug statement
echo 'console.log("test");' > test.js
git add test.js
git commit -m "CDE-123: Test debug detection"
# Expected: ⚠️ Warning shown, commit allowed# Create file with sensitive data
echo 'const api_key = "sk_live_abc123xyz789";' > config.js
git add config.js
git commit -m "CDE-123: Test sensitive data"
# Expected: ⚠️ Warning shown (or ❌ blocked if configured)# Create large file (6MB)
dd if=/dev/zero of=large.bin bs=1m count=6
git add large.bin
git commit -m "CDE-123: Test large file"
# Expected: ⚠️ Warning shown# Create file with trailing whitespace
echo "line with spaces " > test.txt
git add test.txt
git commit -m "CDE-123: Test whitespace"
# Expected: ⚠️ Warning shown# Create file with TODO
echo "// TODO: Fix this later" > test.js
git add test.js
git commit -m "CDE-123: Test TODO detection"
# Expected: ⚠️ Warning shown{
"commit-msg": {
"jira_project": "PROJ",
"min_message_length": 10,
"max_subject_length": 72,
"require_type": true,
"allowed_types": ["feat", "fix", "hotfix", "docs"]
}
}Now commits must use: PROJ-123: type: Message
{
"commit-msg": {
"jira_project": "CDE",
"require_type": false
}
}Now commits can use: CDE-123: Message (without type)
{
"commit-msg": {
"require_type": true,
"allowed_types": ["feat", "fix", "hotfix", "docs", "wip"]
}
}Now only these types are allowed: feat, fix, hotfix, docs, wip
{
"pre-commit": {
"protected_branches": ["develop", "master", "staging", "production"]
}
}{
"sensitive_data": {
"enabled": true,
"blocking": true,
"patterns": ["password", "api_key", "secret"]
}
}{
"debug_statements": {
"enabled": true,
"blocking": false,
"patterns": ["console\\.log", "debugger", "alert\\(", "System\\.out\\.println"]
}
}{
"trailing_whitespace": {
"enabled": false,
"blocking": false
}
}{
"large_files": {
"enabled": true,
"blocking": false,
"max_size_bytes": 10485760
}
}This sets the limit to 10MB (10 * 1024 * 1024 bytes).
# Check if hooks are executable
ls -la .git/hooks/commit-msg
ls -la .git/hooks/pre-commit
# Make them executable
chmod +x .git/hooks/commit-msg
chmod +x .git/hooks/pre-commit# Verify config file exists
cat .githooks-config.json
# Verify JSON is valid
python -m json.tool .githooks-config.jsonIf a check incorrectly flags your code:
- Review the pattern in
.githooks-config.json - Adjust or remove the pattern
Since Git hooks are local and not tracked by Git:
- Add to onboarding docs: Include hook setup in new developer onboarding
- Run setup script: Each team member must run
./setup-hooks.sh - Keep templates updated: Commit changes to
hooks-templates/directory
.
├── .githooks-config.json # Configuration file
├── .gitignore # Git ignore rules
├── setup-hooks.sh # Installation script
├── hooks-templates/ # Hook templates (git-trackable)
│ ├── commit-msg # Commit message validator
│ └── pre-commit # Pre-commit quality checks
└── README.md # This file
Q: Do hooks run on git merge?
A: The commit-msg hook skips merge commits automatically.
Q: Can I use a different Jira project?
A: Yes, change jira_project in .githooks-config.json.
Q: What if I don't use Jira?
A: You can modify the commit-msg hook to use a different format.
Q: Are hooks shared with the team?
A: No, each team member must run the setup script.
Q: Can I make warnings blocking?
A: Yes, set "blocking": true for any check in the config.
Q: How do I update hooks?
A: Pull latest changes and run ./setup-hooks.sh again.
MIT License - Free to use and modify for your projects.
For issues or questions:
- Check this README
- Review the hook output messages (they're designed to be helpful)
- Check
.githooks-config.jsonfor configuration issues - Review hook files in
hooks-templates/for logic
Built with ❤️ for better code quality and security