530 lines
14 KiB
Markdown
530 lines
14 KiB
Markdown
---
|
|
name: windows-git-bash-paths
|
|
description: Windows and Git Bash path handling for SSDT, SqlPackage, and DACPAC files with shell detection
|
|
---
|
|
|
|
## 🚨 CRITICAL GUIDELINES
|
|
|
|
### Windows File Path Requirements
|
|
|
|
**MANDATORY: Always Use Backslashes on Windows for File Paths**
|
|
|
|
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
|
|
|
|
**Examples:**
|
|
- ❌ WRONG: `D:/repos/project/file.tsx`
|
|
- ✅ CORRECT: `D:\repos\project\file.tsx`
|
|
|
|
This applies to:
|
|
- Edit tool file_path parameter
|
|
- Write tool file_path parameter
|
|
- All file operations on Windows systems
|
|
|
|
|
|
### Documentation Guidelines
|
|
|
|
**NEVER create new documentation files unless explicitly requested by the user.**
|
|
|
|
- **Priority**: Update existing README.md files rather than creating new documentation
|
|
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
|
|
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
|
|
- **User preference**: Only create additional .md files when user specifically asks for documentation
|
|
|
|
|
|
---
|
|
|
|
# Windows and Git Bash Path Handling for SSDT
|
|
|
|
## Overview
|
|
|
|
SQL Server development is Windows-heavy, and many developers use Git Bash (MINGW/MSYS2) as their preferred shell on Windows. This creates unique path conversion challenges when working with Windows-native tools like SqlPackage, MSBuild, and Visual Studio that expect Windows-style paths.
|
|
|
|
This skill provides comprehensive guidance on handling path conversion issues, shell detection, and best practices for SSDT workflows on Windows with Git Bash.
|
|
|
|
## The Path Conversion Problem
|
|
|
|
### What Happens in Git Bash/MINGW
|
|
|
|
Git Bash automatically converts POSIX-style paths to Windows paths, but this can cause issues with command-line arguments:
|
|
|
|
**Automatic Conversions:**
|
|
- `/foo` → `C:/Program Files/Git/usr/foo`
|
|
- `/foo:/bar` → `C:\msys64\foo;C:\msys64\bar`
|
|
- `--dir=/foo` → `--dir=C:/msys64/foo`
|
|
|
|
**Problematic for SqlPackage:**
|
|
```bash
|
|
# Git Bash converts /Action to a path!
|
|
sqlpackage /Action:Publish /SourceFile:MyDB.dacpac
|
|
# Becomes: sqlpackage C:/Program Files/Git/usr/Action:Publish ...
|
|
```
|
|
|
|
### What Triggers Conversion
|
|
|
|
✓ Leading forward slash (/) in arguments
|
|
✓ Colon-separated path lists
|
|
✓ Arguments after `-` or `,` with path components
|
|
|
|
### What's Exempt
|
|
|
|
✓ Arguments containing `=` (variable assignments)
|
|
✓ Drive specifiers (`C:`)
|
|
✓ Arguments with `;` (already Windows format)
|
|
✓ Arguments starting with `//` (Windows switches)
|
|
|
|
## Solutions for SqlPackage in Git Bash
|
|
|
|
### Method 1: MSYS_NO_PATHCONV (Recommended)
|
|
|
|
Disable path conversion for specific commands:
|
|
|
|
```bash
|
|
# Temporarily disable path conversion
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"MyDatabase.dacpac" \
|
|
/TargetServerName:"localhost" \
|
|
/TargetDatabaseName:"MyDB"
|
|
|
|
# Works for all SqlPackage actions
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Extract \
|
|
/SourceConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;" \
|
|
/TargetFile:"MyDB_backup.dacpac"
|
|
```
|
|
|
|
**Important Notes:**
|
|
- The VALUE doesn't matter - setting to `0`, `false`, or empty still disables conversion
|
|
- Only matters that variable is DEFINED
|
|
- To re-enable: `env -u MSYS_NO_PATHCONV`
|
|
|
|
### Method 2: Double Slash // (Alternative)
|
|
|
|
Use double slashes for SqlPackage parameters:
|
|
|
|
```bash
|
|
# Works in Git Bash and CMD
|
|
sqlpackage //Action:Publish \
|
|
//SourceFile:MyDatabase.dacpac \
|
|
//TargetServerName:localhost \
|
|
//TargetDatabaseName:MyDB
|
|
|
|
# Extract with double slashes
|
|
sqlpackage //Action:Extract \
|
|
//SourceConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;" \
|
|
//TargetFile:output.dacpac
|
|
```
|
|
|
|
**Advantages:**
|
|
- No environment variable needed
|
|
- Works across shells
|
|
- Shell-agnostic scripts
|
|
|
|
### Method 3: Use Windows-Style Paths with Quotes
|
|
|
|
Always quote paths with backslashes:
|
|
|
|
```bash
|
|
# Quoted Windows paths work in Git Bash
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"D:\Projects\MyDB\bin\Release\MyDB.dacpac" \
|
|
/TargetConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;"
|
|
|
|
# Or with forward slashes (Windows accepts both)
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"D:/Projects/MyDB/bin/Release/MyDB.dacpac" \
|
|
/TargetConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;"
|
|
```
|
|
|
|
### Method 4: Switch to PowerShell or CMD
|
|
|
|
For Windows-native tools, consider using native shells:
|
|
|
|
```powershell
|
|
# PowerShell (recommended for Windows SSDT workflows)
|
|
sqlpackage /Action:Publish `
|
|
/SourceFile:"MyDatabase.dacpac" `
|
|
/TargetServerName:"localhost" `
|
|
/TargetDatabaseName:"MyDB"
|
|
```
|
|
|
|
```cmd
|
|
:: CMD
|
|
sqlpackage /Action:Publish ^
|
|
/SourceFile:"MyDatabase.dacpac" ^
|
|
/TargetServerName:"localhost" ^
|
|
/TargetDatabaseName:"MyDB"
|
|
```
|
|
|
|
## Shell Detection for Scripts
|
|
|
|
### Bash Script Detection
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
|
|
# Method 1: Check $OSTYPE
|
|
case "$OSTYPE" in
|
|
msys*) # MSYS/Git Bash/MinGW
|
|
export MSYS_NO_PATHCONV=1
|
|
SQLPACKAGE_ARGS="/Action:Publish /SourceFile:MyDB.dacpac"
|
|
;;
|
|
cygwin*) # Cygwin
|
|
export MSYS_NO_PATHCONV=1
|
|
SQLPACKAGE_ARGS="/Action:Publish /SourceFile:MyDB.dacpac"
|
|
;;
|
|
linux-gnu*) # Linux
|
|
SQLPACKAGE_ARGS="/Action:Publish /SourceFile:MyDB.dacpac"
|
|
;;
|
|
darwin*) # macOS
|
|
SQLPACKAGE_ARGS="/Action:Publish /SourceFile:MyDB.dacpac"
|
|
;;
|
|
esac
|
|
|
|
sqlpackage $SQLPACKAGE_ARGS
|
|
```
|
|
|
|
```bash
|
|
# Method 2: Check uname -s (most portable)
|
|
case "$(uname -s)" in
|
|
MINGW64*|MINGW32*)
|
|
# Git Bash
|
|
export MSYS_NO_PATHCONV=1
|
|
echo "Git Bash detected - path conversion disabled"
|
|
;;
|
|
MSYS_NT*)
|
|
# MSYS
|
|
export MSYS_NO_PATHCONV=1
|
|
echo "MSYS detected - path conversion disabled"
|
|
;;
|
|
CYGWIN*)
|
|
# Cygwin
|
|
export MSYS_NO_PATHCONV=1
|
|
echo "Cygwin detected - path conversion disabled"
|
|
;;
|
|
Linux*)
|
|
# Linux or WSL
|
|
echo "Linux detected"
|
|
;;
|
|
Darwin*)
|
|
# macOS
|
|
echo "macOS detected"
|
|
;;
|
|
esac
|
|
```
|
|
|
|
```bash
|
|
# Method 3: Check $MSYSTEM (Git Bash specific)
|
|
if [ -n "$MSYSTEM" ]; then
|
|
# Running in Git Bash/MSYS2
|
|
export MSYS_NO_PATHCONV=1
|
|
echo "MSYS environment detected: $MSYSTEM"
|
|
case "$MSYSTEM" in
|
|
MINGW64) echo "64-bit native Windows environment" ;;
|
|
MINGW32) echo "32-bit native Windows environment" ;;
|
|
MSYS) echo "POSIX-compliant environment" ;;
|
|
esac
|
|
fi
|
|
```
|
|
|
|
### Complete Build Script Example
|
|
|
|
```bash
|
|
#!/bin/bash
|
|
# build-and-deploy.sh - Cross-platform SSDT build script
|
|
|
|
set -e # Exit on error
|
|
|
|
# Detect shell and set path conversion
|
|
if [ -n "$MSYSTEM" ]; then
|
|
echo "Git Bash/MSYS2 detected - disabling path conversion"
|
|
export MSYS_NO_PATHCONV=1
|
|
fi
|
|
|
|
# Variables
|
|
PROJECT_NAME="MyDatabase"
|
|
BUILD_CONFIG="Release"
|
|
DACPAC_PATH="bin/${BUILD_CONFIG}/${PROJECT_NAME}.dacpac"
|
|
TARGET_SERVER="${SQL_SERVER:-localhost}"
|
|
TARGET_DB="${SQL_DATABASE:-MyDB}"
|
|
|
|
# Build
|
|
echo "Building ${PROJECT_NAME}..."
|
|
dotnet build "${PROJECT_NAME}.sqlproj" -c "$BUILD_CONFIG"
|
|
|
|
# Verify DACPAC exists
|
|
if [ ! -f "$DACPAC_PATH" ]; then
|
|
echo "ERROR: DACPAC not found at $DACPAC_PATH"
|
|
exit 1
|
|
fi
|
|
|
|
echo "DACPAC built successfully: $DACPAC_PATH"
|
|
|
|
# Deploy
|
|
echo "Deploying to ${TARGET_SERVER}/${TARGET_DB}..."
|
|
|
|
# Use double-slash method for maximum compatibility
|
|
sqlpackage //Action:Publish \
|
|
//SourceFile:"$DACPAC_PATH" \
|
|
//TargetServerName:"$TARGET_SERVER" \
|
|
//TargetDatabaseName:"$TARGET_DB" \
|
|
//p:BlockOnPossibleDataLoss=False
|
|
|
|
echo "Deployment complete!"
|
|
```
|
|
|
|
## Common SSDT Path Issues in Git Bash
|
|
|
|
### Issue 1: DACPAC File Paths
|
|
|
|
**Problem:**
|
|
```bash
|
|
# Git Bash mangles the path
|
|
sqlpackage /Action:Publish /SourceFile:./bin/Release/MyDB.dacpac
|
|
# Error: Cannot find file
|
|
```
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Use MSYS_NO_PATHCONV
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"./bin/Release/MyDB.dacpac"
|
|
|
|
# OR use absolute Windows path
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"D:/Projects/MyDB/bin/Release/MyDB.dacpac"
|
|
|
|
# OR use double slashes
|
|
sqlpackage //Action:Publish //SourceFile:./bin/Release/MyDB.dacpac
|
|
```
|
|
|
|
### Issue 2: SQL Project File Paths
|
|
|
|
**Problem:**
|
|
```bash
|
|
# Path with spaces causes issues
|
|
dotnet build "D:/Program Files/MyProject/Database.sqlproj"
|
|
# Works in Git Bash (dotnet handles paths correctly)
|
|
|
|
# But MSBuild paths may fail
|
|
msbuild "D:/Program Files/MyProject/Database.sqlproj"
|
|
# May fail if not quoted properly
|
|
```
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Always quote paths with spaces
|
|
dotnet build "D:/Program Files/MyProject/Database.sqlproj"
|
|
|
|
# Use backslashes for MSBuild on Windows
|
|
msbuild "D:\Program Files\MyProject\Database.sqlproj"
|
|
|
|
# Or use 8.3 short names (no spaces)
|
|
msbuild "D:/PROGRA~1/MyProject/Database.sqlproj"
|
|
```
|
|
|
|
### Issue 3: Publish Profile Paths
|
|
|
|
**Problem:**
|
|
```bash
|
|
# Publish profile not found
|
|
sqlpackage /Action:Publish \
|
|
/SourceFile:MyDB.dacpac \
|
|
/Profile:./Profiles/Production.publish.xml
|
|
```
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Use MSYS_NO_PATHCONV with quoted paths
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"MyDB.dacpac" \
|
|
/Profile:"./Profiles/Production.publish.xml"
|
|
|
|
# Or absolute Windows path
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish \
|
|
/SourceFile:"D:/Projects/MyDB.dacpac" \
|
|
/Profile:"D:/Projects/Profiles/Production.publish.xml"
|
|
```
|
|
|
|
### Issue 4: Connection Strings
|
|
|
|
**Problem:**
|
|
```bash
|
|
# File paths in connection strings
|
|
/SourceConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;AttachDbFilename=D:/Data/MyDB.mdf"
|
|
# Path gets mangled
|
|
```
|
|
|
|
**Solution:**
|
|
```bash
|
|
# Quote entire connection string
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Extract \
|
|
/SourceConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;AttachDbFilename=D:\Data\MyDB.mdf" \
|
|
/TargetFile:"output.dacpac"
|
|
|
|
# Or use double backslashes in connection string
|
|
/SourceConnectionString:"Server=localhost;Database=MyDB;Integrated Security=True;AttachDbFilename=D:\\Data\\MyDB.mdf"
|
|
```
|
|
|
|
## CI/CD Considerations
|
|
|
|
### GitHub Actions with Git Bash
|
|
|
|
```yaml
|
|
name: SSDT Build and Deploy
|
|
|
|
on: [push]
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: windows-latest
|
|
defaults:
|
|
run:
|
|
shell: bash # Use Git Bash
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup .NET
|
|
uses: actions/setup-dotnet@v4
|
|
with:
|
|
dotnet-version: '8.0.x'
|
|
|
|
- name: Install SqlPackage
|
|
run: dotnet tool install -g Microsoft.SqlPackage
|
|
|
|
- name: Build Database Project
|
|
run: dotnet build Database.sqlproj -c Release
|
|
|
|
- name: Deploy with Path Conversion Disabled
|
|
env:
|
|
MSYS_NO_PATHCONV: 1
|
|
run: |
|
|
sqlpackage /Action:Publish \
|
|
/SourceFile:"bin/Release/MyDatabase.dacpac" \
|
|
/TargetServerName:"localhost" \
|
|
/TargetDatabaseName:"MyDB"
|
|
```
|
|
|
|
### PowerShell Alternative (Recommended for Windows)
|
|
|
|
```yaml
|
|
jobs:
|
|
build:
|
|
runs-on: windows-latest
|
|
defaults:
|
|
run:
|
|
shell: pwsh # Use PowerShell - no path issues
|
|
|
|
steps:
|
|
- name: Deploy Database
|
|
run: |
|
|
sqlpackage /Action:Publish `
|
|
/SourceFile:"bin/Release/MyDatabase.dacpac" `
|
|
/TargetServerName:"localhost" `
|
|
/TargetDatabaseName:"MyDB"
|
|
```
|
|
|
|
## Best Practices Summary
|
|
|
|
### For Interactive Development
|
|
|
|
1. **Use PowerShell or CMD for SSDT on Windows** - avoids path conversion issues entirely
|
|
2. **If using Git Bash**, set `MSYS_NO_PATHCONV=1` in your shell profile for SSDT work
|
|
3. **Always quote paths** containing spaces or special characters
|
|
4. **Use absolute paths** when possible to avoid ambiguity
|
|
|
|
### For Scripts
|
|
|
|
1. **Detect shell environment** and set `MSYS_NO_PATHCONV=1` conditionally
|
|
2. **Use double-slash // syntax** for SqlPackage arguments (most portable)
|
|
3. **Prefer PowerShell for Windows-specific workflows** (build scripts, CI/CD)
|
|
4. **Test scripts on all target platforms** (Windows PowerShell, Git Bash, Linux)
|
|
|
|
### For CI/CD
|
|
|
|
1. **Use PowerShell shell in GitHub Actions** for Windows runners (`shell: pwsh`)
|
|
2. **Self-hosted Windows agents** - use native Windows paths and shells
|
|
3. **Set MSYS_NO_PATHCONV=1 as environment variable** if Git Bash required
|
|
4. **Prefer dotnet CLI over MSBuild** for cross-platform compatibility
|
|
|
|
### For Teams
|
|
|
|
1. **Document shell requirements** in repository README
|
|
2. **Provide scripts for all shells** (bash, PowerShell, CMD)
|
|
3. **Standardize on PowerShell** for Windows SSDT workflows when possible
|
|
4. **Use containerized builds** to avoid shell-specific issues
|
|
|
|
## Quick Reference
|
|
|
|
### Environment Variables
|
|
|
|
```bash
|
|
# Disable path conversion (Git Bash/MSYS2/Cygwin)
|
|
export MSYS_NO_PATHCONV=1
|
|
|
|
# Re-enable path conversion
|
|
env -u MSYS_NO_PATHCONV
|
|
```
|
|
|
|
### SqlPackage Command Templates
|
|
|
|
```bash
|
|
# Git Bash - Method 1 (MSYS_NO_PATHCONV)
|
|
MSYS_NO_PATHCONV=1 sqlpackage /Action:Publish /SourceFile:"MyDB.dacpac" /TargetServerName:"localhost" /TargetDatabaseName:"MyDB"
|
|
|
|
# Git Bash - Method 2 (Double Slash)
|
|
sqlpackage //Action:Publish //SourceFile:MyDB.dacpac //TargetServerName:localhost //TargetDatabaseName:MyDB
|
|
|
|
# PowerShell (Recommended for Windows)
|
|
sqlpackage /Action:Publish /SourceFile:"MyDB.dacpac" /TargetServerName:"localhost" /TargetDatabaseName:"MyDB"
|
|
|
|
# CMD
|
|
sqlpackage /Action:Publish /SourceFile:"MyDB.dacpac" /TargetServerName:"localhost" /TargetDatabaseName:"MyDB"
|
|
```
|
|
|
|
### Shell Detection One-Liners
|
|
|
|
```bash
|
|
# Check if Git Bash/MSYS
|
|
[ -n "$MSYSTEM" ] && echo "Git Bash/MSYS2 detected"
|
|
|
|
# Check uname
|
|
[[ "$(uname -s)" =~ ^MINGW ]] && echo "Git Bash detected"
|
|
|
|
# Set path conversion conditionally
|
|
[ -n "$MSYSTEM" ] && export MSYS_NO_PATHCONV=1
|
|
```
|
|
|
|
## Resources
|
|
|
|
- [Git Bash Path Conversion Guide](https://www.pascallandau.com/blog/setting-up-git-bash-mingw-msys2-on-windows/)
|
|
- [MSYS2 Path Conversion Documentation](https://www.msys2.org/docs/filesystem-paths/)
|
|
- [SqlPackage Documentation](https://learn.microsoft.com/sql/tools/sqlpackage/)
|
|
- [Microsoft.Build.Sql SDK](https://www.nuget.org/packages/Microsoft.Build.Sql)
|
|
- [Git for Windows](https://gitforwindows.org/)
|
|
|
|
## Troubleshooting
|
|
|
|
### "Invalid parameter" errors
|
|
|
|
**Symptom:** SqlPackage reports "Invalid parameter" or "Unknown action"
|
|
**Cause:** Git Bash converting `/Action` to a file path
|
|
**Fix:** Use `MSYS_NO_PATHCONV=1` or double-slash `//Action`
|
|
|
|
### "File not found" with valid paths
|
|
|
|
**Symptom:** DACPAC or project file not found despite correct path
|
|
**Cause:** Path conversion mangling the file path
|
|
**Fix:** Quote paths and use `MSYS_NO_PATHCONV=1`
|
|
|
|
### Build succeeds but publish fails
|
|
|
|
**Symptom:** `dotnet build` works but `sqlpackage` fails
|
|
**Cause:** dotnet CLI handles paths correctly, but SqlPackage uses `/` parameters
|
|
**Fix:** Use `MSYS_NO_PATHCONV=1` for SqlPackage commands only
|
|
|
|
### Spaces in paths cause errors
|
|
|
|
**Symptom:** Paths with "Program Files" or other spaces fail
|
|
**Cause:** Unquoted paths split into multiple arguments
|
|
**Fix:** Always quote paths: `/SourceFile:"D:/Program Files/MyDB.dacpac"`
|