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>
Showing
5 changed files
with
227 additions
and
56 deletions
| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | # | 5 | # |
| 6 | # 功能: | 6 | # 功能: |
| 7 | # 1. 显示提交成功信息 | 7 | # 1. 显示提交成功信息 |
| 8 | -# 2. 补充 CHANGELOG 中的 commit hash | 8 | +# 2. 将 CHANGELOG amend 到当前提交(如果需要) |
| 9 | # | 9 | # |
| 10 | # 作者:Claude Code | 10 | # 作者:Claude Code |
| 11 | # 日期:2026-02-28 | 11 | # 日期:2026-02-28 |
| ... | @@ -49,36 +49,23 @@ echo " 删除行数: -$LINES_DELETED" | ... | @@ -49,36 +49,23 @@ echo " 删除行数: -$LINES_DELETED" |
| 49 | echo "" | 49 | echo "" |
| 50 | 50 | ||
| 51 | # ============================================ | 51 | # ============================================ |
| 52 | -# 补充 CHANGELOG 中的 commit hash | 52 | +# 将 CHANGELOG amend 到当前提交(如果在暂存区) |
| 53 | # ============================================ | 53 | # ============================================ |
| 54 | -CHANGELOG_FILE="CHANGELOG.md" | 54 | +if ! git diff --cached --quiet CHANGELOG.md 2>/dev/null; then |
| 55 | + echo "📝 ${BLUE}将 CHANGELOG 加入当前提交...${NC}" | ||
| 55 | 56 | ||
| 56 | -if [ -f "$CHANGELOG_FILE" ]; then | 57 | + # 使用 amend 将 CHANGELOG 加入当前提交 |
| 57 | - # 检查 CHANGELOG 中是否有 "pending" hash 需要替换 | 58 | + # --no-edit: 不修改 commit message |
| 58 | - if grep -q "\`pending\`" "$CHANGELOG_FILE"; then | 59 | + # --no-verify: 跳过 hooks,避免循环 |
| 59 | - # 获取当前日期时间戳 | ||
| 60 | - NOW_TIME=$(date +%H:%M:%S) | ||
| 61 | - TODAY=$(date +%Y-%m-%d) | ||
| 62 | - | ||
| 63 | - # 解析 commit message | ||
| 64 | - COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/') | ||
| 65 | - COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/') | ||
| 66 | - COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/') | ||
| 67 | - | ||
| 68 | - # 替换 pending hash 为真实的 commit hash | ||
| 69 | - # 使用 sed 进行替换 | ||
| 70 | - 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 || \ | ||
| 71 | - sed -i.tmp "s/\`pending\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/\`$COMMIT_HASH\` - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT/" "$CHANGELOG_FILE" | ||
| 72 | - | ||
| 73 | - # 清理临时文件 | ||
| 74 | - rm -f "${CHANGELOG_FILE}.tmp" | ||
| 75 | - | ||
| 76 | - # 如果 CHANGELOG 有变更, amend 到当前提交 | ||
| 77 | - if ! git diff --quiet "$CHANGELOG_FILE" 2>/dev/null; then | ||
| 78 | - git add "$CHANGELOG_FILE" | ||
| 79 | git commit --amend --no-edit --no-verify >/dev/null 2>&1 | 60 | git commit --amend --no-edit --no-verify >/dev/null 2>&1 |
| 80 | - echo " ${GREEN}✅ CHANGELOG commit hash 已更新${NC}" | 61 | + |
| 81 | - fi | 62 | + if [ $? -eq 0 ]; then |
| 63 | + # 获取 amend 后的 hash | ||
| 64 | + NEW_HASH=$(git log -1 --pretty=%h) | ||
| 65 | + echo " ${GREEN}✅ CHANGELOG 已加入提交${NC}" | ||
| 66 | + echo " ${BLUE} 新 Hash: $NEW_HASH${NC}" | ||
| 67 | + else | ||
| 68 | + echo " ${YELLOW}⚠️ CHANGELOG amend 失败${NC}" | ||
| 82 | fi | 69 | fi |
| 83 | fi | 70 | fi |
| 84 | 71 | ... | ... |
| ... | @@ -120,37 +120,10 @@ fi | ... | @@ -120,37 +120,10 @@ fi |
| 120 | echo " ${GREEN}✅ 改动规模检查通过${NC}" | 120 | echo " ${GREEN}✅ 改动规模检查通过${NC}" |
| 121 | 121 | ||
| 122 | # ============================================ | 122 | # ============================================ |
| 123 | -# 4. 自动更新 CHANGELOG.md(在提交前) | ||
| 124 | -# ============================================ | ||
| 125 | -echo "" | ||
| 126 | -echo "📋 ${BLUE}步骤 4/4: 更新 CHANGELOG${NC}" | ||
| 127 | - | ||
| 128 | -# 获取暂存的 commit message | ||
| 129 | -COMMIT_MSG_FILE=".git/COMMIT_EDITMSG" | ||
| 130 | -if [ -f "$COMMIT_MSG_FILE" ]; then | ||
| 131 | - COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") | ||
| 132 | - | ||
| 133 | - # 解析 commit type | ||
| 134 | - COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/') | ||
| 135 | - | ||
| 136 | - # 只对特定类型更新 CHANGELOG | ||
| 137 | - # 跳过: docs(changelog) 类型的提交,避免循环 | ||
| 138 | - if echo "$COMMIT_MSG" | head -n 1 | grep -qE "^docs\(changelog\):"; then | ||
| 139 | - echo " ⏭️ 跳过 CHANGELOG 更新(docs(changelog) 类型提交)" | ||
| 140 | - elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then | ||
| 141 | - # 调用 CHANGELOG 更新脚本 | ||
| 142 | - bash scripts/changelog/update-changelog-precommit.sh "$COMMIT_MSG_FILE" | ||
| 143 | - else | ||
| 144 | - echo " ⏭️ 跳过 CHANGELOG 更新(类型: $COMMIT_TYPE)" | ||
| 145 | - fi | ||
| 146 | -else | ||
| 147 | - echo " ⚠️ 无法读取 commit message,跳过 CHANGELOG 更新" | ||
| 148 | -fi | ||
| 149 | - | ||
| 150 | -# ============================================ | ||
| 151 | # 所有检查通过 | 123 | # 所有检查通过 |
| 152 | # ============================================ | 124 | # ============================================ |
| 153 | echo "" | 125 | echo "" |
| 154 | echo "✅ ${GREEN}所有检查通过!${NC}" | 126 | echo "✅ ${GREEN}所有检查通过!${NC}" |
| 155 | echo "🚀 ${BLUE}开始提交...${NC}" | 127 | echo "🚀 ${BLUE}开始提交...${NC}" |
| 128 | +echo "📝 ${BLUE}CHANGELOG.md 将在 prepare-commit-msg 阶段更新${NC}" | ||
| 156 | echo "" | 129 | echo "" | ... | ... |
.husky/prepare-commit-msg
0 → 100755
| 1 | +#!/bin/sh | ||
| 2 | +# ============================================ | ||
| 3 | +# Prepare-commit-msg Hook | ||
| 4 | +# ============================================ | ||
| 5 | +# | ||
| 6 | +# 功能: | ||
| 7 | +# 1. 自动更新 CHANGELOG.md(包含在当前提交中) | ||
| 8 | +# | ||
| 9 | +# 关键特性: | ||
| 10 | +# - 只在初始提交时执行,amend 时不会触发 | ||
| 11 | +# - 配合 post-commit 使用 amend --no-verify 完成流程 | ||
| 12 | +# | ||
| 13 | +# 作者:Claude Code | ||
| 14 | +# 日期:2026-02-28 | ||
| 15 | +# ============================================ | ||
| 16 | + | ||
| 17 | +# 颜色定义 | ||
| 18 | +RED='\033[0;31m' | ||
| 19 | +GREEN='\033[0;32m' | ||
| 20 | +BLUE='\033[0;34m' | ||
| 21 | +YELLOW='\033[1;33m' | ||
| 22 | +NC='\033[0m' # No Color | ||
| 23 | + | ||
| 24 | +# 获取 commit message 文件 | ||
| 25 | +COMMIT_MSG_FILE=$1 | ||
| 26 | +COMMIT_SOURCE=$2 # commit 来源:message/template/merge/squash等 | ||
| 27 | + | ||
| 28 | +# 只在正常的 commit 时执行,跳过 merge/rebase/amend | ||
| 29 | +# amend 时 COMMIT_SOURCE 为空 | ||
| 30 | +if [ "$COMMIT_SOURCE" = "message" ] || [ "$COMMIT_SOURCE" = "template" ] || [ "$COMMIT_SOURCE" = "" ]; then | ||
| 31 | + # 检查是否是 amend 操作(通过检查是否已有 commit) | ||
| 32 | + # 如果 HEAD 存在且不是初始提交,可能是 amend | ||
| 33 | + if git rev-parse HEAD >/dev/null 2>&1; then | ||
| 34 | + # 有 HEAD,检查是否是正在 amend | ||
| 35 | + # 简单的判断:如果已经有 commit 且当前没有在 rebase 等操作中 | ||
| 36 | + # 这里我们允许继续,因为关键在于 post-commit 的 --no-verify | ||
| 37 | + : | ||
| 38 | + fi | ||
| 39 | + | ||
| 40 | + # 读取 commit message | ||
| 41 | + if [ -f "$COMMIT_MSG_FILE" ]; then | ||
| 42 | + COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") | ||
| 43 | + | ||
| 44 | + # 只处理第一行(subject) | ||
| 45 | + FIRST_LINE=$(echo "$COMMIT_MSG" | head -n 1) | ||
| 46 | + | ||
| 47 | + # 解析 commit type | ||
| 48 | + COMMIT_TYPE=$(echo "$FIRST_LINE" | sed -E 's/^([a-z]+)\(.*/\1/') | ||
| 49 | + | ||
| 50 | + # 只对特定类型更新 CHANGELOG | ||
| 51 | + # 跳过: docs(changelog) 类型的提交,避免循环 | ||
| 52 | + if echo "$FIRST_LINE" | grep -qE "^docs\(changelog\):"; then | ||
| 53 | + # 跳过 | ||
| 54 | + : | ||
| 55 | + elif [ "$COMMIT_TYPE" = "feat" ] || [ "$COMMIT_TYPE" = "fix" ] || [ "$COMMIT_TYPE" = "refactor" ] || [ "$COMMIT_TYPE" = "perf" ]; then | ||
| 56 | + echo "" | ||
| 57 | + echo "📝 ${BLUE}更新 CHANGELOG...${NC}" | ||
| 58 | + | ||
| 59 | + # 调用 CHANGELOG 更新脚本 | ||
| 60 | + bash scripts/changelog/update-changelog-prepare.sh "$COMMIT_MSG_FILE" | ||
| 61 | + fi | ||
| 62 | + fi | ||
| 63 | +fi |
This diff is collapsed. Click to expand it.
| 1 | +#!/bin/bash | ||
| 2 | + | ||
| 3 | +# ============================================ | ||
| 4 | +# CHANGELOG 自动更新脚本(Prepare-commit-msg 版本) | ||
| 5 | +# ============================================ | ||
| 6 | +# | ||
| 7 | +# 功能:在 prepare-commit-msg 阶段更新 CHANGELOG.md,加入暂存区 | ||
| 8 | +# 配合 post-commit 的 amend --no-verify 完成流程 | ||
| 9 | +# | ||
| 10 | +# 作者:Claude Code | ||
| 11 | +# 日期:2026-02-28 | ||
| 12 | +# ============================================ | ||
| 13 | + | ||
| 14 | +set -e | ||
| 15 | + | ||
| 16 | +# 颜色定义 | ||
| 17 | +RED='\033[0;31m' | ||
| 18 | +GREEN='\033[0;32m' | ||
| 19 | +YELLOW='\033[1;33m' | ||
| 20 | +BLUE='\033[0;34m' | ||
| 21 | +NC='\033[0m' # No Color | ||
| 22 | + | ||
| 23 | +# 参数 | ||
| 24 | +COMMIT_MSG_FILE=$1 | ||
| 25 | +CHANGELOG_FILE="CHANGELOG.md" | ||
| 26 | + | ||
| 27 | +# 检查文件是否存在 | ||
| 28 | +if [ ! -f "$CHANGELOG_FILE" ]; then | ||
| 29 | + echo " ${YELLOW}⚠️ CHANGELOG.md 不存在,跳过自动更新${NC}" | ||
| 30 | + exit 0 | ||
| 31 | +fi | ||
| 32 | + | ||
| 33 | +# 读取 commit message | ||
| 34 | +COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") | ||
| 35 | + | ||
| 36 | +# 解析 commit message | ||
| 37 | +# 格式: type(scope): subject | ||
| 38 | +if ! echo "$COMMIT_MSG" | grep -qE "^([a-z]+)\(([a-z-]+)\): .{1,50}"; then | ||
| 39 | + # 格式不匹配,跳过 | ||
| 40 | + exit 0 | ||
| 41 | +fi | ||
| 42 | + | ||
| 43 | +# 提取信息 | ||
| 44 | +COMMIT_TYPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^([a-z]+)\(.*/\1/') | ||
| 45 | +COMMIT_SCOPE=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\(([a-z-]+)\).*/\1/') | ||
| 46 | +COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1 | sed -E 's/^[a-z]+\([a-z-]+\): (.*)$/\1/') | ||
| 47 | + | ||
| 48 | +# 类型映射到中文 | ||
| 49 | +case "$COMMIT_TYPE" in | ||
| 50 | + feat) | ||
| 51 | + CHANGE_TYPE="新增" | ||
| 52 | + ;; | ||
| 53 | + fix) | ||
| 54 | + CHANGE_TYPE="修复" | ||
| 55 | + ;; | ||
| 56 | + docs) | ||
| 57 | + CHANGE_TYPE="文档" | ||
| 58 | + ;; | ||
| 59 | + style) | ||
| 60 | + CHANGE_TYPE="样式" | ||
| 61 | + ;; | ||
| 62 | + refactor) | ||
| 63 | + CHANGE_TYPE="优化" | ||
| 64 | + ;; | ||
| 65 | + perf) | ||
| 66 | + CHANGE_TYPE="性能" | ||
| 67 | + ;; | ||
| 68 | + test) | ||
| 69 | + CHANGE_TYPE="测试" | ||
| 70 | + ;; | ||
| 71 | + chore) | ||
| 72 | + CHANGE_TYPE="配置" | ||
| 73 | + ;; | ||
| 74 | + revert) | ||
| 75 | + CHANGE_TYPE="回滚" | ||
| 76 | + ;; | ||
| 77 | + *) | ||
| 78 | + CHANGE_TYPE="其他" | ||
| 79 | + ;; | ||
| 80 | +esac | ||
| 81 | + | ||
| 82 | +# 获取当前日期和时间 | ||
| 83 | +TODAY=$(date +%Y-%m-%d) | ||
| 84 | +NOW_TIME=$(date +%H:%M:%S) | ||
| 85 | + | ||
| 86 | +# 获取暂存的变更文件(使用 git diff --cached) | ||
| 87 | +CHANGED_FILES=$(git diff --cached --name-only | tr '\n' '\n' | sed 's/^/- \`/;s/$/`/' | sed '$d') | ||
| 88 | +if [ -z "$CHANGED_FILES" ]; then | ||
| 89 | + CHANGED_FILES="- \`无\`" | ||
| 90 | +fi | ||
| 91 | + | ||
| 92 | +# 生成 CHANGELOG 条目 | ||
| 93 | +CHANGELOG_ENTRY="### $NOW_TIME - $COMMIT_TYPE($COMMIT_SCOPE): $COMMIT_SUBJECT | ||
| 94 | + | ||
| 95 | +**影响文件**: | ||
| 96 | +$CHANGED_FILES | ||
| 97 | + | ||
| 98 | +**变更摘要**: | ||
| 99 | +- $COMMIT_SUBJECT | ||
| 100 | + | ||
| 101 | +--- | ||
| 102 | + | ||
| 103 | +" | ||
| 104 | + | ||
| 105 | +# 检查今天是否已有条目 | ||
| 106 | +if grep -q "^## $TODAY" "$CHANGELOG_FILE"; then | ||
| 107 | + # 今天已有条目,找到日期行号,在日期后追加 | ||
| 108 | + DATE_LINE=$(grep -n "^## $TODAY" "$CHANGELOG_FILE" | head -1 | cut -d: -f1) | ||
| 109 | + | ||
| 110 | + # 创建临时文件 | ||
| 111 | + TEMP_FILE=$(mktemp) | ||
| 112 | + | ||
| 113 | + # 读取日期行之前的内容 | ||
| 114 | + head -n $DATE_LINE "$CHANGELOG_FILE" > "$TEMP_FILE" | ||
| 115 | + | ||
| 116 | + # 在日期后追加新条目 | ||
| 117 | + echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE" | ||
| 118 | + | ||
| 119 | + # 追加日期行之后的内容(从日期行+1开始) | ||
| 120 | + tail -n +$((DATE_LINE + 1)) "$CHANGELOG_FILE" >> "$TEMP_FILE" | ||
| 121 | + | ||
| 122 | + # 替换原文件 | ||
| 123 | + mv "$TEMP_FILE" "$CHANGELOG_FILE" | ||
| 124 | +else | ||
| 125 | + # 今天没有条目,创建新的日期部分 | ||
| 126 | + TEMP_FILE=$(mktemp) | ||
| 127 | + | ||
| 128 | + # 新建日期标题和条目 | ||
| 129 | + echo "## $TODAY" > "$TEMP_FILE" | ||
| 130 | + echo "" >> "$TEMP_FILE" | ||
| 131 | + echo "$CHANGELOG_ENTRY" >> "$TEMP_FILE" | ||
| 132 | + echo "" >> "$TEMP_FILE" | ||
| 133 | + | ||
| 134 | + # 追加原文件内容 | ||
| 135 | + cat "$CHANGELOG_FILE" >> "$TEMP_FILE" | ||
| 136 | + | ||
| 137 | + # 替换原文件 | ||
| 138 | + mv "$TEMP_FILE" "$CHANGELOG_FILE" | ||
| 139 | +fi | ||
| 140 | + | ||
| 141 | +# 将 CHANGELOG.md 加入暂存区 | ||
| 142 | +# 重要:这里只是加入暂存区,实际包含在提交中由 post-commit 的 amend 完成 | ||
| 143 | +git add "$CHANGELOG_FILE" | ||
| 144 | + | ||
| 145 | +echo " ${GREEN}✅ CHANGELOG.md 已自动更新${NC}" | ||
| 146 | +echo " ${BLUE} 类型: $CHANGE_TYPE${NC}" | ||
| 147 | +echo " ${BLUE} 范围: $COMMIT_SCOPE${NC}" | ||
| 148 | +echo " ${BLUE} 描述: $COMMIT_SUBJECT${NC}" |
-
Please register or login to post a comment