本文目录导读:

我来详细说明如何在脚本中实现 Pre-commit 钩子:
基础 Pre-commit 钩子脚本
基础示例(Shell脚本)
#!/bin/bash
# .git/hooks/pre-commit
echo "Running pre-commit checks..."
# 获取暂存区文件
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
if [ -z "$STAGED_FILES" ]; then
echo "No files staged for commit"
exit 0
fi
# 检查是否有调试代码
for FILE in $STAGED_FILES; do
if grep -n "console.log\|debugger\|TODO" "$FILE" 2>/dev/null; then
echo "Warning: Found debug code in $FILE"
exit 1
fi
done
# 检查文件大小
for FILE in $STAGED_FILES; do
if [ -f "$FILE" ]; then
FILESIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE")
if [ $FILESIZE -gt 5242880 ]; then # 5MB
echo "Error: $FILE is too large ($FILESIZE bytes)"
exit 1
fi
fi
done
echo "All checks passed!"
exit 0
语言特定的 Pre-commit 钩子
Python 项目
#!/bin/bash
# .git/hooks/pre-commit
# Python代码检查
echo "Running Python checks..."
STAGED_PY_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.py$')
if [ -n "$STAGED_PY_FILES" ]; then
# 语法检查
python -m py_compile $STAGED_PY_FILES 2>&1
if [ $? -ne 0 ]; then
echo "Python syntax check failed"
exit 1
fi
# Flake8代码风格检查
flake8 $STAGED_PY_FILES
if [ $? -ne 0 ]; then
echo "Flake8 style check failed"
exit 1
fi
# 运行测试
python -m pytest tests/ --quick
fi
JavaScript/Node.js 项目
#!/bin/bash
# .git/hooks/pre-commit
echo "Running JavaScript checks..."
STAGED_JS_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')
if [ -n "$STAGED_JS_FILES" ]; then
# ESLint检查
npx eslint $STAGED_JS_FILES
if [ $? -ne 0 ]; then
echo "ESLint check failed"
exit 1
fi
# Prettier格式化检查
npx prettier --check $STAGED_JS_FILES
if [ $? -ne 0 ]; then
echo "Prettier formatting check failed"
exit 1
fi
fi
完整的 Pre-commit 钩子框架
#!/bin/bash
# .git/hooks/pre-commit
set -e
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 配置
MAX_LINE_LENGTH=120
BANNED_PATTERNS=("console\.log" "debugger" "TODO" "FIXME" "xxx")
BANNED_EXTENSIONS=(".min.js" ".min.css" ".map")
# 获取暂存区文件
get_staged_files() {
git diff --cached --name-only --diff-filter=ACM
}
# 检查禁止的模式
check_banned_patterns() {
local files=$1
local has_error=0
for FILE in $files; do
if [ -f "$FILE" ]; then
for pattern in "${BANNED_PATTERNS[@]}"; do
if grep -qn "$pattern" "$FILE" 2>/dev/null; then
log_error "Found '$pattern' in $FILE"
has_error=1
fi
done
fi
done
return $has_error
}
# 检查文件扩展名
check_extension() {
local files=$1
local has_error=0
for FILE in $files; do
for ext in "${BANNED_EXTENSIONS[@]}"; do
if [[ "$FILE" == *"$ext" ]]; then
log_error "Banned extension $ext found: $FILE"
has_error=1
fi
done
done
return $has_error
}
# 检查行长度
check_line_length() {
local files=$1
local has_error=0
for FILE in $files; do
if [[ "$FILE" =~ \.(py|js|ts|java|rb|go)$ ]]; then
local long_lines=$(awk "length > $MAX_LINE_LENGTH" "$FILE" 2>/dev/null | wc -l)
if [ $long_lines -gt 0 ]; then
log_warn "$FILE has $long_lines lines exceeding $MAX_LINE_LENGTH characters"
fi
fi
done
return 0 # 只是警告,不阻止提交
}
# 检查大文件
check_large_files() {
local files=$1
local max_size_mb=10
local has_error=0
for FILE in $files; do
if [ -f "$FILE" ]; then
local size_kb=$(du -k "$FILE" | cut -f1)
if [ $size_kb -gt $(($max_size_mb * 1024)) ]; then
log_error "$FILE is larger than ${max_size_mb}MB"
has_error=1
fi
fi
done
return $has_error
}
# 主函数
main() {
local staged_files=$(get_staged_files)
if [ -z "$staged_files" ]; then
log_info "No files staged for commit"
exit 0
fi
log_info "Running pre-commit checks on $(echo "$staged_files" | wc -l) files..."
# 运行所有检查
check_extension "$staged_files" || exit 1
check_banned_patterns "$staged_files" || exit 1
check_line_length "$staged_files"
check_large_files "$staged_files" || exit 1
# 运行语言特定的检查
local py_files=$(echo "$staged_files" | grep '\.py$')
local js_files=$(echo "$staged_files" | grep '\.js$')
if [ -n "$py_files" ]; then
log_info "Running Python checks..."
python -m py_compile $py_files 2>&1 || exit 1
flake8 $py_files 2>/dev/null || true # 只是警告
fi
if [ -n "$js_files" ]; then
log_info "Running JavaScript checks..."
npx eslint $js_files 2>/dev/null || exit 1
fi
log_info "All pre-commit checks passed!"
exit 0
}
# 执行主函数
main
使用 pre-commit 框架
安装和配置
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- id: check-merge-conflict
- id: check-case-conflict
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
安装框架钩子
# 安装 pre-commit pip install pre-commit # 或者使用 npm npm install -g pre-commit # 在项目中安装钩子 pre-commit install # 手动运行检查 pre-commit run --all-files # 更新钩子版本 pre-commit autoupdate
高级功能
跳过某些检查
# 使用环境变量跳过检查 git commit -m "message" --no-verify # 或者设置环境变量 SKIP=flake8 git commit -m "message"
阶段性检查
#!/bin/bash
# .git/hooks/pre-commit
# 只检查修改的部分(不是整个文件)
check_staged_lines() {
local file=$1
local staged_lines=$(git diff --cached -U0 "$file" | grep "^@@" | sed 's/.*+\([0-9]*\).*/\1/')
for line_num in $staged_lines; do
local content=$(sed -n "${line_num}p" "$file")
if echo "$content" | grep -q "console.log"; then
echo "Debug code found at line $line_num in $file"
return 1
fi
done
}
自定义检查脚本
#!/bin/bash
# scripts/pre-commit-custom.sh
run_custom_checks() {
local files=$1
# 检查文件命名规范
for file in $files; do
if [[ "$file" =~ [A-Z] ]] && [[ "$file" != *"Config"* ]]; then
echo "Warning: $file contains uppercase characters"
fi
done
# 检查提交信息格式
local commit_msg=$(git log --format=%B -n1 HEAD)
if [[ ! "$commit_msg" =~ ^(feat|fix|docs|style|refactor|test|chore): ]]; then
echo "Commit message should follow conventional commit format"
exit 1
fi
}
最佳实践
- 快速执行:钩子应该快速执行,不要运行完整的测试套件
- 清晰反馈:提供明确的错误信息和修复建议
- 可跳过:允许紧急情况下跳过检查
- 逐步增强:先添加宽松检查,逐步严格
- 团队共享:将钩子脚本保存在项目中
- 自动修复:尽可能自动修复格式问题
这些脚本可以根据项目需求进行调整和扩展,建议先在测试环境中验证钩子,然后再应用到生产环境。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播