Windows下Git commit-msg钩子非ASCII字符计数异常问题求助(无额外依赖)
解决Windows下TortoiseGit commit-msg钩子统计俄文(UTF-8)字符长度翻倍问题
这个问题我之前也碰到过——在Git for Windows的bash环境里,默认的字符串长度统计是按字节数来的,而俄文的西里尔字母在UTF-8编码中每个占2个字节,所以${#line}会返回实际字符数的两倍。刚好你不想加额外依赖,那咱们用Git环境自带的工具和配置就能搞定。
原因分析
你的.git/COMMIT_EDITMSG是UTF-8编码,钩子能正确显示俄文字符,说明终端已经支持UTF-8,但bash默认的字符串处理(包括${#}长度统计)在未指定UTF-8 locale的情况下,会把多字节字符拆成单个字节计数。
解决方案1:配置UTF-8 Locale(推荐)
Git for Windows自带的bash 4.2+版本已经支持Unicode字符长度统计,只要在钩子开头设置正确的locale即可:
#!/bin/sh # 强制设置UTF-8 locale,让bash按Unicode字符统计长度 export LC_ALL=en_US.UTF-8 # 读取提交消息文件($1是commit-msg钩子的参数,即COMMIT_EDITMSG路径) while read -r line; do # 去除Windows风格的回车符(避免干扰长度统计) cleaned_line=$(echo "$line" | tr -d '\r') char_length=${#cleaned_line} # 这里替换成你的长度检查逻辑,比如限制每行不超过72字符 if [ "$char_length" -gt 72 ]; then echo "错误:提交消息行长度超过限制(当前$char_length字符,最大允许72)" >&2 exit 1 fi done < "$1"
保存钩子脚本后,记得给它加可执行权限(在Git Bash里运行chmod +x .git/hooks/commit-msg)。
解决方案2:用iconv转码计算(兼容旧版本bash)
如果你的bash版本比较旧,不支持Unicode长度统计,可以用Git环境自带的iconv工具,把UTF-8转成UTF-16(每个BMP字符占2字节),再通过字节数换算字符数:
#!/bin/sh while read -r line; do cleaned_line=$(echo "$line" | tr -d '\r') # 将UTF-8转成UTF-16LE(无BOM),统计字节数后除以2得到字符数 byte_count=$(printf "%s" "$cleaned_line" | iconv -f utf-8 -t utf-16le | wc -c) char_length=$((byte_count / 2)) if [ "$char_length" -gt 72 ]; then echo "错误:提交消息行长度超过限制(当前$char_length字符,最大允许72)" >&2 exit 1 fi done < "$1"
这个方法不需要依赖bash的Unicode支持,完全用Git自带的工具实现。
验证方法
你可以在钩子中加一行调试代码,打印实际字符数和字节数对比:
echo "字符数:$char_length,字节数:${#cleaned_line}"
运行提交测试,俄文行的字符数应该和你实际输入的一致,字节数是它的两倍。
内容的提问来源于stack exchange,提问作者Igor Melnichenko
相关产品推荐
相关产品推荐

