Files
gh-josiahsiegel-claude-code…/skills/docker-git-bash-guide.md
2025-11-30 08:29:02 +08:00

544 lines
13 KiB
Markdown

---
name: docker-git-bash-guide
description: Comprehensive Windows Git Bash and MINGW path conversion guide for Docker volume mounts and commands
---
# Docker on Windows Git Bash / MINGW - Path Conversion Guide
This skill provides comprehensive guidance on handling Docker commands in Git Bash (MINGW) on Windows, with specific focus on volume mount path conversion issues and solutions.
## The Path Conversion Problem
When running Docker commands in Git Bash (MINGW) or MSYS2 on Windows, automatic path conversion can cause serious issues with volume mounts and other Docker commands.
### What Triggers Automatic Conversion
MSYS/MINGW shells automatically convert arguments that look like Unix paths when calling Windows executables (like `docker.exe`):
**Examples of problematic conversions:**
```bash
# What you type:
docker run -v /c/Users/project:/app myimage
# What Docker receives (BROKEN):
docker run -v C:\Program Files\Git\c\Users\project:/app myimage
```
**Triggers for path conversion:**
- Leading forward slash (`/`) in arguments
- Colon-separated path lists (`/foo:/bar`)
- Arguments with path components after `-` or `,`
**What's exempt from conversion:**
- Arguments containing `=` (variable assignments)
- Drive letters (`C:`)
- Arguments with `;` (already Windows format)
- Arguments starting with `//` (network paths/Windows switches)
## Shell Detection for Docker Commands
### Detecting Git Bash / MINGW Environment
Use these environment variables to detect when path conversion issues may occur:
```bash
# Most reliable: Check for MSYSTEM
if [ -n "$MSYSTEM" ]; then
echo "Running in Git Bash/MINGW - path conversion needed"
fi
# Alternative: Check uname
if [[ "$(uname -s)" == MINGW* ]]; then
echo "Running in MINGW environment"
fi
# Environment variable to check:
# MSYSTEM values: MINGW64, MINGW32, MSYS
```
## Solution 1: MSYS_NO_PATHCONV (Recommended for Git Bash)
The most reliable solution for Git Bash on Windows.
### Per-Command Usage
Prefix each Docker command with `MSYS_NO_PATHCONV=1`:
```bash
# Volume mount with $(pwd)
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
# Volume mount with absolute path
MSYS_NO_PATHCONV=1 docker run -v /c/Users/project:/app myimage
# Multiple volume mounts
MSYS_NO_PATHCONV=1 docker run \
-v $(pwd)/data:/data \
-v $(pwd)/config:/etc/config \
myimage
```
### Shell-Level Configuration
Disable path conversion for all Docker commands in your session:
```bash
# Add to ~/.bashrc or run in current shell
export MSYS_NO_PATHCONV=1
# Now all Docker commands work normally
docker run -v $(pwd):/app myimage
```
### Function Wrapper (Automatic per Docker Command)
Create a function wrapper that automatically disables path conversion:
```bash
# Add to ~/.bashrc
docker() {
(export MSYS_NO_PATHCONV=1; command docker.exe "$@")
}
# Or using MSYS2_ARG_CONV_EXCL for MSYS2
docker() {
(export MSYS2_ARG_CONV_EXCL='*'; command docker.exe "$@")
}
# Make function available in subshells
export -f docker
```
## Solution 2: MSYS2_ARG_CONV_EXCL (MSYS2 Specific)
For MSYS2 environments (not standard Git Bash):
```bash
# Disable all argument conversion
export MSYS2_ARG_CONV_EXCL='*'
# Selective exclusion (specific patterns)
export MSYS2_ARG_CONV_EXCL='--dir=;/test'
# Environment variable conversion exclusion
export MSYS2_ENV_CONV_EXCL='*'
```
## Solution 3: Double Leading Slash
Prefix paths with an extra `/` to prevent conversion:
```bash
# Single slash (converted - BROKEN)
docker run -v /c/Users/project:/app myimage
# Double slash (not converted - WORKS)
docker run -v //c/Users/project:/app myimage
# Works in Git Bash on Windows
# Treated as single slash on Linux (portable)
```
**Advantages:**
- No environment variables needed
- Works without wrapper functions
- Portable (extra slash ignored on Linux)
**Disadvantages:**
- Less readable
- Easy to forget
- Doesn't look like standard Docker syntax
## Solution 4: Use $(pwd) with Proper Escaping
Always use lowercase `$(pwd)` (not `$PWD`) with proper syntax:
```bash
# CORRECT: Round brackets, lowercase pwd, no quotes
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
# CORRECT: With subdirectories
MSYS_NO_PATHCONV=1 docker run -v $(pwd)/src:/app/src myimage
# WRONG: Uppercase PWD variable (may not convert correctly)
docker run -v $PWD:/app myimage
# WRONG: Without MSYS_NO_PATHCONV (path gets mangled)
docker run -v $(pwd):/app myimage
```
## Docker Volume Mount Best Practices (Git Bash on Windows)
### For docker run Commands
```bash
# Named volumes (no path conversion issue)
docker run -v my-named-volume:/data myimage
# Bind mount with MSYS_NO_PATHCONV (RECOMMENDED)
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
# Bind mount with double slash (ALTERNATIVE)
docker run -v //c/Users/project:/app myimage
# Read-only bind mount
MSYS_NO_PATHCONV=1 docker run -v $(pwd)/config:/etc/config:ro myimage
# Multiple volumes
MSYS_NO_PATHCONV=1 docker run \
-v $(pwd)/src:/app/src \
-v $(pwd)/data:/app/data \
-v my-named-volume:/var/lib/data \
myimage
```
### For docker-compose.yml Files
Docker Compose files use forward slashes and relative paths - **these work correctly** in Git Bash:
```yaml
# WORKS WITHOUT MODIFICATION in Git Bash
services:
app:
image: myimage
volumes:
# Relative paths (RECOMMENDED)
- ./src:/app/src
- ./data:/app/data
# Named volumes (RECOMMENDED)
- my-data:/var/lib/data
# Windows absolute paths with forward slashes (WORKS)
- C:/Users/project:/app
# Unix-style paths (WORKS if referring to WSL/MINGW paths)
- /c/Users/project:/app
volumes:
my-data:
```
**Important:** When running `docker compose` commands:
```bash
# No special handling needed for compose files
docker compose up -d
# But if you use command-line volume overrides:
MSYS_NO_PATHCONV=1 docker compose run -v $(pwd)/extra:/extra app
```
## Complete Examples
### Example 1: Simple Application Development
```bash
# Set up environment once per session
export MSYS_NO_PATHCONV=1
# Run with live code reload
docker run -d \
--name dev-app \
-v $(pwd)/src:/app/src \
-v $(pwd)/public:/app/public \
-p 3000:3000 \
node:20-alpine \
npm run dev
# View logs
docker logs -f dev-app
```
### Example 2: Database with Data Persistence
```bash
# Use named volume for database data (no path issues)
docker run -d \
--name postgres-db \
-e POSTGRES_PASSWORD=mypassword \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16-alpine
# Mount init scripts with MSYS_NO_PATHCONV
MSYS_NO_PATHCONV=1 docker run -d \
--name postgres-db \
-e POSTGRES_PASSWORD=mypassword \
-v pgdata:/var/lib/postgresql/data \
-v $(pwd)/init.sql:/docker-entrypoint-initdb.d/init.sql:ro \
-p 5432:5432 \
postgres:16-alpine
```
### Example 3: Full Stack with Docker Compose
```bash
# Project structure:
# /c/Users/project/
# ├── docker-compose.yml
# ├── backend/
# ├── frontend/
# └── data/
# docker-compose.yml (no special path handling needed)
cat > docker-compose.yml <<'EOF'
services:
backend:
build: ./backend
volumes:
- ./backend/src:/app/src
- ./data:/app/data
ports:
- "4000:4000"
frontend:
build: ./frontend
volumes:
- ./frontend/src:/app/src
- ./frontend/public:/app/public
ports:
- "3000:3000"
depends_on:
- backend
database:
image: postgres:16-alpine
volumes:
- db-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: changeme
volumes:
db-data:
EOF
# Start everything (works normally)
docker compose up -d
# Override with additional volume (needs MSYS_NO_PATHCONV)
MSYS_NO_PATHCONV=1 docker compose run -v $(pwd)/scripts:/scripts backend bash
```
## Troubleshooting Path Issues
### Problem: "No such file or directory" errors
**Symptoms:**
```
Error response from daemon: invalid mount config for type "bind":
bind source path does not exist: C:\Program Files\Git\c\Users\project
```
**Diagnosis:**
- Path has been incorrectly converted by MINGW
- Notice `C:\Program Files\Git\` prefix added
**Solution:**
```bash
# Add MSYS_NO_PATHCONV before command
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
```
### Problem: Volume appears empty in container
**Symptoms:**
- Container starts successfully
- But mounted directory is empty
- Files exist on host
**Diagnosis:**
- Path conversion mangled the source path
- Docker created empty directory instead
**Solution:**
```bash
# Use MSYS_NO_PATHCONV with $(pwd)
MSYS_NO_PATHCONV=1 docker run -v $(pwd)/data:/data myimage
# Or use double slash
docker run -v //c/Users/project/data:/data myimage
# Or use named volumes for persistent data
docker run -v my-named-volume:/data myimage
```
### Problem: Path with spaces fails
**Symptoms:**
```
Error: invalid reference format
```
**Diagnosis:**
- Spaces in Windows paths not properly quoted
- Path conversion + spaces = disaster
**Solution:**
```bash
# Use MSYS_NO_PATHCONV and quote $(pwd)
MSYS_NO_PATHCONV=1 docker run -v "$(pwd)":/app myimage
# Or avoid spaces in project paths entirely (RECOMMENDED)
# Move project from:
# C:/Users/My Name/My Projects/app
# To:
# C:/Users/MyName/projects/app
```
### Problem: $PWD not working correctly
**Symptoms:**
- Using `$PWD` variable instead of `$(pwd)`
- Inconsistent behavior
**Solution:**
```bash
# WRONG: Using $PWD
docker run -v $PWD:/app myimage
# CORRECT: Using $(pwd)
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
# Explanation:
# $(pwd) is a command that returns current directory
# $PWD is an environment variable that may not be properly formatted
```
## Testing Your Configuration
Create a test script to verify Docker volume mounts work correctly:
```bash
#!/bin/bash
# test-docker-volume.sh
echo "Testing Docker volume mounts in Git Bash..."
# Create test file
mkdir -p test-mount
echo "Hello from host" > test-mount/test.txt
# Test 1: With MSYS_NO_PATHCONV
echo "Test 1: With MSYS_NO_PATHCONV"
MSYS_NO_PATHCONV=1 docker run --rm -v $(pwd)/test-mount:/data alpine cat /data/test.txt
# Test 2: With double slash
echo "Test 2: With double slash"
docker run --rm -v //$(pwd)/test-mount:/data alpine cat /data/test.txt
# Test 3: Without workaround (should fail)
echo "Test 3: Without workaround (may fail)"
docker run --rm -v $(pwd)/test-mount:/data alpine cat /data/test.txt
# Cleanup
rm -rf test-mount
echo "Testing complete!"
```
Run it:
```bash
chmod +x test-docker-volume.sh
./test-docker-volume.sh
```
## Recommended Configuration
Add to your `~/.bashrc`:
```bash
# Docker path conversion fix for Git Bash on Windows
export MSYS_NO_PATHCONV=1
# Or use a wrapper function if you prefer per-command control
docker() {
(export MSYS_NO_PATHCONV=1; command docker.exe "$@")
}
export -f docker
# Alias for docker compose (if needed)
alias docker-compose='MSYS_NO_PATHCONV=1 docker compose'
```
## Platform Detection Script
Use this to automatically detect and configure Docker for Git Bash:
```bash
# Add to ~/.bashrc
# Detect if running in Git Bash/MINGW on Windows
if [ -n "$MSYSTEM" ] || [[ "$(uname -s)" == MINGW* ]]; then
# Running in Git Bash/MINGW
echo "Git Bash detected - enabling Docker path conversion fix"
export MSYS_NO_PATHCONV=1
# Optional: Create wrapper function for explicit control
docker() {
(export MSYS_NO_PATHCONV=1; command docker.exe "$@")
}
export -f docker
fi
```
## Quick Reference
### Environment Variables
| Variable | Purpose | Values |
|----------|---------|--------|
| `MSYS_NO_PATHCONV` | Disable all path conversion (Git Bash) | `1` to disable |
| `MSYS2_ARG_CONV_EXCL` | Exclude specific arguments (MSYS2) | `'*'` or patterns |
| `MSYS2_ENV_CONV_EXCL` | Exclude environment variables (MSYS2) | `'*'` or patterns |
| `MSYSTEM` | MSYS subsystem indicator | `MINGW64`, `MINGW32`, `MSYS` |
### Command Patterns
```bash
# RECOMMENDED: Export once per session
export MSYS_NO_PATHCONV=1
docker run -v $(pwd):/app myimage
# Per-command prefix
MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app myimage
# Double slash workaround
docker run -v //c/Users/project:/app myimage
# Named volumes (no path issues)
docker run -v my-data:/data myimage
# Docker Compose (relative paths work)
docker compose up -d
```
### What Works Without Modification
These Docker commands work normally in Git Bash without special handling:
- Named volumes: `-v my-volume:/data`
- Network commands: `docker network create`
- Image commands: `docker build`, `docker pull`
- Container commands without volumes: `docker run myimage`
- Docker Compose with relative paths in YAML
### What Needs MSYS_NO_PATHCONV
These commands require path conversion fixes:
- Bind mounts with absolute paths: `-v /c/Users/project:/app`
- Bind mounts with $(pwd): `-v $(pwd):/app`
- Volume mounts on docker run command line
- Any command with Unix-style absolute paths
## Summary
**Best Practice for Git Bash on Windows:**
1. **Add to ~/.bashrc:** `export MSYS_NO_PATHCONV=1`
2. **Use relative paths in docker-compose.yml:** `./src:/app/src`
3. **Use named volumes for data:** `my-data:/var/lib/data`
4. **Use $(pwd) with MSYS_NO_PATHCONV** for bind mounts: `MSYS_NO_PATHCONV=1 docker run -v $(pwd):/app`
This configuration ensures Docker commands work correctly in Git Bash on Windows without path conversion issues.