在git主分支清理代码注释的方案

需求:
有两个分支 master 和 dev,dev 保留代码注释,master 去掉代码注释。
把 dev 合并到 master 之后,在 master 分支提交代码之前,先清理注释。
把 master 合并到 dev 的时候,需保证 dev 中的注释内容不受干扰。
要求Git提交日志中不显示因为清理注释而发生改变的文件。

实现方案:

  1. dev 分支合并到 master 分支的时候,使用 git merge --squash dev 命令。
    --squash 选项可以将 dev 分支的所有提交造成的改变一次性打包并入master分支,避免在 master 分支上显示 dev 分支的提交记录。

  2. Git 并没有“pre-add”钩子(也就是在执行 git add 之前的钩子),但是可以用 pre-commit 钩子来在“提交之前”清理注释。
    .git/hooks/pre-commit 中写入以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    #!/bin/bash
    #
    # pre-commit 钩子:
    # 当在 master 分支提交时,自动清除本次提交中修改过文件的注释。
    # 如果清理前后文件内容无变化,则不重新 git add。
    #

    branch=$(git rev-parse --abbrev-ref HEAD)

    # 只在 master 分支启用
    if [ "$branch" != "master" ]; then
    exit 0
    fi

    echo "🔧 [pre-commit] Cleaning comments in modified files (branch: $branch)"

    # 获取当前暂存区的修改文件列表(新增/修改)
    files=$(git diff --cached --name-only --diff-filter=ACM)

    for file in $files; do
    # 仅处理指定类型文件
    if [[ $file =~ \.(php|js|vue|java|kt|go|html)$ ]]; then
    if [ -f "$file" ]; then
    echo " - Checking $file"

    # 创建临时文件
    tmpfile=$(mktemp)

    # 删除前导空格 + // + 反引号包裹的注释(贪婪匹配,不跨行),例:// `这是注释` or // `这是注释`这是注释`
    sed -E 's#\s*//\s*`.*`##g' "$file" > "$tmpfile"

    # 比较清理前后是否有变化,有变化则重新 git add,无变化则继续下一个文件
    if ! cmp -s "$file" "$tmpfile"; then
    echo " → Cleaned: comments removed"
    mv "$tmpfile" "$file"
    git add "$file"
    else
    echo " → Skipped: no change detected"
    rm "$tmpfile"
    fi
    fi
    fi
    done

如果修改的文件太多,导致 pre-commit 钩子执行时间过长,会影响提交效率。
下面的脚本进行了优化,避免重复执行rmgit add命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/bin/bash
#
# pre-commit 钩子(Windows 友好 + 优化版)
# 功能:
# 1. 仅在 master 分支运行
# 2. 只处理本次 commit 修改过的文件
# 3. 仅处理特定后缀文件(.php, .js, .vue, .java, .kt, .go, .html)
# 4. 删除 // `...` 注释(贪婪匹配,不跨行)
# 5. 如果文件清理前后无变化,不重新 git add
#

branch=$(git rev-parse --abbrev-ref HEAD)

# 仅在 master 分支执行
if [ "$branch" != "master" ]; then
exit 0
fi

echo "🔧 [pre-commit] Cleaning comments in modified files (branch: $branch)"

# 临时目录
tmpdir=$(mktemp -d -t comment_strip.XXXXXX)

# 获取当前暂存区新增/修改/复制文件列表
files=$(git diff --cached --name-only --diff-filter=ACM)

# 数组保存最终需要 git add 的文件
changed_files=()

# 定义支持的文件后缀数组
extensions=("php" "js" "vue" "java" "kt" "go" "html")

# 遍历所有文件
for file in $files; do
# 如果不是文件(可能被删除),跳过
if [ ! -f "$file" ]; then
continue
fi

# 获取文件后缀
ext="${file##*.}"

# 如果 ext 不在 extensions 数组中,则跳过
if [[ ! " ${extensions[*]} " =~ " ${ext} " ]]; then
echo " - Skipping $file (unsupported extension)"
continue
fi

echo " - Checking $file"

# 临时文件路径
tmpfile="$tmpdir/$(basename "$file")"

# 优化 sed:删除每行前导空格 + // + 反引号注释(贪婪匹配,不跨行)
# 不使用管道,直接输出到临时文件
sed -E 's#\s*//\s*`.*`##g' "$file" > "$tmpfile"

# 比较清理前后文件内容
if ! cmp -s "$file" "$tmpfile"; then
echo " → Cleaned: comments removed"
# 替换原文件
cp "$tmpfile" "$file"
# 保存到 git add 列表
changed_files+=("$file")
else
echo " → Skipped: no comment match"
fi
done

# 一次性 git add 所有变化文件
if [ ${#changed_files[@]} -gt 0 ]; then
git add "${changed_files[@]}"
echo "✅ [pre-commit] Comments removed & staged."
else
echo "✅ [pre-commit] No changes after cleaning."
fi

# 删除临时目录
rm -rf "$tmpdir"