44STYLE=$( git config --get hooks.clangformat.style)
55
66GIT_ROOT=$( git rev-parse --show-toplevel)
7- # 定义 clang-format.exe 和 clang-tidy.exe 的路径
7+ # 定义 clang-format.exe 的路径(假设在根目录下)
88CLANG_FORMAT=" ${GIT_ROOT} /clang-format.exe"
9- CLANG_TIDY=" ${GIT_ROOT} /clang-tidy/clang-tidy.exe"
109# 检测操作系统类型
1110case " $( uname -s) " in
1211 Linux* ) OS=Linux;;
1817# 调用对应平台的子脚本
1918if [ " $OS " = " Windows" ]; then
2019 CLANG_FORMAT=" ${GIT_ROOT} /clang-format.exe"
21- CLANG_TIDY=" ${GIT_ROOT} /clang-tidy/clang-tidy.exe"
2220else
2321 # 检查clang-format是否安装
2422 if ! command -v clang-format > /dev/null 2>&1 ; then
2826 echo " Linux: sudo apt-get install clang-format" >&2
2927 exit 1
3028 fi
31- # 检查clang-tidy是否安装
32- if ! command -v clang-tidy > /dev/null 2>&1 ; then
33- echo " 错误:未安装 clang-tidy" >&2
34- echo " 安装方法:" >&2
35- echo " macOS: brew install clang-tidy" >&2
36- echo " Linux: sudo apt-get install clang-tidy" >&2
37- exit 1
38- fi
3929 CLANG_FORMAT=" clang-format"
40- CLANG_TIDY=" clang-tidy"
4130fi
4231
43- # 检查clang-format文件是否存在
32+ # 检查文件是否存在
4433if [ ! -f " ${CLANG_FORMAT} " ]; then
4534 echo " 错误:未找到 ${CLANG_FORMAT} ,请确保 clang-format.exe 在项目根目录下!" >&2
4635 exit 1
4736fi
4837
49- # 检查clang-tidy文件是否存在
50- if [ ! -f " ${CLANG_TIDY} " ]; then
51- echo " 错误:未找到 ${CLANG_TIDY} ,请确保 clang-tidy.exe 在项目根目录下!" >&2
52- exit 1
53- fi
54-
5538if [ -n " ${STYLE} " ]; then
5639 STYLEARG=" -style=${STYLE} "
5740else
6346 fi
6447fi
6548
66- # 检查是否有.clang-tidy配置文件
67- if [ -f " $( git rev-parse --show-toplevel) /clang-tidy/.clang-tidy" ]; then
68- TIDY_CONFIG=" --config-file=$( git rev-parse --show-toplevel) /clang-tidy/.clang-tidy"
69- else
70- TIDY_CONFIG=" "
71- fi
72-
7349# 格式化单个文件函数
7450format_file () {
7551 file=" ${1} "
7652 if [ -f " ${file} " ]; then
77- " ${CLANG_FORMAT} " -i ${STYLEARG} " ${file} "
53+ " ${CLANG_FORMAT} " -i ${STYLEARG} " ${file} "
7854 echo " clang-format ${STYLEARG} -i ${file} "
55+
56+ # 统一行尾符为CRLF(Windows格式)
57+ normalize_line_endings " ${file} "
58+
59+ # 在文件第一行添加格式化标记
60+ add_format_marker " ${file} "
61+
7962 git add " ${file} "
8063 fi
8164}
8265
83- # 对单个文件运行clang-tidy检查
84- tidy_file () {
66+ # 统一文件行尾符处理
67+ normalize_line_endings () {
8568 file=" ${1} "
8669 if [ -f " ${file} " ]; then
87- # 定义日志文件路径
88- TIDY_LOG=" ${GIT_ROOT} /clang-tidy-report.log"
89-
90- echo " 运行 clang-tidy ${TIDY_CONFIG} --header-filter=\" ^$( realpath " ${file} " ) $\" ${file} "
91-
92- # 在日志文件中添加分隔符和文件信息
93- echo " ========================================" >> " ${TIDY_LOG} "
94- echo " 检查文件: ${file} " >> " ${TIDY_LOG} "
95- echo " 时间: $( date) " >> " ${TIDY_LOG} "
96- echo " ========================================" >> " ${TIDY_LOG} "
97-
98- # 运行 clang-tidy 并将输出重定向到日志文件
99- # 使用 --header-filter 限制只检查目标文件,不检查包含的头文件
100- tidy_output=$( " ${CLANG_TIDY} " ${TIDY_CONFIG} --header-filter=" ^$( realpath " ${file} " ) $" " ${file} " 2>&1 )
101- tidy_exit_code=$?
70+ # 由于Git的core.autocrlf=true会自动处理行尾符转换
71+ # 我们只需要确保文件内容一致性,让Git处理行尾符
72+ # 这样可以避免与Git的自动转换产生冲突
10273
103- # 将完整输出写入日志文件
104- echo " $tidy_output " >> " ${TIDY_LOG} "
105- echo " " >> " ${TIDY_LOG} "
106-
107- # 检查是否是编译数据库相关的错误
108- if echo " $tidy_output " | grep -q " compilation database" ; then
109- echo " 提示: ${file} 的 clang-tidy 检查跳过(缺少编译数据库)" >&2
110- echo " 跳过: 缺少编译数据库" >> " ${TIDY_LOG} "
111- elif echo " $tidy_output " | grep -q " unable to handle compilation" ; then
112- echo " 提示: ${file} 的 clang-tidy 检查跳过(无法处理编译)" >&2
113- echo " 跳过: 无法处理编译" >> " ${TIDY_LOG} "
114- elif [ $tidy_exit_code -ne 0 ]; then
115- # 统计警告数量
116- warning_count=$( echo " $tidy_output " | grep -c " warning:" )
117- error_count=$( echo " $tidy_output " | grep -c " error:" )
118-
119- if [ $warning_count -gt 0 ] || [ $error_count -gt 0 ]; then
120- echo " clang-tidy 检查完成: ${file} (发现 ${warning_count} 个警告, ${error_count} 个错误)"
121- echo " 详细报告已保存到: ${TIDY_LOG} "
74+ # 检查文件是否有混合行尾符
75+ if grep -q $' \r\n ' " ${file} " && grep -q $' [^\r ]\n ' " ${file} " ; then
76+ # 文件有混合行尾符,统一处理
77+ if [ " $OS " = " Windows" ]; then
78+ # Windows环境:移除所有CR,让Git的autocrlf处理
79+ tr -d ' \r' < " ${file} " > " ${file} .tmp" && mv " ${file} .tmp" " ${file} "
80+ echo " Normalized mixed line endings for ${file} "
12281 else
123- echo " clang-tidy 检查完成: ${file} (其他问题,详见日志)"
124- echo " 详细报告已保存到: ${TIDY_LOG} "
82+ # Unix/Linux环境:统一为LF
83+ tr -d ' \r' < " ${file} " > " ${file} .tmp" && mv " ${file} .tmp" " ${file} "
84+ echo " Normalized line endings to LF for ${file} "
12585 fi
86+ fi
87+ fi
88+ }
89+
90+ # 添加格式化标记到文件第一行
91+ add_format_marker () {
92+ file=" ${1} "
93+ if [ -f " ${file} " ]; then
94+ # 获取文件扩展名
95+ ext=" ${file##* .} "
96+
97+ # 根据文件类型选择注释符号
98+ case " ${ext} " in
99+ cpp|cc|c|h|hpp)
100+ marker=" // [FORMATTED BY CLANG-FORMAT $( date ' +%Y-%m-%d %H:%M:%S' ) ]"
101+ ;;
102+ * )
103+ marker=" // [FORMATTED BY CLANG-FORMAT $( date ' +%Y-%m-%d %H:%M:%S' ) ]"
104+ ;;
105+ esac
106+
107+ # 检查第一行是否已经有格式化标记
108+ first_line=$( head -n 1 " ${file} " )
109+ if [[ " ${first_line} " == * " [FORMATTED BY CLANG-FORMAT" * ]]; then
110+ # 如果已有标记,更新第一行的时间戳
111+ temp_file=$( mktemp)
112+ echo " ${marker} " > " ${temp_file} "
113+ tail -n +2 " ${file} " >> " ${temp_file} "
114+ mv " ${temp_file} " " ${file} "
115+ echo " Updated format marker in ${file} "
126116 else
127- # 成功执行
128- if [ -n " $tidy_output " ]; then
129- warning_count=$( echo " $tidy_output " | grep -c " warning:" )
130- if [ $warning_count -gt 0 ]; then
131- echo " clang-tidy 检查完成: ${file} (发现 ${warning_count} 个警告)"
132- echo " 详细报告已保存到: ${TIDY_LOG} "
133- else
134- echo " clang-tidy 检查完成: ${file} (无问题)"
135- fi
136- else
137- echo " clang-tidy 检查完成: ${file} (无问题)"
138- fi
117+ # 如果没有标记,添加新标记到第一行
118+ temp_file=$( mktemp)
119+ echo " ${marker} " > " ${temp_file} "
120+ cat " ${file} " >> " ${temp_file} "
121+ mv " ${temp_file} " " ${file} "
122+ echo " Added format marker to ${file} "
139123 fi
140124 fi
141125}
142126
143- # 检查是否需要格式化和静态检查
144- is_need_check () {
127+ # 检查是否需要格式化
128+ is_need_format () {
145129 file=" ${1} "
146130 need=1
147131
@@ -162,29 +146,24 @@ is_need_check() {
162146
163147case " ${1} " in
164148 --about )
165- echo " Runs clang-format and clang-tidy on source files"
149+ echo " Runs clang-format on source files"
166150 ;;
167151 * )
168- # 初始化 clang-tidy 日志文件
169- TIDY_LOG=" ${GIT_ROOT} /clang-tidy-report.log"
170- echo " ======================================== clang-tidy 检查报告 ========================================" > " ${TIDY_LOG} "
171- echo " 开始时间: $( date) " >> " ${TIDY_LOG} "
172- echo " 项目路径: ${GIT_ROOT} " >> " ${TIDY_LOG} "
173- echo " =====================================================================================================" >> " ${TIDY_LOG} "
174- echo " " >> " ${TIDY_LOG} "
152+ # 获取暂存区的文件列表
153+ # 对于amend操作,也需要检查当前暂存的文件
154+ if git rev-parse --verify HEAD > /dev/null 2>&1 ; then
155+ # 有提交历史,使用diff-index
156+ files=$( git diff-index --cached --name-only HEAD)
157+ else
158+ # 初始提交,使用diff-index --cached
159+ files=$( git diff-index --cached --name-only --diff-filter=A HEAD 2> /dev/null || git ls-files --cached)
160+ fi
175161
176- for file in $( git diff-index --cached --name-only HEAD ) ; do
177- is_need_check " ${file} "
162+ for file in $files ; do
163+ is_need_format " ${file} "
178164 if [[ $? -eq 1 ]]; then
179165 format_file " ${file} "
180- tidy_file " ${file} "
181166 fi
182167 done
183-
184- # 在日志文件末尾添加总结
185- echo " " >> " ${TIDY_LOG} "
186- echo " =====================================================================================================" >> " ${TIDY_LOG} "
187- echo " 检查完成时间: $( date) " >> " ${TIDY_LOG} "
188- echo " =====================================================================================================" >> " ${TIDY_LOG} "
189168 ;;
190169esac
0 commit comments