mcpField
A
ado-windows-git-bash-compatibility

ado-windows-git-bash-compatibility

github.com/josiahsiegel云与 DevOps59155 次安装19 周前更新
代码仓库

关于 ado-windows-git-bash-compatibility

面向 Azure DevOps 团队的兼容性指南,聚焦 Windows Agent 中 Git Bash 的路径转换与 Shell 差异。内容提供跨平台脚本模式、配置建议和故障诊断方法。

主要功能

  1. 01解释 MINGW 路径转换问题
  2. 02介绍 MSYS 路径转换控制
  3. 03提供跨平台流水线模式
  4. 04说明系统与 Shell 检测方式
  5. 05列出常见错误及诊断方法

适用场景

  1. 01修复 Windows 流水线中的路径错误
  2. 02编写兼容多平台的构建步骤
  3. 03配置 Git Bash 命令参数
  4. 04诊断 Azure DevOps Agent 故障

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill ado-windows-git-bash-compatibility

安装后在 Claude Code 中输入/ado-windows-git-bash-compatibility确认已加载。

详细介绍

Azure Pipelines:Windows 与 Git Bash 兼容性

概述

Azure Pipelines 经常在 Windows Agent 上运行,团队也常使用 Git Bash 编写脚本。这会带来路径转换和 Shell 兼容性问题,可能导致流水线失败。本指南全面介绍了在 Azure DevOps 流水线中集成 Windows 和 Git Bash 的解决方案。

Windows Agent 关键事实

Git Bash 集成

Microsoft 的官方立场:

  • Microsoft 建议在配置 Agent 时避免使用基于 mintty 的 Shell(例如 git-bash)
  • mintty 与原生 Windows 输入/输出 API 并非完全兼容
  • 不过,流水线中的 Git Bash 任务已被广泛使用并受到支持

Git 版本管理:

  • 默认情况下,Windows Agent 使用 Agent 软件随附的 Git
  • Microsoft 建议使用随附的 Git 版本
  • 可通过 System.PreferGitFromPath=true 覆盖

Windows Agent 上的 Git Bash 位置:

C:\Program Files (x86)\Git\usr\bin\bash.exe
C:\Program Files\Git\usr\bin\bash.exe

流水线中的路径转换问题

核心问题

在 Windows Agent 上使用 Bash 任务时,Azure DevOps 变量会返回 Windows 风格的路径,但 Git Bash(MINGW)会自动转换路径,这可能导致问题。

常见故障模式
问题 1:Bash 中的反斜杠转义
# ❌ FAILS - Backslashes treated as escape characters
- bash: |
    cd $(System.DefaultWorkingDirectory)  # d:\a\s\1 becomes d:as1

解决方案:

# ✅ CORRECT - Use forward slashes or variable properly
- bash: |
    cd "$BUILD_SOURCESDIRECTORY"
    # Or use PWD variable which is already set correctly
    echo "Working in: $PWD"
问题 2:参数中的路径变量
# ❌ FAILS - MINGW converts /d /s style arguments
- bash: |
    my-tool /d $(Build.SourcesDirectory)

解决方案:

# ✅ CORRECT - Use double slashes or environment variable
- bash: |
    export MSYS_NO_PATHCONV=1
    my-tool /d $(Build.SourcesDirectory)
    unset MSYS_NO_PATHCONV
问题 3:以冒号分隔的路径列表
# ❌ FAILS - MINGW converts colon-separated Windows paths
- bash: |
    export PATH="/usr/bin:$(Agent.ToolsDirectory)"

解决方案:

# ✅ CORRECT - Use semicolon for Windows or convert properly
- bash: |
    # For Windows-style paths
    export PATH="/usr/bin;$(Agent.ToolsDirectory)"

流水线脚本中的 Shell 检测

方法 1:使用 $OSTYPE(仅限 Bash)
- bash: |
    case "$OSTYPE" in
      linux-gnu*)
        echo "Running on Linux agent"
        BUILD_PATH="$(Build.SourcesDirectory)"
        ;;
      darwin*)
        echo "Running on macOS agent"
        BUILD_PATH="$(Build.SourcesDirectory)"
        ;;
      msys*|mingw*|cygwin*)
        echo "Running on Windows agent with Git Bash"
        # Windows paths already work in MINGW, but may need conversion
        BUILD_PATH="$(Build.SourcesDirectory)"
        export MSYS_NO_PATHCONV=1
        ;;
      *)
        echo "Unknown OS: $OSTYPE"
        BUILD_PATH="$(Build.SourcesDirectory)"
        ;;
    esac

    echo "Build path: $BUILD_PATH"
    cd "$BUILD_PATH"
  displayName: 'Cross-platform path handling'
方法 2:使用 uname(可移植性最佳)
- bash: |
    OS_TYPE=$(uname -s)

    case "$OS_TYPE" in
      Darwin*)
        echo "macOS agent detected"
        ;;
      Linux*)
        echo "Linux agent detected"
        # Check if WSL
        if grep -qi microsoft /proc/version 2>/dev/null; then
          echo "Running in WSL"
        fi
        ;;
      MINGW64*|MINGW32*)
        echo "Git Bash on Windows detected"
        export MSYS_NO_PATHCONV=1
        ;;
      CYGWIN*)
        echo "Cygwin on Windows detected"
        ;;
      MSYS_NT*)
        echo "MSYS on Windows detected"
        export MSYS_NO_PATHCONV=1
        ;;
      *)
        echo "Unknown OS: $OS_TYPE"
        ;;
    esac
  displayName: 'Detect shell environment'
方法 3:使用 Agent.OS(Azure Pipelines 变量)
- bash: |
    if [ "$(Agent.OS)" = "Windows_NT" ]; then
      echo "Windows agent - applying MINGW path handling"
      export MSYS_NO_PATHCONV=1
    elif [ "$(Agent.OS)" = "Linux" ]; then
      echo "Linux agent"
    elif [ "$(Agent.OS)" = "Darwin" ]; then
      echo "macOS agent"
    fi
  displayName: 'Agent-specific configuration'

控制路径转换

MSYS_NO_PATHCONV(主要方法)

禁用 MINGW/Git Bash 中的所有自动路径转换:

- bash: |
    # Disable path conversion for this script
    export MSYS_NO_PATHCONV=1

    # Now Windows paths work as-is
    dotnet build /p:Configuration=Release
    docker run -v "$(Build.SourcesDirectory):/workspace" myimage

    # Optionally re-enable
    unset MSYS_NO_PATHCONV
  displayName: 'Build with path conversion disabled'
MSYS2_ARG_CONV_EXCL(选择性排除)

排除特定参数模式,避免转换:

- bash: |
    # Exclude specific prefixes from conversion
    export MSYS2_ARG_CONV_EXCL="--config=;/p:"

    dotnet build /p:Configuration=Release --config=$(Build.SourcesDirectory)/app.config
  displayName: 'Selective path conversion'
使用 cygpath 手动转换

显式转换 Windows 路径与 Unix 路径:

- bash: |
    # Convert Windows path to Unix
    UNIX_PATH=$(cygpath -u "$(Build.SourcesDirectory)")
    echo "Unix path: $UNIX_PATH"

    # Convert Unix path to Windows
    WINDOWS_PATH=$(cygpath -w "$PWD")
    echo "Windows path: $WINDOWS_PATH"

    # Mixed format (forward slashes with drive letter)
    MIXED_PATH=$(cygpath -m "$(Build.SourcesDirectory)")
    echo "Mixed path: $MIXED_PATH"
  displayName: 'Path conversion examples'

跨平台流水线模式

模式 1:使用条件执行平台特定步骤
jobs:
  - job: CrossPlatformBuild
    strategy:
      matrix:
        Linux:
          imageName: 'ubuntu-24.04'
          osType: 'Linux'
        Windows:
          imageName: 'windows-2025'
          osType: 'Windows_NT'
        macOS:
          imageName: 'macOS-15'
          osType: 'Darwin'
    pool:
      vmImage: $(imageName)

    steps:
      # Windows-specific setup
      - bash: |
          export MSYS_NO_PATHCONV=1
          echo "Windows Git Bash configuration applied"
        condition: eq(variables['Agent.OS'], 'Windows_NT')
        displayName: 'Windows Git Bash setup'

      # Cross-platform build
      - bash: |
          echo "Building on: $(Agent.OS)"
          cd "$(Build.SourcesDirectory)"
          npm install
          npm run build
        displayName: 'Cross-platform build'
模式 2:使用平台检测的可复用模板
# File: templates/cross-platform-script.yml
parameters:
  - name: script
    type: string

steps:
  - bash: |
      # Auto-detect Windows and apply MSYS configuration
      if [ "$(Agent.OS)" = "Windows_NT" ]; then
        export MSYS_NO_PATHCONV=1
      fi

      # Run provided script
      ${{ parameters.script }}
    displayName: 'Cross-platform script execution'

# Usage in main pipeline:
steps:
  - template: templates/cross-platform-script.yml
    parameters:
      script: |
        dotnet build /p:Configuration=Release
        dotnet test --no-build
模式 3:Windows 使用 PowerShell,Unix 使用 Bash
- pwsh: |
    Write-Host "Building on Windows with PowerShell"
    dotnet build /p:Configuration=Release
  condition: eq(variables['Agent.OS'], 'Windows_NT')
  displayName: 'Windows build (PowerShell)'

- bash: |
    echo "Building on Unix with Bash"
    dotnet build -p:Configuration=Release
  condition: ne(variables['Agent.OS'], 'Windows_NT')
  displayName: 'Unix build (Bash)'

Windows Agent 上的 Azure DevOps CLI

常见 CLI 路径问题
# ❌ FAILS - Windows paths in bash arguments
- bash: |
    az pipelines run --id 123 --variables sourceDir=$(Build.SourcesDirectory)

解决方案:

# ✅ CORRECT - Use MSYS_NO_PATHCONV or proper quoting
- bash: |
    export MSYS_NO_PATHCONV=1
    az pipelines run --id 123 --variables sourceDir="$(Build.SourcesDirectory)"
使用路径执行仓库操作
- bash: |
    # Configure Git to handle Windows paths correctly
    git config --global core.autocrlf true
    git config --global core.safecrlf false

    # Clone with proper path handling
    export MSYS_NO_PATHCONV=1
    az repos pr create \
      --repository myrepo \
      --source-branch feature/new \
      --target-branch main
  displayName: 'Git operations on Windows agent'
  condition: eq(variables['Agent.OS'], 'Windows_NT')

Agent 配置最佳实践

为 Windows Agent 配置 Git
- bash: |
    # Recommended Git configuration for Windows agents
    git config --global core.autocrlf true
    git config --global core.longpaths true
    git config --global core.symlinks false

    # Show configuration
    git config --list | grep core
  displayName: 'Configure Git for Windows'
  condition: eq(variables['Agent.OS'], 'Windows_NT')
使用 System.PreferGitFromPath
# Use system Git instead of agent-bundled Git
variables:
  System.PreferGitFromPath: true

steps:
  - bash: |
      git --version
      which git
    displayName: 'Check Git version'
Agent .env 配置

对于可自托管的 Windows Agent,请在 Agent 根目录中创建 .env 文件:

# File: agent/.env
System.PreferGitFromPath=true
MSYS_NO_PATHCONV=1

排查 Windows 流水线故障

诊断脚本
- bash: |
    echo "=== Environment Diagnostics ==="
    echo "Agent.OS: $(Agent.OS)"
    echo "Agent.OSArchitecture: $(Agent.OSArchitecture)"
    echo "System.DefaultWorkingDirectory: $(System.DefaultWorkingDirectory)"
    echo "Build.SourcesDirectory: $(Build.SourcesDirectory)"
    echo ""

    echo "=== Shell Detection ==="
    echo "OSTYPE: $OSTYPE"
    echo "MSYSTEM: $MSYSTEM"
    uname -a
    echo ""

    echo "=== Path Information ==="
    echo "PWD: $PWD"
    echo "HOME: $HOME"
    echo "PATH: $PATH"
    echo ""

    echo "=== Git Configuration ==="
    git --version
    which git
    git config --list | grep core
    echo ""

    echo "=== Path Conversion Test ==="
    echo "Windows-style: $(Build.SourcesDirectory)"
    if command -v cygpath &> /dev/null; then
      echo "Unix-style: $(cygpath -u "$(Build.SourcesDirectory)")"
      echo "Mixed-style: $(cygpath -m "$(Build.SourcesDirectory)")"
    fi
  displayName: 'Windows agent diagnostics'
  condition: eq(variables['Agent.OS'], 'Windows_NT')
常见错误模式及修复方法
错误:“No such file or directory”
# Error: bash: line 1: d:as1: No such file or directory

# ❌ Problem: Backslashes removed
- bash: cd $(System.DefaultWorkingDirectory)

# ✅ Solution: Quote the variable
- bash: cd "$(System.DefaultWorkingDirectory)"
错误:“Invalid switch”
# Error: Invalid switch - "/d"

# ❌ Problem: MINGW converts /d to Windows path
- bash: dotnet test /d:SonarQubeAnalysisPath=.

# ✅ Solution: Disable path conversion
- bash: |
    export MSYS_NO_PATHCONV=1
    dotnet test /d:SonarQubeAnalysisPath=.
路径中包含空格时出现错误:“Access denied”
# Error: Access to path 'C:\Program' is denied

# ❌ Problem: Unquoted path with spaces
- bash: my-tool $(Agent.ToolsDirectory)/mytool

# ✅ Solution: Always quote paths
- bash: my-tool "$(Agent.ToolsDirectory)/mytool"

最佳实践总结

务必做到
  1. 为所有路径变量加引号:"$(Build.SourcesDirectory)"
  2. 对 Windows 专用命令使用 MSYS_NO_PATHCONV
  3. 使用 $(Agent.OS) 或 uname 检测平台
  4. 如果部署目标是 Windows,请在 Windows Agent 上进行测试
  5. 尽可能在路径中使用正斜杠(兼容 Git Bash)
切勿这样做
  1. ❌ 使用未加引号的路径:cd $(Build.SourcesDirectory)
  2. ❌ 假设 Bash 就是 Linux(Windows 上有 Git Bash)
  3. ❌ 硬编码特定平台的路径
  4. ❌ 在同一脚本中混用 PowerShell 和 Bash 语法
  5. ❌ 忽略参数中的 MINGW 路径转换
平台检测模板

在复杂的跨平台脚本开头使用以下内容:

- bash: |
    #!/bin/bash
    set -euo pipefail

    # Detect platform and configure
    if [ "$(Agent.OS)" = "Windows_NT" ]; then
      echo "Windows agent detected"
      export MSYS_NO_PATHCONV=1
      PATH_SEP=";"
    else
      echo "Unix-like agent detected"
      PATH_SEP=":"
    fi

    # Your script logic here
    echo "Build directory: $(Build.SourcesDirectory)"
    cd "$(Build.SourcesDirectory)"

    # Platform-agnostic operations
    npm install
    npm run build
  displayName: 'Cross-platform build script'

更多资源

快速参考卡

场景解决方案
在 Windows 上运行 Bash 脚本使用 export MSYS_NO_PATHCONV=1
检测 Windows Agent检查 $(Agent.OS) = Windows_NT
检测 Git Bash检查 uname -s 是否以 MINGW 开头
将 Windows 路径转换为 Unix 路径cygpath -u "C:\path"
将 Unix 路径转换为 Windows 路径cygpath -w "/c/path"
引用包含空格的路径始终使用 "$(variable)"
禁用参数转换使用 export MSYS2_ARG_CONV_EXCL="pattern"
检查 Git 版本git --version && which git
使用系统 Git设置 System.PreferGitFromPath: true
测试路径处理运行上方的诊断脚本

如有疑问,在运行 Bash 任务的 Windows Agent 上使用 MSYS_NO_PATHCONV=1。

评论

支持 Markdown