Нет новой строки в конце файла - PullRequest
403 голосов
/ 28 апреля 2011

При выполнении git diff выдается "Нет новой строки в конце файла" .

Хорошо, в конце файла нет новой строки. Что в этом такого?

Каково значение сообщения и что оно пытается нам сказать?

Ответы [ 12 ]

397 голосов
/ 28 апреля 2011

Это означает, что у вас нет новой строки (обычно '\n', иначе CR или CRLF) в конце файла.

То есть, последний байт (или байты, если вы в Windows) в файле не является переводом строки.

Сообщение отображается, потому что в противном случае невозможно определить разницу между файлом, в конце которого находится символ новой строки, и файлом, в котором его нет. В любом случае Diff должен выводить новую строку, иначе результат будет сложнее прочитать или обработать автоматически.

Обратите внимание, что это хороший стиль - всегда ставить символ новой строки как последний символ, если это разрешено форматом файла. Кроме того, например, для заголовочных файлов C и C ++ это требуется стандартом языка.

84 голосов
/ 07 июня 2016

Это не просто плохой стиль, это может привести к неожиданному поведению при использовании других инструментов в файле.

Здесь test.txt:

first line
second line

На новой строке нет символа новой строкипоследняя строкаДавайте посмотрим, сколько строк в файле:

$ wc -l test.txt
1 test.txt

Может быть, это то, что вы хотите, но в большинстве случаев вы, вероятно, ожидаете, что в файле будет 2 строки.

Также, если вы хотите объединить файлы, они могут вести себя не так, как вы ожидаете:

$ cat test.txt test.txt
first line
second linefirst line
second line

Наконец, если вы добавите новую строку, ваши различия будут немного более шумными.Если вы добавили третью строку, она показала бы редактирование второй строки, а также новое добавление.

20 голосов
/ 20 июня 2017

Единственная причина в том, что Unix исторически имел соглашение о всех читаемых человеком текстовых файлах, заканчивающихся символом новой строки.В то время это позволило избежать дополнительной обработки при отображении или объединении текстовых файлов и избежать обработки текстовых файлов по-разному по сравнению с файлами, содержащими другие виды данных (например, необработанные двоичные данные, которые не читаются человеком).

Из-заВ соответствии с этим соглашением многие инструменты той эпохи ожидают окончания новой строки, включая текстовые редакторы, инструменты сравнения и другие инструменты обработки текста.Mac OS X была построена на BSD Unix, а Linux был разработан для совместимости с Unix, поэтому обе операционные системы унаследовали одно и то же соглашение, поведение и инструменты.

Windows не была разработана для совместимости с Unix,поэтому он не имеет такого же соглашения, и большинство программ для Windows будут отлично работать без запаздывающего перевода строки.

Но, поскольку Git был разработан для Linux впервые, и на нем основано много программного обеспечения с открытым исходным кодом.Unix-совместимые системы, такие как Linux, Mac OS X, FreeBSD и т. Д., Большинство сообществ с открытым исходным кодом и их инструменты (включая языки программирования) продолжают следовать этим соглашениям.

Существуют технические причины, которые имели смысл в 1971 году,но в эту эпоху это в основном соглашение и поддержание совместимости с существующими инструментами.

17 голосов
/ 28 апреля 2011

Это просто означает, что в конце файла нет новой строки.Это не катастрофа, это просто сообщение, чтобы прояснить, что его нет, когда вы смотрите на diff в командной строке.

15 голосов
/ 21 марта 2014

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

Это как минимум одна веская причина для добавления новой строки в конце.

Пример

Файл содержит:

A() {
    // do something
}

Hexdump:

00000000: 4128 2920 7b0a 2020 2020 2f2f 2064 6f20  A() {.    // do 
00000010: 736f 6d65 7468 696e 670a 7d              something.}

Теперь вы редактируете его как

A() {
    // do something
}
// Useful comment

Hexdump:

00000000: 4128 2920 7b0a 2020 2020 2f2f 2064 6f20  A() {.    // do 
00000010: 736f 6d65 7468 696e 670a 7d0a 2f2f 2055  something.}.// U
00000020: 7365 6675 6c20 636f 6d6d 656e 742e 0a    seful comment..

Git diff покажет:

-}
\ No newline at end of file
+}
+// Useful comment.

Inдругими словами, это показывает больший различие, чем концептуально произошло.Он показывает, что вы удалили строку } и добавили строку }\n.Фактически это то, что произошло, но это не то, что концептуально произошло , так что это может сбить с толку.

7 голосов
/ 24 марта 2018

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

5 голосов
/ 18 августа 2018

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

Предположим, например, что файл с символом перевода строки рассматривается как одна пустая строка.И наоборот, файл с длиной нулевых байтов фактически является пустым файлом с нулевыми строками.Это может быть подтверждено в соответствии с командой wc -l.

В целом, это поведение является разумным, потому что не было бы никакого другого способа отличить пустой текстовый файл от текстового файла с одной пустой строкой, если *Символ 1006 * был просто разделителем строки, а не разделителем строки.Таким образом, допустимые текстовые файлы всегда должны заканчиваться символом новой строки.Единственное исключение - текстовый файл должен быть пустым (без строк).

4 голосов
/ 01 июня 2013

Основная проблема заключается в том, что вы определяете строку и является ли последовательность символов конца строки онлайновой частью строки или нет.Редакторы на основе UNIX (например, VIM) или инструменты (например, Git) используют последовательность символов EOL в качестве ограничителя строки, поэтому она является частью строки.Это похоже на использование точки с запятой (;) в Си и Паскале.В Си точка с запятой завершает операторы, в Паскале - разделяет их.

3 голосов
/ 29 июля 2017

Исходные файлы часто объединяются инструментами (C, C ++: заголовочные файлы, Javascript: упаковщики). Если вы опустите символ новой строки, вы можете ввести неприятные ошибки (когда последняя строка одного источника объединяется с первой строкой следующего исходного файла). Надеемся, что все инструменты конкатата исходного кода в любом случае вставляют новую строку между конкатенированными файлами, но это не всегда так.

Суть проблемы в том, что в большинстве языков символы новой строки имеют семантическое значение, а конец файла не является языковой альтернативой для символа новой строки. Таким образом, вы должны завершать каждое утверждение / выражение символом новой строки, включая последний.

2 голосов
/ 30 мая 2015

Это на самом деле вызывает проблему, потому что окончания строк автоматически изменяются, загрязняя файлы без внесения в них изменений.См. Этот пост для разрешения.

git с заменой LF на CRLF

...