Playbook: Fix Missing .gitattributes LF Enforcement
When to use
repo-consistency-audit.mdreports.gitattributes MISSINGorno eol=lf rule- SOPS decrypt fails with
extra text: "\x0d"(CRLF in encrypted file) - Shell scripts on Linux servers fail with
bad interpreter: /bin/bash^M - Windows developer commits a
.shor.env.sopsfile with CRLF line endings
Root cause
Windows git defaults to CRLF line endings. Without .gitattributes:
.shfiles committed on Windows get CRLF → fail on Linux servers (^Min shebang)*.env.sopsfiles committed on Windows get CRLF → SOPS timestamp parse fails.github/workflows/*.ymlcommitted on Windows → GitHub Actions may reject with YAML errors
.gitattributes overrides the core.autocrlf setting per file pattern and normalizes
line endings at commit time, regardless of the developer’s OS.
Standard .gitattributes entries (all repos)
# Normalize line endings on commit
* text=auto
# Force LF for shell scripts — CRLF breaks shebang on Linux
*.sh text eol=lf
# Force LF for YAML (GitHub Actions, Docker Compose)
*.yml text eol=lf
*.yaml text eol=lfAdditional entries for repos with SOPS files
# SOPS encrypted secrets — text/YAML format, enforce LF
secrets/*.env.sops text eol=lfAdd this to: p24-infra, radekkonarski-personal-brand (already have it).
Also add to any other repo that stores .env.sops files.
Fix
Step 1 — Create or update .gitattributes
$repo = "C:\code_2026\<repo>"
$ga = "$repo\.gitattributes"
# Build the block to add
$block = @"
# Normalize line endings on commit
* text=auto
# Force LF for shell scripts — CRLF breaks shebang on Linux
*.sh text eol=lf
# Force LF for YAML (GitHub Actions, Docker Compose)
*.yml text eol=lf
*.yaml text eol=lf
"@
# Append to existing file or create new
$existing = if (Test-Path $ga) { Get-Content $ga -Raw } else { "" }
# Avoid adding duplicate block
if ($existing -notmatch "eol=lf") {
[System.IO.File]::WriteAllText($ga, $existing + $block, [System.Text.UTF8Encoding]::new($false))
Write-Host "Updated .gitattributes"
} else {
Write-Host "eol=lf already present — no change needed"
}Step 2 — Re-normalize already-committed files
After adding .gitattributes, files already in the index retain their old line endings.
Run renormalization:
git -C "C:\code_2026\<repo>" add --renormalize .
git -C "C:\code_2026\<repo>" status
# Review what changed — usually only .sh / .yml filesStep 3 — Commit
git -C "C:\code_2026\<repo>" add .gitattributes
git -C "C:\code_2026\<repo>" add --renormalize .
git -C "C:\code_2026\<repo>" commit -m "chore: add .gitattributes — enforce LF for sh/yml/sops files
Prevents CRLF corruption on Windows commits for shell scripts and YAML files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>"
git -C "C:\code_2026\<repo>" push origin HEADAffected repos (as of 2026-06-28)
| Repo | Has .gitattributes | Has LF rule | Action |
|---|---|---|---|
| p24-infra | ✅ | ✅ | none |
| et-operational-platform | ❌ | ❌ | add standard block |
| Art-Agency | ❌ | ❌ | add standard block |
| brandpilot | ❌ | ❌ | add standard block |
| whatsup-android-chat-puller | ❌ | ❌ | add standard block |
| radekkonarski-personal-brand | ✅ | ✅ | none |
| amazon-kdp-tango | ❌ | ❌ | add standard block |
Escalation
If renormalize creates a very large diff (many files converted): commit the .gitattributes first
in one commit, then do a follow-up --renormalize commit clearly labelled chore: normalize line endings.
This keeps the renormalization separate from code changes for easier git blame navigation.
If a .sh file still fails on Linux after this fix: the file may have been committed before the
.gitattributes was pushed. The collaborator must run git pull to get the attributes, then
git checkout -- <file> to re-checkout with correct endings.