Windows закінчує рядки двома символами CRLF (\r\n), macOS і Linux - одним LF (\n). Якщо редактор чи інструмент перетворює закінчення, кожен рядок файлу вважається зміненим: diff на весь файл, конфлікти на рівному місці, blame втрачає авторів.
Ще гірші наслідки для PHP-проєкту:
- shell-скрипти (
entrypoint.sh) зCRLFне запускаються в Linux-контейнері:/bin/sh^M: bad interpreter; CRLFу шаблонах чи тестах з очікуваним текстом ламає порівняння рядків.
Рішення - .gitattributes у репозиторії, а не налаштування кожного розробника:
# .gitattributes
* text=auto eol=lf
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
*.jpg binary
*.pdf binary
text=auto- Git сам визначає текстові файли й зберігає їх у репозиторії зLF;eol=lf- у робочому каталозі тежLFна будь-якій ОС (сучасні редактори на Windows працюють зLFбез проблем);binary- жодних перетворень і текстових diff для бінарних файлів.
Чому не core.autocrlf: це локальне налаштування кожного розробника (true на Windows, input на macOS/Linux). Достатньо одному учаснику налаштувати неправильно - і в репозиторій потрапляють CRLF. .gitattributes комітиться й діє для всіх однаково, маючи пріоритет над core.autocrlf.
Нормалізація існуючого репозиторію після додавання .gitattributes:
git add --renormalize .
git commit -m "Normalize line endings"
Цей коміт змінить багато файлів - його варто додати в .git-blame-ignore-revs, щоб blame не показував його автором кожного рядка.
Додатково:
.editorconfigзend_of_line = lf- щоб редактори одразу створювали файли правильно;- перевірка у CI:
git ls-files --eolпоказує закінчення рядків у індексі й робочому каталозі для кожного файлу; - Pint і Prettier також нормалізують закінчення рядків у файлах, які форматують.
Докладніше в документації: gitattributes: перетворення закінчень рядків