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)