如何通过Husky实现Git提交信息自动添加分支名前缀并解决钩子覆盖问题
Husky works by replacing the default Git hooks in .git/hooks with its own orchestration layer, which is why your original custom hook stopped working. Instead of trying to block Husky from overriding hooks (which would break Husky's core functionality), the right approach is to migrate your custom logic into Husky's managed hook system. This way you keep Husky's features and maintain your branch-prefix commit message behavior.
Here's a step-by-step solution:
1. Add a Husky-managed commit-msg hook
First, create the hook file through Husky to ensure it's properly integrated:
npx husky add .husky/commit-msg
This will generate a .husky/commit-msg shell script linked to Husky's core setup.
2. Add your custom branch prefix logic
Replace the contents of .husky/commit-msg with this shell script (it replicates your original hook's behavior with edge-case handling to avoid duplicate prefixes):
#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" # Fetch the current branch name BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD) # Extract the part of the branch name before the first underscore # (Uses the full branch name if no underscore exists) TICKET_PREFIX=$(echo "$BRANCH_NAME" | cut -d'_' -f1) # Get the path to the commit message file (passed by Git as the first argument) COMMIT_MSG_FILE="$1" # Read the original commit message ORIGINAL_MESSAGE=$(cat "$COMMIT_MSG_FILE") # Skip adding the prefix if it's already present (prevents duplicates on commit amend) if ! echo "$ORIGINAL_MESSAGE" | grep -q "^$TICKET_PREFIX:"; then # Write the prefixed message back to the file echo "$TICKET_PREFIX: $ORIGINAL_MESSAGE" > "$COMMIT_MSG_FILE" fi
3. Ensure the hook has execution permissions
If the script isn't executable, run this command to fix it:
chmod +x .husky/commit-msg
Alternative: Use a JavaScript script (Vue/Nuxt-friendly)
If you'd rather write the logic in JS (common in Vue/Nuxt projects), create a .husky/commit-msg.js file with this code:
const fs = require('fs'); const { execSync } = require('child_process'); // Get current branch name const branchName = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim(); // Extract the prefix up to the first underscore const ticketPrefix = branchName.split('_')[0]; // Path to the commit message file const commitMsgPath = process.argv[2]; // Read original message const originalMsg = fs.readFileSync(commitMsgPath, 'utf8').trim(); // Skip if prefix already exists if (!originalMsg.startsWith(`${ticketPrefix}:`)) { const newMsg = `${ticketPrefix}: ${originalMsg}`; fs.writeFileSync(commitMsgPath, newMsg); }
Then update your .husky/commit-msg shell script to run the JS file:
#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" node .husky/commit-msg.js "$1"
Test it out
Switch to a branch like JIRA-123_fix_problem, run:
git commit -m 'Fix problem' --allow-empty
Then check the commit log with git log --oneline — you should see the message formatted as JIRA-123: Fix problem.
This approach keeps Husky fully functional while preserving your custom commit message behavior, and since the .husky directory is committed to Git, this hook will work consistently for all team members.
内容的提问来源于stack exchange,提问作者RSeidelsohn

