How to implement a custom commit message format that improves team collaboration and project tracking
π― Why Standardize Commit Messages?
In any development team, consistent commit messages are crucial for:
- π Traceability - Link code changes to specific tasks/tickets
- π Automation - Generate changelogs and release notes
- π₯ Team Collaboration - Everyone understands what each commit does
- π CI/CD Integration - Automated workflows based on commit patterns
- π Project Management - Track progress and estimate work
ποΈ The Problem
Without standardization, you get commit messages like:
git commit -m "fix stuff"
git commit -m "updated things"
git commit -m "WIP"
git commit -m "bug fix"
This makes it impossible to:
- Track which features are complete
- Generate meaningful changelogs
- Link commits to project management tools
- Understand the scope of changes
π‘ The Solution: Custom Commit Message Format
We'll implement a format like:
RPP-123 Adding user authentication
RPP-456 Fix login validation bug
RPP-789 Update dashboard layout
Where:
-
RPP-
is your project prefix -
123
is the task/ticket number - Description is optional but recommended
π οΈ Implementation Guide
Step 1: Install Dependencies
# Install Husky for Git hooks
yarn add -D husky
# Initialize Husky
npx husky init
Step 2: Create the Commit Message Hook
Create .husky/commit-msg
:
#!/bin/sh
# Get the commit message from the first argument
commit_msg=$(cat "$1")
# Check if the commit message matches the RPP pattern using secure string operations
# This avoids regex backtracking vulnerabilities
if [ -z "$commit_msg" ]; then
echo "β Commit message cannot be empty!"
exit 1
fi
# Check if it starts with RPP-
if [ "${commit_msg#RPP-}" = "$commit_msg" ]; then
echo "β Invalid commit message format!"
echo "β
Use format: RPP-[taskNumber] [Description (Optional)]"
echo "π Examples:"
echo " RPP-123 Adding Home page navigation"
echo " RPP-456 Implement Button component"
echo " RPP-789"
exit 1
fi
# Extract the part after RPP-
task_part="${commit_msg#RPP-}"
# Check if the task part starts with a digit
if [ -z "$task_part" ] || ! echo "$task_part" | grep -q "^[0-9]"; then
echo "β Invalid commit message format!"
echo "β
Use format: RPP-[taskNumber] [Description (Optional)]"
echo "π Examples:"
echo " RPP-123 Adding Home page navigation"
echo " RPP-456 Implement Button component"
echo " RPP-789"
exit 1
fi
echo "β
Commit message format is valid!"
Make it executable:
chmod +x .husky/commit-msg
Step 3: Create a Commit Message Template
Create .gitmessage
:
# RPP Commit Message Template
#
# Format: RPP-[taskNumber] [Description (Optional)]
#
# Examples:
# RPP-123 Adding Home page navigation
# RPP-456 Implement Button component
# RPP-789 Fix login validation
# RPP-101
#
# Rules:
# - Must start with RPP- followed by a number
# - Description is optional but recommended
# - Keep it concise and descriptive
# - Use present tense (Add, Fix, Update, etc.)
RPP-
Step 4: Create Setup Scripts
Create scripts/setup-hooks.sh
:
#!/bin/bash
echo "π§ Setting up Git hooks and commit template..."
# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "β οΈ Not in a git repository."
echo " Git hooks will be set up when you run this in a git repo."
exit 0
fi
# Set up commit template
git config commit.template .gitmessage
echo "β
Git commit template configured"
# Force Husky to be properly initialized
echo "π§ Ensuring Husky is properly set up..."
# Always run husky to ensure proper setup
npx husky
# Fix git hooks path if it's wrong
current_hooks_path=$(git config --get core.hooksPath 2>/dev/null || echo "")
if [ "$current_hooks_path" != ".husky" ]; then
echo "π§ Fixing git hooks path..."
git config core.hooksPath .husky
fi
# Check if .husky/_ directory exists after install
if [ ! -d ".husky/_" ]; then
echo "β .husky/_ directory still not created"
echo "π§ Trying alternative approach..."
# Try to force create the _ directory
mkdir -p .husky/_
# Copy husky.sh if it exists in node_modules
if [ -f "node_modules/husky/lib/sh/husky.sh" ]; then
cp node_modules/husky/lib/sh/husky.sh .husky/_/
chmod +x .husky/_/husky.sh
fi
# Create basic hook files
for hook in commit-msg pre-commit; do
if [ ! -f ".husky/_/$hook" ]; then
echo "#!/usr/bin/env sh" > ".husky/_/$hook"
echo ". \"\$(dirname \"\$0\")/husky.sh\"" >> ".husky/_/$hook"
chmod +x ".husky/_/$hook"
fi
done
fi
# Make sure husky hooks are executable
chmod +x .husky/* 2>/dev/null || true
chmod +x .husky/_/* 2>/dev/null || true
echo "β
Made Husky hooks executable"
echo "β
Git hooks and commit template configured successfully!"
echo "π Your commits will now use the RPP-[taskNumber] format."
# Final verification
echo ""
echo "π Verifying setup..."
if [ -d ".husky/_" ] && [ -f ".husky/commit-msg" ] && [ -x ".husky/commit-msg" ]; then
echo "β
All hooks are properly set up!"
echo "π§ͺ Test with: git commit -m 'RPP-123 Test commit'"
else
echo "β Setup incomplete. Please run: yarn setup"
fi
Create scripts/debug-husky.sh
:
#!/bin/bash
echo "π Husky Debug Information"
echo "=========================="
echo ""
echo "1. Node.js version:"
node --version
echo ""
echo "2. Yarn version:"
yarn --version
echo ""
echo "3. Husky version:"
npx husky --version 2>/dev/null || echo "Husky not found"
echo ""
echo "4. Git repository status:"
if [ -d ".git" ]; then
echo "β
Git repository found"
git --version
else
echo "β Not in a git repository"
fi
echo ""
echo "5. .husky directory contents:"
if [ -d ".husky" ]; then
echo "β
.husky directory exists"
ls -la .husky/
if [ -d ".husky/_" ]; then
echo "β
.husky/_ directory exists"
ls -la .husky/_/
else
echo "β .husky/_ directory missing"
fi
else
echo "β .husky directory not found"
fi
echo ""
echo "6. Git hooks path:"
git config --get core.hooksPath 2>/dev/null || echo "No hooks path configured"
echo ""
echo "7. Package.json scripts:"
grep -A 5 '"scripts"' package.json
echo ""
echo "8. Testing husky:"
npx husky
echo ""
echo "9. After husky - .husky contents:"
ls -la .husky/ 2>/dev/null || echo "No .husky directory"
echo ""
echo "π§ Debug complete!"
Step 5: Update package.json
{
"scripts": {
"prepare": "husky",
"postinstall": "bash -c 'if [ -d \".git\" ]; then ./scripts/setup-hooks.sh; else echo \"Not in git repo, run yarn setup when ready\"; fi'",
"setup": "./scripts/setup-hooks.sh",
"debug-husky": "./scripts/debug-husky.sh"
}
}
Step 6: Document in README.md
## π Git Commit Message Convention
This project follows a standardized commit message format to maintain consistency and improve project tracking.
### Format
RPP-[taskNumber] [Description (Optional)]
### Examples
- `RPP-123 Adding Home page navigation`
- `RPP-456 Implement Button component`
- `RPP-789 Fix login validation`
- `RPP-101` (description is optional)
### Rules
- **Must start with `RPP-`** followed by a task number
- Description is optional but recommended
- Keep it concise and descriptive
- Use present tense (Add, Fix, Update, etc.)
### Setup
The project is configured with:
- **Husky** - Git hooks for automated validation
- **Git template** - Pre-filled commit message template
When you commit, the system will automatically validate your commit message format.
π Security Considerations
Why Avoid Complex Regex?
The original approach used regex patterns that could be vulnerable to ReDoS (Regular Expression Denial of Service) attacks:
# β Vulnerable to backtracking
grep -E "^RPP-[0-9]+( .*)?$"
# β
Secure approach using string operations
[ "${commit_msg#RPP-}" = "$commit_msg" ]
Security Benefits of Our Implementation:
- No backtracking vulnerabilities - Uses O(1) string operations
- Input validation - Checks for empty and malformed input
- Defensive programming - Validates each part separately
- Clear error messages - Helps developers understand issues
π§ͺ Testing Your Implementation
Valid Commit Messages:
git commit -m "RPP-123 Adding user authentication"
git commit -m "RPP-456 Fix login validation bug"
git commit -m "RPP-789"
git commit -m "RPP-101 Update README"
Invalid Commit Messages (will be rejected):
git commit -m "fix stuff" # Missing RPP- prefix
git commit -m "RPP-" # Missing task number
git commit -m "RPP-abc" # Non-numeric task number
git commit -m "" # Empty message
π Advanced Customization
Customize the Prefix
To use a different prefix (e.g., TASK-
, JIRA-
, PROJ-
):
# Replace all instances of "RPP-" with your prefix
sed -i 's/RPP-/TASK-/g' .husky/commit-msg
sed -i 's/RPP-/TASK-/g' .gitmessage
Add Pre-commit Hooks
Create .husky/pre-commit
for additional checks:
#!/bin/sh
# Run linting before commit
yarn lint
# Run tests before commit
yarn test
# Check for console.log statements
if git diff --cached --name-only | xargs grep -l "console\.log"; then
echo "β console.log statements found in staged files"
exit 1
fi
Integration with CI/CD
Add to your GitHub Actions workflow:
name: Validate Commit Messages
on: [push, pull_request]
jobs:
validate-commits:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Validate commit messages
run: |
# Check last 10 commits
for commit in $(git log --oneline -10 | cut -d' ' -f2-); do
if ! echo "$commit" | grep -q "^RPP-[0-9]"; then
echo "β Invalid commit message: $commit"
exit 1
fi
done
π Benefits and Impact
Immediate Benefits:
- Consistent History - All commits follow the same format
- Task Tracking - Easy to see which tasks are complete
- Automated Validation - No more manual review of commit messages
- Better Onboarding - New developers know exactly what format to use
Long-term Benefits:
- Automated Changelogs - Generate release notes automatically
- Project Analytics - Track velocity and completion rates
- Integration Ready - Connect with Jira, GitHub Issues, etc.
- Audit Trail - Complete traceability of changes
Team Productivity:
- Reduced Review Time - Clear commit messages speed up code reviews
- Better Communication - Everyone understands what changed and why
- Faster Debugging - Easy to find which commit introduced a bug
- Improved Planning - Better estimation based on historical data
π§ Troubleshooting
Common Issues:
1. Hook not running:
# Check if hooks are executable
ls -la .husky/
# Make executable if needed
chmod +x .husky/commit-msg
2. Template not showing:
# Verify template configuration
git config --get commit.template
# Set template if missing
git config commit.template .gitmessage
3. .husky/_ directory missing:
# Run setup script
yarn setup
# Or debug the issue
yarn debug-husky
4. Bypass validation (emergency only):
git commit -m "RPP-123 Emergency fix" --no-verify
π Conclusion
Implementing standardized commit messages with Husky provides:
- Immediate value through consistent commit history
- Long-term benefits for automation and analytics
- Security through proper input validation
- Scalability as your team and project grow
The investment in setting up this system pays dividends in:
- Reduced communication overhead
- Improved project tracking
- Better automation capabilities
- Enhanced team collaboration
Start with the basic implementation and gradually add more sophisticated features as your team's needs evolve.
π Additional Resources
Happy coding! π
If you found this helpful, consider sharing it with your team or following me for more development tips.
Top comments (0)