Initial commit
This commit is contained in:
529
skills/windows-git-bash-paths.md
Normal file
529
skills/windows-git-bash-paths.md
Normal file
@@ -0,0 +1,529 @@
|
||||
---
|
||||
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"`
|
||||
Reference in New Issue
Block a user