Git-Zeilenenden — die CRLF-Hölle zwischen Mac/Linux und Windows beenden
Eine einzige .gitattributes-Datei garantiert überall dieselben Zeilenenden. Die core.autocrlf-Falle und der richtige Weg.
Wird dasselbe Repository zwischen Mac/Linux und Windows geteilt, tritt es fast zwangsläufig auf — CRLF vs. LF. PR-Diffs explodieren in „1000 geänderte Zeilen, obwohl nichts geändert wurde", Shell-Skripte brechen mit \r: command not found, Python wirft SyntaxError: invalid character.
Ich denke, was das CRLF-Problem so hartnäckig macht, ist nicht die technische Komplexität, sondern dass core.autocrlf eine per-Entwickler-Einstellung ist — weil jedes neue Teammitglied ohne Anleitung dieselbe Einstellung anders konfiguriert, statt dass das Repository selbst das Verhalten vorschreibt. Früher habe ich auf core.autocrlf=input vertraut; heute ist .gitattributes mein Standard, da es für alle Mitwirkenden gleichermaßen gilt, unabhängig von ihrer lokalen git-Konfiguration.
Diese Anleitung zeigt den richtigen Weg, um auf jedem OS dieselben Zeilenenden zu garantieren — per .gitattributes. Einmal einrichten; nie wieder daran denken.
TL;DR
.gitattributesmit* text=auto eol=lfim Repo-Stamm ablegencore.autocrlfdeaktivieren —.gitattributesüberschreibt es ohnehin- LF für Windows-Shell-Skripte erzwingen (
*.sh text eol=lf) - CRLF für Windows-Batch-Dateien erzwingen (
*.bat text eol=crlf) - Nach der Vereinheitlichung
git add --renormalize .ausführen, um vorhandene Dateien anzugleichen
Voraussetzungen
- Git 2.10+ (unterstützt
eol=in.gitattributes) - Repo wird gleichzeitig von Mac/Win-Nutzern verwendet
1. Problem — Warum CRLF nicht verschwindet
1.1 Standard-Zeilenenden je OS
| OS | Zeilenende | Geschichte |
|---|---|---|
| Unix · macOS · Linux | LF (\n, 0x0A) | Unix 1970+ |
| Windows | CRLF (\r\n, 0x0D 0x0A) | DOS 1980+ |
| Classic Mac OS 9 | CR (\r) | 1984–2001 |
1.2 Gits automatische Konvertierung — core.autocrlf
| Wert | Beim Auschecken | Beim Commit |
|---|---|---|
true (Windows-Standard) | LF → CRLF | CRLF → LF |
input (Unix empfohlen) | keine | CRLF → LF |
false | keine | keine |
Problem: Jeder Nutzer hat unterschiedliche Einstellungen, neue Rechner variieren, und stille Konvertierungen führen zu „Ich habe es nicht geändert, aber es hat sich geändert"-Vorfällen.
1.3 Der richtige Weg: .gitattributes
Im Repo platziert, erzwingt es für alle dieselben Regeln — und überschreibt core.autocrlf.
2. .gitattributes-Grundlage — 5 min
.gitattributes im Repo-Stamm:
# Standard — alle Textdateien als LF speichern; Text automatisch erkennen
* text=auto eol=lf
# Explizit Text — LF erzwingen
*.c text eol=lf
*.cc text eol=lf
*.cpp text eol=lf
*.h text eol=lf
*.hpp text eol=lf
*.cs text eol=lf
*.go text eol=lf
*.java text eol=lf
*.kt text eol=lf
*.py text eol=lf
*.rb text eol=lf
*.rs text eol=lf
*.swift text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.js text eol=lf
*.jsx text eol=lf
*.mjs text eol=lf
*.cjs text eol=lf
*.json text eol=lf
*.jsonc text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.toml text eol=lf
*.md text eol=lf
*.mdx text eol=lf
*.txt text eol=lf
*.html text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.svg text eol=lf
*.xml text eol=lf
*.sql text eol=lf
# Shell-Skripte — LF (CRLF bricht sie)
*.sh text eol=lf
*.bash text eol=lf
*.zsh text eol=lf
*.fish text eol=lf
Dockerfile* text eol=lf
Makefile* text eol=lf
# Nur Windows — CRLF
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
*.psm1 text eol=crlf
# Binär — keine Konvertierung
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.webp binary
*.avif binary
*.pdf binary
*.zip binary
*.gz binary
*.tar binary
*.7z binary
*.exe binary
*.dll binary
*.so binary
*.dylib binary
*.woff binary
*.woff2 binary
*.ttf binary
*.otf binary
*.mp3 binary
*.mp4 binary
*.mov binary
# Stille Diffs — Text, aber Diff sinnlos
*.lock text eol=lf -diff
pnpm-lock.yaml text eol=lf -diff
package-lock.json text eol=lf -diff
yarn.lock text eol=lf -diff
Cargo.lock text eol=lf -diff⚠️ PowerShell-Dateien (
*.ps1) benötigen CRLF. Windows PowerShell lehnt LF-only ps1 gelegentlich ab.
3. Auf vorhandenes Repo anwenden — 5 min
.gitattributes hinzufügen und committen; anschließend bereits falsche Zeilenenden angleichen.
3.1 renormalize
# Im Repo-Stamm
git add .gitattributes
git commit -m "feat: add .gitattributes baseline"
# Alle Dateien gemäß .gitattributes angleichen
git add --renormalize .
git status # was sich geändert hat anzeigen
git commit -m "chore: renormalize line endings"--renormalize lässt den Arbeitsbaum unberührt; nur der Index wird neu geschrieben. Andere Entwickler gleichen beim nächsten Pull automatisch an.
3.2 Große Repos / Aktive Zusammenarbeit
--renormalize erzeugt einen riesigen PR. Koordinieren:
- Zeitfenster festlegen („Pushes nach X halten")
- Den Renormalize-Commit mergen und alle einmalig
git pullausführen lassen - Oder
git rebase origin/mainauf Feature-Branches, um ihn aufzunehmen
3.3 Kleine Repos / Einzelnutzer
Einfach als einen PR mergen.
4. Globale Nutzereinstellung — core.autocrlf zähmen — 1 min
.gitattributes macht core.autocrlf in diesem Repo wirkungslos. Für Legacy-/externe Repos ohne .gitattributes bleibt es jedoch relevant. Empfehlung:
# macOS / Linux
git config --global core.autocrlf input
# Kein Konvertierung beim Auschecken; CRLF → LF beim Commit
# Windows
git config --global core.autocrlf input
# Auch auf Windows input bevorzugen — Dateien werden als LF committed. CRLFs anderer werden trotzdem normalisiert.
# Oder nur .gitattributes vertrauen
git config --global core.autocrlf falseWarum input auch unter Windows: Die Ausgabe wird nicht von OS-Standards beeinflusst — immer LF.
core.eol
git config --global core.eol lfStandard-Zeilenende beim Auschecken. eol= in .gitattributes hat Vorrang.
5. Editor-Einstellungen — IDE anpassen
VS Code (.vscode/settings.json oder Nutzereinstellungen):
{
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true
}JetBrains: Einstellungen → Editor → Code-Stil → Zeilentrenner → Unix und macOS (\n).
Vim:
" ~/.vimrc
set fileformats=unix,dos
set fileformat=unix6. Überprüfung — Sind es wirklich LF?
6.1 Einzelne Datei
# macOS/Linux
file scripts/build.sh
# ASCII text ← OK
file scripts/build.sh | grep -q CRLF && echo has CRLF
# Oder
od -c scripts/build.sh | head -3
# Zeilen enden nur mit \n. Wenn \r \n zu sehen, ist CRLF vorhanden.6.2 Gesamtes Repo
# Dateien mit CRLF finden
git grep --cached -lI $'\r' -- ':!*.bat' ':!*.cmd' ':!*.ps1'-I schließt Binärdateien aus. Beabsichtigte CRLF-Dateien ausschließen (ps1, bat).
6.3 CI-Gate hinzufügen
GitHub Actions:
- name: Check no CRLF in LF files
run: |
crlf=$(git grep --cached -lI $'\r' -- ':!*.bat' ':!*.cmd' ':!*.ps1' || true)
if [ -n "$crlf" ]; then
echo "CRLF found in LF-expected files:"
echo "$crlf"
exit 1
fi7. Häufige Fallstricke und Lösungen
7.1 .sh schlägt unter Windows fehl mit ^M: command not found
Ein CRLF-Shell-Skript wurde committet. Schnellkorrektur:
dos2unix scripts/build.sh
# Oder
sed -i 's/\r$//' scripts/build.shGrundlegende Behebung: *.sh text eol=lf in .gitattributes + git add --renormalize.
7.2 Python SyntaxError: invalid character
.py-Datei mit CRLF + UTF-8-BOM. LF in .gitattributes erzwingen und BOM im Editor entfernen.
sed -i '1s/^\xEF\xBB\xBF//' file.py7.3 .gitattributes wird nicht tatsächlich angewendet
.gitattributesnicht im Stamm sondern in einem Unterverzeichnis — gilt nur dort- Dateien wurden nicht renormalisiert — vorhandene Zeilenenden bleiben (Renormalize einmalig ausführen)
7.4 IDE speichert als CRLF
.editorconfig hinzufügen:
# .editorconfig (im Repo-Stamm)
root = true
[*]
end_of_line = lf
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.{bat,cmd,ps1}]
end_of_line = crlfVS Code, JetBrains, Vim, Sublime Text usw. lesen .editorconfig automatisch.
7.5 Windows-Editor fügt automatisch BOM hinzu
PowerShell Out-File verwendet standardmäßig UTF-16-BOM. UTF-8 erzwingen:
$content | Out-File "file.txt" -Encoding utf8 -NoNewline
# Oder PowerShell 7+
$content | Out-File "file.txt" -Encoding utf8NoBOM8. PR-Checkliste für ein vorhandenes Repo
-
.gitattributes-Grundlage hinzufügen (§2) -
.editorconfighinzufügen (§7.4) -
git add --renormalize .+ commit - CI CRLF-Check hinzufügen (§6.3)
- Team benachrichtigen — „Nach dem Pull
git config --global core.autocrlf inputsetzen" - Eine README-Zeile ergänzen — „Dieses Repo verwendet LF. Siehe
.gitattributes."
Nächste Schritte
- Multi-OS-Dateisync — auch über Git hinaus
- Mac-Ersteinrichtung — globale Git-Grundlage
- Windows-Ersteinrichtung — WSL2-Git-Einrichtung
Referenzen
Changelog
- 2026-05-12 — Erster Entwurf (devAlice M2-Seed-Erweiterung)