Переводы строк: 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, macOS

true на 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.txt

i/ - как файл лежит в индексе и в истории, 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"

Получится один большой коммит, который трогает почти все файлы. Делай его отдельно от содержательных правок и предупреди команду: незакрытые ветки после этого сольются с конфликтами.

Где это в учебнике

Глава 2. Первый репозиторий