Nessuna nuova riga alla fine del file


473

Quando lo si fa git diff, dice "Nessuna nuova riga alla fine del file" .

Ok, non c'è newline alla fine del file. Qual è il grosso problema?

Qual è il significato del messaggio e cosa sta cercando di dirci?


11
Forse, se hai un file che termina senza una nuova riga e aggiungi un'altra riga, git dovrebbe mostrare che la precedente ultima riga è cambiata, poiché include il carattere di nuova riga come parte della riga?
nafg

Risposte:


458

Indica che non si dispone di una nuova riga (in genere '\n', ovvero CR o CRLF) alla fine del file.

Cioè, semplicemente parlando, l'ultimo byte (o byte se sei su Windows) nel file non è una nuova riga.

Il messaggio viene visualizzato perché altrimenti non è possibile distinguere tra un file in cui è presente una riga alla fine e uno in cui non lo è. Diff deve comunque generare una nuova riga, altrimenti il ​​risultato sarebbe più difficile da leggere o elaborare automaticamente.

Si noti che è un buon stile inserire sempre la nuova riga come ultimo carattere se è consentito dal formato del file. Inoltre, ad esempio, per i file di intestazione C e C ++ è richiesto dallo standard linguistico.


136
Per curiosità, puoi spiegare perché è considerato un buon stile mettere sempre una nuova riga come ultimo personaggio? Modifica: trovato questa discussione .
Paul Bellora,

84
@PaulBellora Storicamente, è stata una decisione presa dallo standard del linguaggio C stackoverflow.com/a/729725/233098 Praticamente, perché molti strumenti Unix lo richiedono o se lo aspettano per una corretta visualizzazione stackoverflow.com/a/729795/233098 . Filosoficamente, poiché ogni riga di un file di testo termina con un carattere di "fine riga", l'ultima riga non dovrebbe fare eccezione. Pensandoci diversamente, esploriamo l'inverso. Se fosse presente un marcatore "inizio linea" anziché "fine linea", ometteresti il ​​carattere "inizio linea" sulla prima riga?
Joe,

29
@Joe Non ha molto senso. Una nuova riga è una nuova riga , ovvero il separatore tra le righe, non una fine riga. Non abbiamo caratteri di inizio riga perché non sono necessari. Non abbiamo caratteri di fine riga per lo stesso motivo.
Acjay,

6
@acjay sostengo che tra "Separatore tra linee" e "fine linea" sia intrinsecamente meglio. Nessuna vista è intrinsecamente giusta o sbagliata, solo un modo per guardarla. Sto suggerendo continuiamo ad utilizzare il punto di vista che è storicamente pratico, dal momento che stiamo già facendo in questo modo e non ha senso quando lo si accetta. La coerenza è importante. Non è necessario spezzarlo nel nome del punto di vista "il separatore tra le linee".
Joe,

17
@WORMSS "Nuovo per me" non è la stessa cosa di "una nuova convenzione". È come scoprire qualsiasi altro tipo di convenzione di programmazione. Ci vai e basta. Si potrebbe deviare, ma si sta solo isolarsi. (O in questo caso, in realtà strumenti di rottura.) Pensa a quanti altri hanno scoperto alcune convenzioni di Rails, o PEP8, e quanto coerenti quelle comunità sono rimaste nel loro insieme perché si sono arrese, nonostante abbiano scritto codice al contrario.
Joe,

100

Non è solo un cattivo stile, può portare a comportamenti imprevisti quando si utilizzano altri strumenti nel file.

Ecco qui test.txt:

first line
second line

Non vi è alcun carattere di nuova riga sull'ultima riga. Vediamo quante righe ci sono nel file:

$ wc -l test.txt
1 test.txt

Forse è quello che vuoi, ma nella maggior parte dei casi probabilmente ti aspetteresti che ci siano 2 righe nel file.

Inoltre, se si desidera combinare i file, potrebbe non comportarsi come previsto:

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

Infine, renderebbe i tuoi diff leggermente più rumorosi se dovessi aggiungere una nuova linea. Se hai aggiunto una terza riga, mostrerebbe una modifica alla seconda riga e alla nuova aggiunta.


4
Il risultato di cat è ok ma il parametro wc "-l, --lines" è semplicemente sbagliato. Anche il suo manuale dice "stampa i conteggi di riga" e non "stampa i conteggi di riga".
L'incredibile gennaio

E non riesco nemmeno a riprodurre questo (wc e cat) con il recente util linux (util-linux 2.34).
wget,

1
@wget sono su util-linux 2.34 e può confermare che ciò che questa risposta descrive è il comportamento attuale. Suppongo che il tuo editor abbia aggiunto il carattere "\ n".
Stephanos,

29

L'unica ragione è che Unix storicamente aveva una convenzione di tutti i file di testo leggibili dall'uomo che terminavano con una nuova riga. Al momento, ciò evitava un'ulteriore elaborazione durante la visualizzazione o l'unione di file di testo ed evitava di trattare i file di testo in modo diverso rispetto ai file contenenti altri tipi di dati (ad es. Dati binari grezzi che non sono leggibili dall'uomo).

A causa di questa convenzione, molti strumenti di quell'epoca si aspettano la fine della nuova riga, inclusi editor di testo, strumenti di diffing e altri strumenti di elaborazione del testo. Mac OS X è stato costruito su BSD Unix e Linux è stato sviluppato per essere compatibile con Unix, quindi entrambi i sistemi operativi hanno ereditato la stessa convenzione, comportamento e strumenti.

Windows non è stato sviluppato per essere compatibile con Unix, quindi non ha la stessa convenzione e la maggior parte dei software Windows gestirà bene senza alcuna nuova riga finale.

Ma dal momento che Git è stato sviluppato per Linux per primo, e molti software open source sono basati su sistemi compatibili con Unix come Linux, Mac OS X, FreeBSD, ecc., La maggior parte delle comunità open source e i loro strumenti (compresi i linguaggi di programmazione) continuano seguire queste convenzioni.

Ci sono ragioni tecniche che avevano senso nel 1971, ma in questa era è principalmente convenzione e mantenimento della compatibilità con gli strumenti esistenti.


23

Se aggiungi una nuova riga di testo alla fine del file esistente che non ha già una newline characteralla fine, il diff mostrerà la vecchia ultima riga come modificata, anche se concettualmente non lo era.

Questo è almeno un buon motivo per aggiungere un newline characteralla fine.

Esempio

Un file contiene:

A() {
    // do something
}

hexdump:

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

Ora lo modifichi in

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

Il diff git mostrerà:

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

In altre parole, mostra una differenza maggiore di quanto si sia verificato concettualmente. Mostra che hai eliminato la linea }e aggiunta la linea }\n. Questo è, in effetti, ciò che è accaduto, ma non è ciò che è accaduto concettualmente , quindi può essere fonte di confusione.


2
Possiamo scrivere la stessa cosa nell'altra direzione: se rimuovete una nuova riga alla fine del file esistente che ha già una nuova riga alla fine, il diff mostrerà la vecchia ultima riga anche come modificata, quando concettualmente non lo è. Almeno un buon motivo per rimuovere una nuova riga alla fine.
gentiane,

3
@gentiane Stai confondendo "una nuova riga" (una nuova riga) e "una nuova riga" (1 o 2 caratteri che delimitano la fine di una riga)
minexew

@minexew No, gentiane no. Forse non ti rendi conto che "una nuova linea" è la stessa di "una nuova linea".
L'incredibile gennaio

3
@TheincredibleJan Il modo in cui vengono utilizzati nella risposta, i due termini hanno significati distinti. Non so se stai cercando di essere un coglione o stai solo fraintendendo cosa sta succedendo.
minexew,

18

Indica solo che la fine del file non ha una nuova riga. Non è una catastrofe, è solo un messaggio per chiarire che non ce n'è uno quando si osserva un diff nella riga di comando.


10

Il motivo per cui questa convenzione è entrata in pratica è perché nei sistemi operativi simili a UNIX un carattere di nuova riga viene trattato come terminatore di linea e / o limite di messaggio (questo include il piping tra processi, buffering di linea, ecc.).

Si consideri, ad esempio, che un file con solo un carattere di nuova riga viene trattato come una singola riga vuota. Al contrario, un file con una lunghezza di zero byte è in realtà un file vuoto con zero righe. Questo può essere confermato secondo il wc -lcomando.

Nel complesso, questo comportamento è ragionevole perché non ci sarebbe altro modo per distinguere tra un file di testo vuoto rispetto a un file di testo con una sola riga vuota se il \ncarattere fosse semplicemente un separatore di riga anziché un terminatore di riga. Pertanto, i file di testo validi devono sempre terminare con un carattere di nuova riga. L'unica eccezione è se il file di testo deve essere vuoto (nessuna riga).


1
Perché sono sottovalutato -2? Ho sottolineato non solo la conferma di ciò che hanno affermato altre risposte (ovvero gli strumenti standard basati su UNIX prevedono una nuova riga come terminatore per le righe), ma anche che non esiste alcun modo per distinguere un file vuoto da una singola riga vuota, il che è assolutamente vero . Ho risposto specificamente alla domanda originale "Qual è il significato del messaggio e cosa sta cercando di dirci?"
Leslie Krause,

Non ti ho sottovalutato, ma questa risposta sembra essere specifica per i sistemi di tipo Unix in quanto si applica solo quando una nuova riga è solo il carattere di nuova riga. Non è chiaro che ciò si applichi qui. Inoltre, l'avviso sembra inutile se il file è costituito solo da una riga vuota. Tuttavia, evito StackOverflow perché le persone spesso effettuano il downgrade senza una spiegazione.
user34660

9

C'è una cosa che non vedo nelle risposte precedenti. L'avvertimento di non chiudere la riga potrebbe essere un avvertimento quando una parte di un file è stata troncata. Potrebbe essere un sintomo di dati mancanti.


Buon punto in generale, ma non credo abbia senso nel contesto di questa particolare domanda.
cst1992,

@ cst1992 Le risposte in StackOverflow dovrebbero essere le più utili possibili, il che significa che dovrebbero applicarsi a tutte le possibilità. La domanda è breve e non vedo dove escluda la possibilità che ho suggerito.
user34660

7

Il problema principale è ciò che si definisce linea e se la sequenza di caratteri end-on-line fa parte o meno della linea. Gli editor basati su UNIX (come VIM) o gli strumenti (come Git) usano la sequenza di caratteri EOL come terminatore di riga, quindi fa parte della riga. È simile all'uso del punto e virgola (;) in C e Pascal. In C il punto e virgola termina le istruzioni, in Pascal le separa.


4

Questo in realtà causa un problema perché le terminazioni di riga vengono automaticamente modificate dai file di sporco senza apportare modifiche. Vedi questo post per la risoluzione.

git sostituisce LF con CRLF


3

I file sorgente sono spesso concatenati da strumenti (C, C ++: file header, Javascript: bundlers). Se si omette il carattere di nuova riga, è possibile introdurre cattivi bug (in cui l'ultima riga di una sorgente è concatenata con la prima riga del file sorgente successivo). Si spera che tutti gli strumenti di concatenamento del codice sorgente inseriscano comunque una nuova riga tra i file concatenati, ma ciò non sembra sempre essere il caso.

Il punto cruciale del problema è che nella maggior parte delle lingue le newline hanno un significato semantico e end-of-file non è un'alternativa definita nella lingua per il carattere newline. Quindi dovresti terminare ogni affermazione / espressione con un carattere di nuova riga, incluso l'ultimo.


1
In C / C ++ potresti scrivere l'intero progetto in una riga. Non c'è bisogno di newline.
L'incredibile gennaio

Si potrebbe scrivere l'intero progetto in una sola riga ... se non si utilizza un //commento stile nel mezzo del codice.
Doug Coburn,

2

Il tuo file originale probabilmente non aveva un carattere di nuova riga.

Tuttavia, alcuni editor come gedit in linux aggiungono silenziosamente newline alla fine del file. Non è possibile eliminare questo messaggio mentre si utilizza questo tipo di editor.

Quello che ho provato a superare questo problema è aprire il file con l'editor di codice di Visual Studio

Questo editor mostra chiaramente l'ultima riga e puoi eliminare la riga come desideri.


0

Per quello che vale, l'ho riscontrato quando ho creato un progetto IntelliJ su un Mac, quindi ho spostato il progetto sul mio computer Windows. Ho dovuto aprire manualmente ogni file e modificare l'impostazione di codifica in basso a destra nella finestra di IntelliJ. Probabilmente non succederà alla maggior parte se qualcuno leggesse questa domanda, ma ciò avrebbe potuto salvarmi un paio d'ore di lavoro ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.