Переводы строк: LF, CRLF и .gitattributes
Обновлено 31 июля 2026 г.
Конец строки в текстовом файле в Linux и macOS записывается одним символом (LF), а в Windows двумя (CR и LF). Git видит эту разницу как изменение текста, и без настройки файл, где поправили одну строку, выглядит переписанным целиком.
$ git diff
diff --git a/notes.txt b/notes.txt
index 0c2aa38..8c902f2 100644
--- a/notes.txt
+++ b/notes.txt
@@ -1,3 +1,3 @@
-line one
-line two
-line three
+line one
+line two CHANGED
+line threeСтроки line one и line three слева и справа выглядят одинаково, и это сбивает с толку. Разница в невидимом символе CR, приклеенном к концу каждой правой строки. git diff в таком виде бесполезен: настоящую правку в нём не найти, а ревью превращается в угадайку. В команде, где часть людей работает в Windows, а часть в Linux, такие diff появляются постоянно.
Настройка на своей машине
Ключ core.autocrlf в git config говорит, что делать при записи в репозиторий и при выдаче файла обратно на диск:
$ git config --global core.autocrlf true # Windows
$ git config --global core.autocrlf input # Linux, macOStrue на Windows значит: в репозиторий уходит LF, а в рабочем каталоге файлы получают привычный местным редакторам CRLF. input на Linux и macOS значит: при коммите CRLF превращается в LF, обратной подстановки нет. В обоих случаях в истории лежит один вариант, LF, и файлы перестают меняться целиком.
.gitattributes: настройка, которая едет с проектом
core.autocrlf живёт на конкретной машине, и поставить его должен каждый участник. Один человек забыл, и в репозиторий снова приезжает файл целиком. Надёжнее положить в корень репозитория файл .gitattributes и закоммитить его вместе с кодом:
$ cat .gitattributes
* text=auto
*.png binary* text=auto значит: всё, что git считает текстом, хранить в истории с LF, а в рабочий каталог отдавать в том виде, который принят в системе. Правило приезжает вместе с клоном и работает у всех одинаково, что бы ни было записано в личных настройках.
Вторая строка нужна не меньше первой. binary отключает любые преобразования для картинок, архивов и шрифтов: байт 0x0d внутри PNG - это данные, и подмена его чем-то другим ломает файл. Git обычно распознаёт двоичные файлы сам, но для форматов своего проекта правило лучше написать явно.
Что получилось в итоге, показывает git ls-files --eol:
$ git ls-files --eol
i/lf w/crlf attr/text=auto notes.txti/ - как файл лежит в индексе и в истории, w/ - как он выглядит в рабочем каталоге.
Частые ошибки
Скрипт для Linux, сохранённый с CRLF, не запускается:
$ ./deploy.sh
bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory^M в сообщении - это тот самый CR, приклеившийся к пути /bin/bash. Такого интерпретатора в системе нет, отсюда и ошибка. Лечится перезаписью файла с LF, а чтобы не повторялось, добавь в .gitattributes строку *.sh text eol=lf.
Вторая ошибка - включить настройку в репозитории, где переводы строк уже перемешаны. Правила действуют на то, что коммитится дальше; старые снимки они не переписывают. Файлы придётся один раз перезаписать самому:
$ git add --renormalize .
$ git commit -m "normalize line endings"Получится один большой коммит, который трогает почти все файлы. Делай его отдельно от содержательных правок и предупреди команду: незакрытые ветки после этого сольются с конфликтами.