实现 Git 挂钩

已完成

本指南介绍如何为开发团队创建、部署和管理 Git 挂钩。 了解现代跨平台技术、以安全为中心的实现,以及在大型开发团队中扩展软件挂钩的策略。

新式 Git 挂钩设置

Git 挂钩实现需要仔细考虑跨平台兼容性、可维护性和团队部署策略。 新式方法侧重于版本控制的挂钩管理和自动分发,而不是手动设置。

跨平台钩子开发

现代开发环境需要在 Windows、macOS 和 Linux 上以相同方式工作的 Git 挂钩。

通用实现

#!/usr/bin/env bash
# Cross-platform compatible shebang that automatically finds bash interpreter
# Works consistently across Windows Git Bash, macOS, and Linux environments

此方法消除了导致传统实现中出现问题的特定于平台的路径问题,并确保在不同开发环境中的行为一致。

环境检测策略

#!/usr/bin/env bash
# Smart environment detection for platform-specific optimizations
detect_environment() {
    if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
        PLATFORM="windows"
        PYTHON_CMD="python"
    elif [[ "$OSTYPE" == "darwin"* ]]; then
        PLATFORM="macos"
        PYTHON_CMD="python3"
    else
        PLATFORM="linux"
        PYTHON_CMD="python3"
    fi
}

企业预提交钩子实施

以安全为中心的凭据检测

实现超越简单关键字匹配的复杂凭据检测:

#!/usr/bin/env bash
# Advanced credential detection with pattern recognition

check_credentials() {
    local staged_files=$(git diff --cached --name-only)
    local violations=""

    # Define comprehensive credential patterns
    local patterns=(
        "password\s*[=:]\s*['\"][^'\"]{8,}"
        "api[_-]?key\s*[=:]\s*['\"][^'\"]{20,}"
        "secret\s*[=:]\s*['\"][^'\"]{16,}"
        "token\s*[=:]\s*['\"][^'\"]{24,}"
        "-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----"
        "mysql://.*:.*@"
        "postgresql://.*:.*@"
    )

    for file in $staged_files; do
        if [ -f "$file" ]; then
            for pattern in "${patterns[@]}"; do
                if git show ":$file" | grep -qiE "$pattern"; then
                    violations+="Potential credential detected in $file\n"
                fi
            done
        fi
    done

    if [ ! -z "$violations" ]; then
        echo -e "Security Alert: Credential Detection\n"
        echo -e "$violations"
        echo -e "Please remove sensitive information before committing\n"
        return 1
    fi

    return 0
}

# Execute security validation
check_credentials || exit 1

全面的代码质量验证

实现适应技术堆栈的多语言代码质量强制:

#!/usr/bin/env bash
# Enterprise code quality validation framework

validate_code_quality() {
    local staged_files=$(git diff --cached --name-only --diff-filter=ACM)
    local quality_violations=0

    echo "Performing code quality validation..."

    for file in $staged_files; do
        case "$file" in
            *.js|*.jsx|*.ts|*.tsx)
                if command -v npx >/dev/null 2>&1; then
                    echo "Linting JavaScript/TypeScript: $file"
                    npx eslint "$file" || ((quality_violations++))

                    if [[ "$file" =~ \.(ts|tsx)$ ]]; then
                        echo "Type checking: $file"
                        npx tsc --noEmit --skipLibCheck "$file" || ((quality_violations++))
                    fi
                fi
                ;;
            *.py)
                if command -v python3 >/dev/null 2>&1; then
                    echo "Linting Python: $file"
                    python3 -m flake8 "$file" || ((quality_violations++))

                    if command -v mypy >/dev/null 2>&1; then
                        echo "Type checking Python: $file"
                        python3 -m mypy "$file" || ((quality_violations++))
                    fi
                fi
                ;;
            *.cs)
                if command -v dotnet >/dev/null 2>&1; then
                    echo "Formatting C#: $file"
                    dotnet format --verify-no-changes --include "$file" || ((quality_violations++))
                fi
                ;;
            *.go)
                if command -v go >/dev/null 2>&1; then
                    echo "Formatting Go: $file"
                    if ! gofmt -l "$file" | grep -q .; then
                        gofmt -w "$file"
                        git add "$file"
                    fi

                    echo "Linting Go: $file"
                    golint "$file" || ((quality_violations++))
                fi
                ;;
        esac
    done

    if [ $quality_violations -gt 0 ]; then
        echo "Code quality validation failed with $quality_violations violations"
        echo "Please fix the issues above before committing"
        return 1
    fi

    echo "Code quality validation passed"
    return 0
}

# Execute quality validation
validate_code_quality || exit 1

智能测试执行策略

实现仅基于已更改代码运行相关测试的智能测试执行:

#!/usr/bin/env bash
# Intelligent test execution based on change impact

execute_relevant_tests() {
    local changed_files=$(git diff --cached --name-only)
    local test_failures=0

    echo "Analyzing test requirements for changed files..."

    # Check if source code changes require testing
    if echo "$changed_files" | grep -qE "\.(js|jsx|ts|tsx|py|cs|go)$"; then
        echo "Source code changes detected, running relevant tests..."

        # JavaScript/TypeScript projects
        if [ -f "package.json" ] && command -v npm >/dev/null 2>&1; then
            if echo "$changed_files" | grep -qE "\.(js|jsx|ts|tsx)$"; then
                echo "Running JavaScript/TypeScript tests..."
                npm test -- --findRelatedTests $changed_files --passWithNoTests || ((test_failures++))
            fi
        fi

        # Python projects
        if [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
            if echo "$changed_files" | grep -qE "\.py$"; then
                echo "Running Python tests..."
                if command -v pytest >/dev/null 2>&1; then
                    pytest --tb=short || ((test_failures++))
                elif command -v python3 >/dev/null 2>&1; then
                    python3 -m unittest discover || ((test_failures++))
                fi
            fi
        fi

        # .NET projects
        if find . -name "*.csproj" -o -name "*.sln" | grep -q .; then
            if echo "$changed_files" | grep -qE "\.cs$"; then
                echo "Running .NET tests..."
                dotnet test --no-build --verbosity minimal || ((test_failures++))
            fi
        fi

        # Go projects
        if [ -f "go.mod" ]; then
            if echo "$changed_files" | grep -qE "\.go$"; then
                echo "Running Go tests..."
                go test ./... || ((test_failures++))
            fi
        fi
    fi

    if [ $test_failures -gt 0 ]; then
        echo "Test execution failed"
        echo "Please fix failing tests before committing"
        return 1
    fi

    echo "All relevant tests passed"
    return 0
}

# Execute intelligent testing
execute_relevant_tests || exit 1

高级提交消息自动化

Prepare-commit-msg 挂钩实现

自动提交消息生成,以确保一致性并包括必要的元数据:

#!/usr/bin/env bash
# Automated commit message enhancement with Azure DevOps integration

enhance_commit_message() {
    local commit_msg_file="$1"
    local commit_source="$2"
    local sha="$3"

    # Skip automation for merge commits, amend commits, etc.
    if [ -n "$commit_source" ]; then
        return 0
    fi

    # Get current branch information
    local current_branch=$(git branch --show-current)
    local branch_prefix=""

    # Extract work item ID from branch name if present
    if [[ "$current_branch" =~ ^(feature|bugfix|hotfix)/([0-9]+) ]]; then
        local work_item_id="${BASH_REMATCH[2]}"
        branch_prefix="AB#$work_item_id: "
    elif [[ "$current_branch" =~ ^(feature|bugfix|hotfix)/(.+)$ ]]; then
        local feature_name="${BASH_REMATCH[2]}"
        branch_prefix="[$feature_name] "
    fi

    # Read existing commit message
    local existing_message=$(cat "$commit_msg_file")

    # Only add prefix if not already present
    if [ ! -z "$branch_prefix" ] && ! echo "$existing_message" | grep -q "^$branch_prefix"; then
        # Create enhanced commit message
        echo "${branch_prefix}${existing_message}" > "$commit_msg_file"
    fi

    # Add commit template if message is empty
    if [ -z "$existing_message" ] || [ "$existing_message" = "" ]; then
        cat >> "$commit_msg_file" << EOF
${branch_prefix}Brief description of changes

# Detailed explanation of what and why changes were made
#
# Include:
# - What problem this solves
# - Why this approach was chosen
# - Any breaking changes or migration notes
#
# Link to work items: AB#1234
EOF
    fi
}

enhance_commit_message "$@"

提交消息验证挂钩

确保提交消息符合组织标准:

#!/usr/bin/env bash
# Comprehensive commit message validation

validate_commit_message() {
    local commit_msg_file="$1"
    local commit_message=$(cat "$commit_msg_file")

    # Remove comment lines for validation
    local clean_message=$(echo "$commit_message" | grep -v '^#' | sed '/^$/d')

    # Check minimum length
    if [ ${#clean_message} -lt 10 ]; then
        echo "Commit message too short (minimum 10 characters)"
        return 1
    fi

    # Check maximum length for first line
    local first_line=$(echo "$clean_message" | head -n1)
    if [ ${#first_line} -gt 72 ]; then
        echo "Commit message first line too long (maximum 72 characters)"
        echo "Current length: ${#first_line}"
        return 1
    fi

    # Check for work item reference in enterprise environments
    if ! echo "$clean_message" | grep -qE "(AB#[0-9]+|#[0-9]+|closes #[0-9]+|fixes #[0-9]+)"; then
        echo "Commit message should reference a work item (e.g., AB#1234 or #1234)"
        echo "Continue anyway? (y/N)"
        read -r response
        if [[ ! "$response" =~ ^[Yy]$ ]]; then
            return 1
        fi
    fi

    # Check for conventional commit format (optional)
    if echo "$first_line" | grep -qE "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: "; then
        echo "Conventional commit format detected"
    fi

    echo "Commit message validation passed"
    return 0
}

validate_commit_message "$@" || exit 1

Azure DevOps 集成

服务器端钩子集成

将 Azure DevOps 服务挂钩用于服务器端自动化:

#!/usr/bin/env bash
# Azure DevOps webhook integration for advanced workflows

trigger_azure_validation() {
    local branch_name=$(git branch --show-current)
    local commit_sha=$(git rev-parse HEAD)

    # Trigger Azure Pipelines validation build
    if command -v az >/dev/null 2>&1; then
        echo "Triggering Azure DevOps validation pipeline..."

        az pipelines build queue \
            --definition-name "PR-Validation" \
            --branch "$branch_name" \
            --commit-id "$commit_sha" \
            --output table
    fi
}

# Integration with Azure Boards
update_work_item() {
    local commit_message="$1"

    # Extract work item ID from commit message
    if [[ "$commit_message" =~ AB#([0-9]+) ]]; then
        local work_item_id="${BASH_REMATCH[1]}"

        echo "Updating Azure Boards work item #$work_item_id..."

        # Add commit information to work item
        az boards work-item update \
            --id "$work_item_id" \
            --discussion "Commit $(git rev-parse --short HEAD): $(echo "$commit_message" | head -n1)"
    fi
}

性能优化和最佳做法

钩子性能指南

实现性能优化以保持开发人员工作效率:

#!/usr/bin/env bash
# Performance-optimized hook implementation

optimize_hook_performance() {
    # Cache expensive operations
    local cache_dir=".git/hooks-cache"
    mkdir -p "$cache_dir"

    # Only run expensive checks on changed files
    local changed_files=$(git diff --cached --name-only)

    # Implement timeout protection
    timeout 30s expensive_operation || {
        echo "Hook operation timed out, skipping..."
        return 0
    }

    # Provide progress feedback for long operations
    echo "Running validation (this may take a moment)..."
}

# Implement graceful degradation
fallback_validation() {
    echo "Primary validation failed, running minimal checks..."
    # Implement basic validation as fallback
}

此全面的实施指南为复杂的企业 Git 挂钩提供了基础,可增强安全性、质量和合规性,同时保持开发人员的工作效率和工作流效率。