No hay nueva línea al final del archivo

473

Al hacer un git diff , dice "No hay nueva línea al final del archivo" .

Ok, no hay nueva línea al final del archivo. ¿Cual es el problema?

¿Cuál es el significado del mensaje y qué intenta decirnos?

Pacerier
fuente
11
Quizás, si tiene un archivo que termina sin una nueva línea, y agrega otra línea, git tendría que mostrar que la última última línea ha cambiado, ya que incluye el carácter de nueva línea como parte de la línea.
nafg

Respuestas:

458

Indica que no tiene una nueva línea (generalmente '\n', también conocida como CR o CRLF) al final del archivo.

Es decir, simplemente hablando, el último byte (o bytes si está en Windows) en el archivo no es una nueva línea.

El mensaje se muestra porque, de lo contrario, no hay forma de distinguir entre un archivo donde hay una nueva línea al final y uno donde no. Diff tiene que generar una nueva línea de todos modos, o el resultado sería más difícil de leer o procesar automáticamente.

Tenga en cuenta que es un buen estilo colocar siempre la nueva línea como último carácter si el formato de archivo lo permite. Además, por ejemplo, para los archivos de encabezado C y C ++ es requerido por el estándar de lenguaje.

Alexander Gladysh
fuente
136
Por curiosidad, ¿puedes explicar por qué se considera un buen estilo poner siempre una nueva línea como el último personaje? Editar: encontró esta discusión .
Paul Bellora
84
@PaulBellora Históricamente, fue una decisión tomada por el estándar de lenguaje C stackoverflow.com/a/729725/233098 Prácticamente, porque muchas herramientas de Unix lo requieren o esperan para una visualización adecuada stackoverflow.com/a/729795/233098 . Filosóficamente, debido a que cada línea en un archivo de texto termina con un carácter de "fin de línea", la última línea no debería ser una excepción. Pensando en ello de manera diferente, exploremos lo inverso. Si hubiera un marcador de "inicio de línea" en lugar de "fin de línea", ¿omitiría el carácter de "inicio de línea" en la primera línea?
Joe
29
@ Joe Eso no tiene mucho sentido. Una nueva línea es una nueva línea , es decir, el separador entre líneas, no un final de línea. No tenemos caracteres de inicio de línea porque no son necesarios. No tenemos caracteres de final de línea por la misma razón.
acjay
66
@acjay Argumento que hay inherentemente mejor entre "Separador entre líneas" frente a "fin de línea". Ninguna vista es inherentemente correcta o incorrecta, solo una forma de verla. Sugiero que sigamos usando el punto de vista que es históricamente práctico, ya que ya lo estamos haciendo de esa manera y tiene sentido cuando lo aceptas. La consistencia es importante. No hay necesidad de romper eso en el nombre del punto de vista "el separador entre líneas".
Joe
17
@WORMSS "Nuevo para mí" no es lo mismo que "una nueva convención". Esto es como descubrir cualquier otro tipo de convención de programación. Solo ve con eso. Usted podría desviarse, pero que sólo está aislando a sí mismo. (O, en este caso, realmente romper herramientas). Piense en cuántos otros descubrieron alguna convención de Rails, o PEP8, y cuán consistentes se mantuvieron esas comunidades en su conjunto porque se rindieron, a pesar de tener un código escrito en contrario.
Joe
100

No es solo un mal estilo, puede conducir a un comportamiento inesperado al usar otras herramientas en el archivo.

Aqui esta test.txt:

first line
second line

No hay caracteres de nueva línea en la última línea. Veamos cuántas líneas hay en el archivo:

$ wc -l test.txt
1 test.txt

Tal vez eso es lo que quieres, pero en la mayoría de los casos probablemente esperarías que haya 2 líneas en el archivo.

Además, si desea combinar archivos, es posible que no se comporte de la manera esperada:

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

Finalmente, haría que sus diferencias fueran un poco más ruidosas si tuviera que agregar una nueva línea. Si agrega una tercera línea, mostrará una edición en la segunda línea, así como la nueva adición.

Decano
fuente
44
El resultado de cat está bien, pero el parámetro wc "-l, --lines" es simplemente incorrecto. Incluso su manual dice "imprimir los recuentos de línea nueva" y no "imprimir los recuentos de línea".
El increíble Jan
Y ni siquiera puedo reproducir esto (wc y cat) con el reciente util linux (util-linux 2.34).
wget
1
@wget Estoy en util-linux 2.34 y puedo confirmar que lo que esta respuesta describe es el comportamiento actual. Supongo que su editor agregó el carácter "\ n".
stephanos
29

La única razón es que Unix históricamente tenía una convención de todos los archivos de texto legibles por humanos que terminaban en una nueva línea. En ese momento, esto evitó el procesamiento adicional al mostrar o unir archivos de texto, y evitó tratar los archivos de texto de manera diferente a los archivos que contienen otros tipos de datos (por ejemplo, datos binarios sin procesar que no son legibles para los humanos).

Debido a esta convención, muchas herramientas de esa época esperan el final de la nueva línea, incluidos los editores de texto, las diferentes herramientas y otras herramientas de procesamiento de texto. Mac OS X se creó en BSD Unix y Linux se desarrolló para ser compatible con Unix, por lo que ambos sistemas operativos han heredado la misma convención, comportamiento y herramientas.

Windows no fue desarrollado para ser compatible con Unix, por lo que no tiene la misma convención, y la mayoría del software de Windows funcionará bien sin una nueva línea final.

Pero, dado que Git se desarrolló primero para Linux, y una gran cantidad de software de código abierto se basa en sistemas compatibles con Unix como Linux, Mac OS X, FreeBSD, etc., la mayoría de las comunidades de código abierto y sus herramientas (incluidos los lenguajes de programación) continúan seguir estas convenciones.

Hay razones técnicas que tuvieron sentido en 1971, pero en esta era es principalmente convencional y mantener la compatibilidad con las herramientas existentes.

Nathan Craike
fuente
23

Si agrega una nueva línea de texto al final del archivo existente que aún no tiene unnewline character al final, el diff mostrará la última línea anterior como modificada, aunque conceptualmente no lo fue.

Esta es al menos una buena razón para agregar un newline character al final.

Ejemplo

Un archivo contiene:

A() {
    // do something
}

Hexdump:

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

Ahora lo editas en

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..

El git diff mostrará:

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

En otras palabras, muestra una diferencia mayor que la ocurrida conceptualmente. Muestra que eliminó la línea }y agregó la línea }\n. Esto es, de hecho, lo que sucedió, pero no es lo que sucedió conceptualmente , por lo que puede ser confuso.

Jaseem
fuente
2
Podemos escribir lo mismo en la otra dirección: si elimina una nueva línea al final del archivo existente que ya tiene una nueva línea al final, el diff mostrará la última línea anterior también como modificada, cuando conceptualmente no lo es. Al menos una buena razón para eliminar una nueva línea al final.
gentiane
3
@gentiane Estás confundiendo "una nueva línea" (una nueva línea) y "una nueva línea" (1 o 2 caracteres que delimitan el final de una línea)
minexew
@minexew No, gentiane no lo es. Quizás simplemente no se dé cuenta de que "una nueva línea" es lo mismo que "una nueva línea".
El increíble Jan
3
@TheincredibleJan La forma en que se usan en la respuesta, los dos términos tienen significados distintos. No sé si estás tratando de ser un asno inteligente o simplemente estás malinterpretando lo que está sucediendo.
minexew
18

Simplemente indica que el final del archivo no tiene una nueva línea. No es una catástrofe, es solo un mensaje para aclarar que no hay una cuando se mira un diferencial en la línea de comando.

JohnD
fuente
10

La razón por la que esta convención entró en práctica es porque en los sistemas operativos tipo UNIX, un carácter de nueva línea se trata como un terminador de línea y / o límite de mensaje (esto incluye la conexión entre procesos, almacenamiento en línea, etc.).

Considere, por ejemplo, que un archivo con solo un carácter de nueva línea se trata como una sola línea vacía. Por el contrario, un archivo con una longitud de cero bytes es en realidad un archivo vacío con cero líneas. Esto se puede confirmar de acuerdo con el wc -lcomando.

En conjunto, este comportamiento es razonable porque no habría otra forma de distinguir entre un archivo de texto vacío versus un archivo de texto con una sola línea vacía si el \ncarácter fuera simplemente un separador de línea en lugar de un terminador de línea. Por lo tanto, los archivos de texto válidos siempre deben terminar con un carácter de nueva línea. La única excepción es si el archivo de texto está vacío (sin líneas).

Leslie Krause
fuente
1
¿Por qué me rechazan -2? Señalé no solo la confirmación de lo que han dicho otras respuestas (es decir, las herramientas estándar basadas en UNIX esperan una nueva línea como terminador de líneas), sino también que no hay forma de distinguir un archivo vacío de una sola línea vacía, lo cual es absolutamente cierto. . Respondí específicamente la pregunta original "¿Cuál es el significado del mensaje y qué intenta decirnos?"
Leslie Krause
No te voté negativamente, pero esta respuesta parece ser específica para los sistemas de tipo Unix, ya que solo se aplica cuando una nueva línea es solo el carácter de nueva línea. No está claro que eso se aplique aquí. Además, la advertencia parece inútil si el archivo consiste solo en una línea vacía. Sin embargo, evito Stackoverflow porque las personas a menudo votan negativamente sin una explicación.
user34660
9

Hay una cosa que no veo en las respuestas anteriores. La advertencia de no final de línea podría ser una advertencia cuando una parte de un archivo se ha truncado. Podría ser un síntoma de datos faltantes.

usuario34660
fuente
Buen punto en general, pero no creo que tenga sentido en el contexto de esta pregunta en particular.
cst1992
@ cst1992 Se supone que las respuestas en Stackoverflow son lo más útiles posible, lo que significa que se deben aplicar a todas las posibilidades. La pregunta es corta y no veo dónde excluye la posibilidad que sugerí.
user34660
7

El problema central es qué define la línea y si la secuencia de caracteres de final de línea es parte de la línea o no. Los editores basados ​​en UNIX (como VIM) o las herramientas (como Git) usan la secuencia de caracteres EOL como terminador de línea, por lo tanto, es parte de la línea. Es similar al uso de punto y coma (;) en C y Pascal. En C el punto y coma termina las declaraciones, en Pascal las separa.

mmcorrelo
fuente
4

En realidad, esto causa un problema porque los finales de línea se modifican automáticamente archivos sucios sin hacer ningún cambio en ellos. Ver esta publicación para su resolución.

git reemplazando LF con CRLF

Brian Blum
fuente
3

Los archivos de origen a menudo están concatenados por herramientas (C, C ++: archivos de encabezado, Javascript: paquetes). Si omite el carácter de nueva línea, podría introducir errores desagradables (donde la última línea de una fuente se concatena con la primera línea del siguiente archivo fuente). Afortunadamente, todas las herramientas de concat del código fuente por ahí insertan una nueva línea entre archivos concatenados de todos modos, pero ese no siempre parece ser el caso.

El quid de la cuestión es: en la mayoría de los idiomas, las nuevas líneas tienen un significado semántico y el final del archivo no es una alternativa definida por el idioma para el carácter de nueva línea. Por lo tanto, debe terminar cada declaración / expresión con un carácter de nueva línea, incluida la última.

Doug Coburn
fuente
1
En C / C ++ puedes escribir todo tu proyecto en una línea. No hay necesidad de nueva línea.
El increíble Jan
Usted podría escribir todo su proyecto en una sola línea ... si no utiliza un //estilo de comentarios en el medio del código.
Doug Coburn
2

Su archivo original probablemente no tenía carácter de nueva línea.

Sin embargo, algunos editores como gedit en linux agregan en silencio nueva línea al final del archivo. No puede deshacerse de este mensaje mientras usa este tipo de editores.

Lo que intenté superar este problema es abrir el archivo con el editor de código visual studio

Este editor muestra claramente la última línea y puede eliminar la línea como lo desee.

Berkay92
fuente
0

Por lo que vale, me encontré con esto cuando creé un proyecto IntelliJ en una Mac, y luego moví el proyecto a mi máquina Windows. Tuve que abrir manualmente cada archivo y cambiar la configuración de codificación en la parte inferior derecha de la ventana IntelliJ. Probablemente no le pase a la mayoría de los que leyeron esta pregunta, pero eso podría haberme ahorrado un par de horas de trabajo ...

Lou Morda
fuente