guide/line-endings.md

Символы конца строки (CRLF и LF) и невидимые различия — когда изменёнными считаются все строки

Причины, по которым визуально одинаковые файлы различаются в diff во всех строках: переводы строк CRLF и LF, перевод строки в конце файла, BOM, табуляции и пробелы, особые пробелы, нормализация Юникода, — и способы их устранить.

Обновлено: 2026-09-23

Бывает, что два файла на вид совпадают до символа, а diff сообщает, что изменились все строки или только первая и последняя. Обычно причина — символы, которых не видно на экране. В этой статье собраны виды таких «невидимых различий» и способы с ними справиться.

Символы перевода строки: CRLF, LF, CR

В разных операционных системах приняты разные способы перевода строки.

ОбозначениеБайтыГде встречается
LF0A (\n)Linux, macOS, большинство инструментов разработки
CRLF0D 0A (\r\n)Многие программы Windows, например Блокнот; интернет-протоколы вроде электронной почты и HTTP
CR0D (\r)Очень старые Mac OS (до версии 9)

Если один файл сохранён с CRLF, а другой с LF, при построчном сравнении в конце каждой строки различием оказывается невидимый \r, и кажется, будто изменилось всё. В GNU diff это различие игнорируется опцией --strip-trailing-cr, в git diff — опцией --ignore-cr-at-eol.

Перевод строки в конце файла

По соглашению POSIX строки текстового файла заканчиваются символом перевода строки. Поэтому многие инструменты ставят перевод строки и после последней строки, но некоторые редакторы этого не делают. В unified diff это различие выглядит так:

@@ -1,2 +1,2 @@ host=example.com-port=8080\ No newline at end of file+port=8080

\ No newline at end of file означает, что в конце строки прямо над пометкой нет перевода строки. В примере содержимое одинаково, а завершающий перевод строки добавлен только в файл после изменения. Многие руководства по стилю кода требуют перевод строки в конце файла, и его можно унифицировать настройкой редактора «вставлять перевод строки в конце файла».

BOM: когда отличается только первая строка

Иногда в начале файла UTF-8 стоят три байта EF BB BF. Это метка порядка байтов (BOM). Для UTF-8 порядок байтов не нужен, но некоторые программы добавляют её как пометку «этот файл в UTF-8». BOM на экране не виден, поэтому если diff сообщает, что отличается только первая строка, подозревайте BOM. Этот сайт удаляет BOM в начале файла при загрузке, а при включённом игнорировании пробелов считает пробелом и BOM (U+FEFF) во вставленном тексте.

Табуляции, пробелы и особые пробелы

Большую часть таких символов отсеивают опции игнорирования пробелов (однако символы, которые не относятся к пробельным, например U+200B, могут остаться и при включённой опции). Если переключить сравнение внутри строки на символы, подсветка покажет, где именно стоит невидимый символ.

Нормализация Юникода: одинаковые символы, разные байты

Букву «é» можно записать одним символом (U+00E9) или сочетанием буквы e (U+0065) и комбинируемого знака ударения (U+0301). Так же и корейский слог «가» бывает одним символом (U+AC00) или сочетанием отдельных букв (U+1100 и U+1161). Юникод называет первую форму NFC, а вторую — NFD (UAX #15). На экране такие тексты выглядят одинаково, но при сравнении это разные символы. Типичный пример — имена файлов, созданных в macOS: в других системах они иногда оказываются в разложенной форме и не совпадают с внешне идентичными именами. Решение — перед сравнением привести обе стороны к NFC.

Как унифицировать переводы строк в git

Если с репозиторием работают в разных операционных системах, переводы строк можно унифицировать настройками git.

* text=auto
*.sh text eol=lf
*.bat text eol=crlf

text=auto нормализует переводы строк в LF внутри репозитория для файлов, которые git считает текстовыми, а eol=lf и eol=crlf задают перевод строки при выгрузке файлов в рабочий каталог.

Попробуйте в этом инструменте

Опция Нормализовать концы строк в сравнении текстов включена по умолчанию: CRLF, CR и LF считаются одним и тем же переводом строки, а наличие перевода строки в конце файла игнорируется. Если выключить её, CR в конце строки будет показан как , а строка без завершающего перевода строки — как , и невидимые различия станут заметны. Опции пробелов описаны в статье Опции игнорирования пробелов, а значения символов в результате — в статье Как читать unified diff.

Перейти к сравнению текстов