hookehuyr

feat(husky): 使用 prepare-commit-msg + amend 实现 CHANGELOG 自动更新

- 创建 prepare-commit-msg hook
- 创建 update-changelog-prepare.sh 脚本
- 修改 post-commit 检查暂存区并 amend
- 使用 --no-verify 避免 amend 触发循环

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
......@@ -5,7 +5,7 @@
#
# 功能:
# 1. 显示提交成功信息
# 2. 补充 CHANGELOG 中的 commit hash
# 2. 将 CHANGELOG amend 到当前提交(如果需要)
#
# 作者:Claude Code
# 日期:2026-02-28
......@@ -49,36 +49,23 @@ echo " 删除行数: -$LINES_DELETED"
echo ""
# ============================================
# 补充 CHANGELOG 中的 commit hash
# 将 CHANGELOG amend 到当前提交(如果在暂存区)
# ============================================
CHANGELOG_FILE="CHANGELOG.md"
if ! git diff --cached --quiet CHANGELOG.md 2>/dev/null; then
echo "📝 ${BLUE}将 CHANGELOG 加入当前提交...${NC}"
if [ -f "$CHANGELOG_FILE" ]; then
# 检查 CHANGELOG 中是否有 "pending" hash 需要替换
if grep -q "\`pending\`" "$CHANGELOG_FILE"; then
# 获取当前日期时间戳
NOW_TIME=$(date +%H:%M:%S)
TODAY=$(date +%Y-%m-%d)
# 解析 commit message
COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/')
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/')
# 替换 pending hash 为真实的 commit hash
# 使用 sed 进行替换
sed -i.tmp "s/\[\$NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/[$NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE" 2>/dev/null || \
sed -i.tmp "s/\`pending\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/\`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE"
# 清理临时文件
rm -f "${CHANGELOG_FILE}.tmp"
# 如果 CHANGELOG 有变更, amend 到当前提交
if ! git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then
git add "$CHANGELOG_FILE"
# 使用 amend 将 CHANGELOG 加入当前提交
# --no-edit: 不修改 commit message
# --no-verify: 跳过 hooks,避免循环
git commit --amend --no-edit --no-verify >/dev/null 2>&1
echo " ${GREEN}✅ CHANGELOG commit hash 已更新${NC}"
fi
if [ $? -eq 0 ]; then
# 获取 amend 后的 hash
NEW_HASH=$(git log -1 --pretty=%h)
echo " ${GREEN}✅ CHANGELOG 已加入提交${NC}"
echo " ${BLUE} 新 Hash: $NEW_HASH${NC}"
else
echo " ${YELLOW}⚠️ CHANGELOG amend 失败${NC}"
fi
fi
......
......@@ -120,37 +120,10 @@ fi
echo " ${GREEN}✅ 改动规模检查通过${NC}"
# ============================================
# 4. 自动更新 CHANGELOG.md(在提交前)
# ============================================
echo ""
echo "📋 ${BLUE}步骤 4/4: 更新 CHANGELOG${NC}"
# 获取暂存的 commit message
COMMIT_MSG_FILE=".git/COMMIT_EDITMSG"
if [ -f "$COMMIT_MSG_FILE" ]; then
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 解析 commit type
COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
# 只对特定类型更新 CHANGELOG
# 跳过: docs(changelog) 类型的提交,避免循环
if echo "$COMMIT_MSG" | head -n 1 | grep -qE "^docs\(changelog\):"; then
echo " ⏭️ 跳过 CHANGELOG 更新(docs(changelog) 类型提交)"
elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then
# 调用 CHANGELOG 更新脚本
bash scripts/changelog/update-changelog-precommit.sh "$COMMIT_MSG_FILE"
else
echo " ⏭️ 跳过 CHANGELOG 更新(类型: $COMMIT_TYPE)"
fi
else
echo " ⚠️ 无法读取 commit message,跳过 CHANGELOG 更新"
fi
# ============================================
# 所有检查通过
# ============================================
echo ""
echo "✅ ${GREEN}所有检查通过!${NC}"
echo "🚀 ${BLUE}开始提交...${NC}"
echo "📝 ${BLUE}CHANGELOG.md 将在 prepare-commit-msg 阶段更新${NC}"
echo ""
......
#!/bin/sh
# ============================================
# Prepare-commit-msg Hook
# ============================================
#
# 功能:
# 1. 自动更新 CHANGELOG.md(包含在当前提交中)
#
# 关键特性:
# - 只在初始提交时执行,amend 时不会触发
# - 配合 post-commit 使用 amend --no-verify 完成流程
#
# 作者:Claude Code
# 日期:2026-02-28
# ============================================
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 获取 commit message 文件
COMMIT_MSG_FILE=$1
COMMIT_SOURCE=$2 # commit 来源:message/template/merge/squash等
# 只在正常的 commit 时执行,跳过 merge/rebase/amend
# amend 时 COMMIT_SOURCE 为空
if [ "$COMMIT_SOURCE" = "message" ] || [ "$COMMIT_SOURCE" = "template" ] || [ "$COMMIT_SOURCE" = "" ]; then
# 检查是否是 amend 操作(通过检查是否已有 commit)
# 如果 HEAD 存在且不是初始提交,可能是 amend
if git rev-parse HEAD >/dev/null 2>&1; then
# 有 HEAD,检查是否是正在 amend
# 简单的判断:如果已经有 commit 且当前没有在 rebase 等操作中
# 这里我们允许继续,因为关键在于 post-commit 的 --no-verify
:
fi
# 读取 commit message
if [ -f "$COMMIT_MSG_FILE" ]; then
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 只处理第一行(subject)
FIRST_LINE=$(echo "$COMMIT_MSG" | head -n 1)
# 解析 commit type
COMMIT_TYPE=$(echo "$FIRST_LINE" | sed -E 's/^([a-z]+)\(.*/\1/')
# 只对特定类型更新 CHANGELOG
# 跳过: docs(changelog) 类型的提交,避免循环
if echo "$FIRST_LINE" | grep -qE "^docs\(changelog\):"; then
# 跳过
:
elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then
echo ""
echo "📝 ${BLUE}更新 CHANGELOG...${NC}"
# 调用 CHANGELOG 更新脚本
bash scripts/changelog/update-changelog-prepare.sh "$COMMIT_MSG_FILE"
fi
fi
fi
This diff is collapsed. Click to expand it.
#!/bin/bash
# ============================================
# CHANGELOG 自动更新脚本(Prepare-commit-msg 版本)
# ============================================
#
# 功能:在 prepare-commit-msg 阶段更新 CHANGELOG.md,加入暂存区
# 配合 post-commit 的 amend --no-verify 完成流程
#
# 作者:Claude Code
# 日期:2026-02-28
# ============================================
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 参数
COMMIT_MSG_FILE=$1
CHANGELOG_FILE="CHANGELOG.md"
# 检查文件是否存在
if [ ! -f "$CHANGELOG_FILE" ]; then
echo " ${YELLOW}⚠️ CHANGELOG.md 不存在,跳过自动更新${NC}"
exit 0
fi
# 读取 commit message
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# 解析 commit message
# 格式: type(scope): subject
if ! echo "$COMMIT_MSG" | grep -qE "^([a-z]+)\(([a-z-]+)\): .{1,50}"; then
# 格式不匹配,跳过
exit 0
fi
# 提取信息
COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/')
COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/')
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/')
# 类型映射到中文
case "$COMMIT_TYPE" in
feat)
CHANGE_TYPE="新增"
;;
fix)
CHANGE_TYPE="修复"
;;
docs)
CHANGE_TYPE="文档"
;;
style)
CHANGE_TYPE="样式"
;;
refactor)
CHANGE_TYPE="优化"
;;
perf)
CHANGE_TYPE="性能"
;;
test)
CHANGE_TYPE="测试"
;;
chore)
CHANGE_TYPE="配置"
;;
revert)
CHANGE_TYPE="回滚"
;;
*)
CHANGE_TYPE="其他"
;;
esac
# 获取当前日期和时间
TODAY=$(date +%Y-%m-%d)
NOW_TIME=$(date +%H:%M:%S)
# 获取暂存的变更文件(使用 git diff --cached)
CHANGED_FILES=$(git diff --cached --name-only | tr '\n' '\n' | sed 's/^/- \`/;s/$/`/' | sed '$d')
if [ -z "$CHANGED_FILES" ]; then
CHANGED_FILES="- \`\`"
fi
# 生成 CHANGELOG 条目
CHANGELOG_ENTRY="### $NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT
**影响文件**:
$CHANGED_FILES
**变更摘要**:
- $COMMIT_SUBJECT
---
"
# 检查今天是否已有条目
if grep -q "^## $TODAY" "$CHANGELOG_FILE"; then
# 今天已有条目,找到日期行号,在日期后追加
DATE_LINE=$(grep -n "^## $TODAY" "$CHANGELOG_FILE" | head -1 | cut -d: -f1)
# 创建临时文件
TEMP_FILE=$(mktemp)
# 读取日期行之前的内容
head -n $DATE_LINE "$CHANGELOG_FILE" > "$TEMP_FILE"
# 在日期后追加新条目
echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
# 追加日期行之后的内容(从日期行+1开始)
tail -n +$((DATE_LINE + 1)) "$CHANGELOG_FILE" >> "$TEMP_FILE"
# 替换原文件
mv "$TEMP_FILE" "$CHANGELOG_FILE"
else
# 今天没有条目,创建新的日期部分
TEMP_FILE=$(mktemp)
# 新建日期标题和条目
echo "## $TODAY" > "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE"
echo "" >> "$TEMP_FILE"
# 追加原文件内容
cat "$CHANGELOG_FILE" >> "$TEMP_FILE"
# 替换原文件
mv "$TEMP_FILE" "$CHANGELOG_FILE"
fi
# 将 CHANGELOG.md 加入暂存区
# 重要:这里只是加入暂存区,实际包含在提交中由 post-commit 的 amend 完成
git add "$CHANGELOG_FILE"
echo " ${GREEN}✅ CHANGELOG.md 已自动更新${NC}"
echo " ${BLUE} 类型: $CHANGE_TYPE${NC}"
echo " ${BLUE} 范围: $COMMIT_SCOPE${NC}"
echo " ${BLUE} 描述: $COMMIT_SUBJECT${NC}"