Finales de línea en Git — acaba con el infierno de CRLF entre Mac/Linux y Windows
Un único .gitattributes garantiza los mismos finales de línea en todas partes. La trampa de core.autocrlf y la manera correcta de evitarla.
Si el mismo repositorio se comparte entre Mac/Linux y Windows, casi con certeza te tropezarás con esto: CRLF vs LF. Las diferencias en un PR explotan con «1000 líneas cambiadas cuando no cambié nada», los scripts de shell fallan con \r: command not found y Python lanza SyntaxError: invalid character.
Creo que los finales de línea son uno de los problemas más frustrantes precisamente porque son invisibles. No es que el código sea incorrecto — en lugar de un error claro, ves un diff gigante o un script que falla por una razón que no parece tener sentido. Por eso .gitattributes es la solución correcta: no depende de que cada desarrollador configure su entorno, porque está en el repositorio.
Esta guía muestra cómo garantizar los mismos finales de línea en todos los sistemas operativos mediante .gitattributes. Configúralo una vez y olvídate del problema.
TL;DR
- Coloca
.gitattributesen la raíz del repositorio con* text=auto eol=lf - Desactiva
core.autocrlf—.gitattributeslo sobreescribe de todos modos - Fuerza LF en los scripts de shell de Windows (
*.sh text eol=lf) - Fuerza CRLF en los archivos batch de Windows (
*.bat text eol=crlf) - Tras unificar, ejecuta
git add --renormalize .para realinear los archivos existentes
Requisitos previos
- Git 2.10+ (compatible con
eol=en.gitattributes) - Repositorio usado simultáneamente por usuarios de Mac y Windows
1. El problema — por qué CRLF no desaparece
1.1 Finales de línea por defecto según el SO
| SO | Final de línea | Historia |
|---|---|---|
| Unix · macOS · Linux | LF (\n, 0x0A) | Unix 1970+ |
| Windows | CRLF (\r\n, 0x0D 0x0A) | DOS 1980+ |
| Mac OS 9 clásico | CR (\r) | 1984–2001 |
1.2 La conversión automática de git — core.autocrlf
| Valor | Al hacer checkout | Al hacer commit |
|---|---|---|
true (por defecto en Windows) | LF → CRLF | CRLF → LF |
input (recomendado en Unix) | ninguno | CRLF → LF |
false | ninguno | ninguno |
El problema: cada usuario tiene ajustes distintos, las máquinas nuevas varían y las conversiones silenciosas provocan los clásicos incidentes de «no cambié nada pero aparecen diferencias».
1.3 La solución correcta es .gitattributes
Colócalo dentro del repositorio para imponer las mismas reglas a todo el equipo. Tiene prioridad sobre core.autocrlf.
2. Línea base de .gitattributes — 5 min
.gitattributes en la raíz del repositorio:
# Por defecto — almacena todos los archivos de texto como LF; detección automática de texto
* text=auto eol=lf
# Texto explícito — fuerza LF
*.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
# Scripts de shell — LF (CRLF los rompe)
*.sh text eol=lf
*.bash text eol=lf
*.zsh text eol=lf
*.fish text eol=lf
Dockerfile* text eol=lf
Makefile* text eol=lf
# Solo para Windows — CRLF
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
*.psm1 text eol=crlf
# Binarios — sin conversión
*.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
# Diffs silenciosos — texto pero inútil comparar
*.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⚠️ Los archivos PowerShell (
*.ps1) requieren CRLF. Windows PowerShell a veces rechaza los archivos.ps1que solo tienen LF.
3. Aplicar a un repositorio existente — 5 min
Añade .gitattributes y haz commit; después realinea los finales de línea ya incorrectos.
3.1 renormalize
# En la raíz del repositorio
git add .gitattributes
git commit -m "feat: add .gitattributes baseline"
# Realinea todos los archivos según .gitattributes
git add --renormalize .
git status # ver qué cambió
git commit -m "chore: renormalize line endings"--renormalize deja el árbol de trabajo intacto; solo reescribe el índice. El resto de colaboradores se alineará automáticamente al hacer pull.
3.2 Repositorios grandes / colaboración activa
--renormalize genera un PR enorme. Coordina el equipo:
- Abre una ventana de tiempo («parar los pushes a partir de X»)
- Mergea el renormalize y pide a todos que hagan
git pulluna vez - O usa
git rebase origin/mainen las ramas de funcionalidades para absorber el cambio
3.3 Repositorios pequeños / trabajo en solitario
Basta con mergearlo en un PR.
4. Configuración global del usuario — Domar core.autocrlf — 1 min
.gitattributes hace irrelevante core.autocrlf en ese repositorio. Para repositorios heredados o externos sin .gitattributes, sí importa. Recomendación:
# macOS / Linux
git config --global core.autocrlf input
# Sin conversión al hacer checkout; CRLF → LF al hacer commit
# Windows
git config --global core.autocrlf input
# Incluso en Windows, prefiere input — tus archivos hacen commit como LF. El CRLF ajeno se normaliza.
# O confía solo en .gitattributes
git config --global core.autocrlf falsePor qué input incluso en Windows: tu salida no depende de los valores por defecto del SO; siempre será LF.
core.eol
git config --global core.eol lfFinal de línea por defecto al hacer checkout. La directiva eol= en .gitattributes tiene prioridad.
5. Ajustes del editor — Alinea tu IDE
VS Code (.vscode/settings.json o ajustes de usuario):
{
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true
}JetBrains: Settings → Editor → Code Style → Line separator → Unix and macOS (\n).
Vim:
" ~/.vimrc
set fileformats=unix,dos
set fileformat=unix6. Verificación — ¿Son realmente LF?
6.1 Un solo archivo
# macOS/Linux
file scripts/build.sh
# ASCII text ← OK
file scripts/build.sh | grep -q CRLF && echo has CRLF
# O también
od -c scripts/build.sh | head -3
# Las líneas terminan solo en \n. Si ves \r \n, hay CRLF.6.2 Todo el repositorio
# Busca archivos con CRLF
git grep --cached -lI $'\r' -- ':!*.bat' ':!*.cmd' ':!*.ps1'-I excluye binarios. Descarta los archivos con CRLF intencional (ps1, bat).
6.3 Añadir una comprobación en CI
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. Problemas habituales y soluciones
7.1 .sh falla en Windows con ^M: command not found
Script de shell con CRLF en el repositorio. Solución rápida (no permanente):
dos2unix scripts/build.sh
# O
sed -i 's/\r$//' scripts/build.shSolución definitiva: *.sh text eol=lf en .gitattributes + git add --renormalize.
7.2 Python SyntaxError: invalid character
Archivo .py con CRLF + BOM UTF-8. Fuerza LF en .gitattributes + elimina el BOM en tu editor.
sed -i '1s/^\xEF\xBB\xBF//' file.py7.3 .gitattributes no se aplica realmente
.gitattributesno está en la raíz sino en un subdirectorio: solo se aplica allí- Los archivos no se renormalizaron: los finales existentes permanecen (hay que ejecutar renormalize una vez)
7.4 El IDE guarda de nuevo como CRLF
Añade .editorconfig:
# .editorconfig (en la raíz del repositorio)
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 y otros leen .editorconfig automáticamente.
7.5 El editor de Windows añade BOM automáticamente
PowerShell Out-File usa UTF-16 BOM por defecto. Fuerza UTF-8:
$content | Out-File "file.txt" -Encoding utf8 -NoNewline
# O PowerShell 7+
$content | Out-File "file.txt" -Encoding utf8NoBOM8. Lista de verificación para arreglar un repositorio existente
- Añadir la línea base de
.gitattributes(§2) - Añadir
.editorconfig(§7.4) -
git add --renormalize .+ commit - Añadir comprobación CRLF en CI (§6.3)
- Notificar al equipo — «Después de hacer pull, confirma
git config --global core.autocrlf input» - Una línea en el README — «Este repositorio unifica LF. Ver
.gitattributes.»
Siguientes pasos
- Sincronización de archivos multi-OS — más allá de Git también
- Configuración inicial de Mac — línea base global de git
- Configuración inicial de Windows — configuración de git en WSL2
Referencias
Historial de cambios
- 2026-05-12 — Borrador inicial (devAlice M2 seed expansion)