Nenhuma nova linha no final do arquivo

472

Ao fazer um git diff, diz "Sem nova linha no final do arquivo" .

Ok, não há nova linha no final do arquivo. Qual é o grande problema?

Qual é o significado da mensagem e o que ela está tentando nos dizer?

Pacerier
fonte
11
Talvez, se você tem um arquivo que termina sem uma nova linha e adiciona outra linha, o git precisaria mostrar que a última última linha mudou, pois inclui o caractere da nova linha como parte da linha?
nafg

Respostas:

458

Indica que você não possui uma nova linha (geralmente '\n', também conhecida como CR ou CRLF) no final do arquivo.

Ou seja, simplesmente, o último byte (ou bytes, se você estiver no Windows) no arquivo não é uma nova linha.

A mensagem é exibida porque, caso contrário, não há como diferenciar um arquivo em que existe uma nova linha no final e uma em que não existe. Diff precisa gerar uma nova linha de qualquer maneira, ou o resultado seria mais difícil de ler ou processar automaticamente.

Observe que é um bom estilo sempre colocar a nova linha como último caractere, se for permitido pelo formato do arquivo. Além disso, por exemplo, para arquivos de cabeçalho C e C ++, é exigido pelo padrão da linguagem.

Alexander Gladysh
fonte
136
Por curiosidade, você pode explicar por que é considerado bom estilo sempre colocar uma nova linha como o último personagem? Edit: encontrou esta discussão .
Paul Bellora
84
@PaulBellora Historicamente, foi uma decisão tomada pelo padrão da linguagem C stackoverflow.com/a/729725/233098 Praticamente, porque muitas ferramentas Unix exigem ou esperam uma exibição adequada stackoverflow.com/a/729795/233098 . Filosoficamente, porque cada linha em um arquivo de texto termina com um caractere "final de linha" - a última linha não deve ser exceção. Pensando de maneira diferente, vamos explorar o inverso. Se houvesse um marcador "início de linha" em vez de "fim de linha", você omitiria o caractere "início de linha" na primeira linha?
Joe
29
@ Joe Isso não faz muito sentido. Uma nova linha é uma nova linha , ou seja, o separador entre linhas, não um final de linha. Não temos caracteres de início de linha porque eles não são necessários. Não temos caracteres de fim de linha pelo mesmo motivo.
acjay
6
@ acjay Eu argumento que há inerentemente melhor entre "Separador entre linhas" vs "final de linha". Nenhuma das vistas é inerentemente certa ou errada, apenas uma maneira de olhar para ela. Estou sugerindo que continuemos a usar o ponto de vista historicamente prático, já que já estamos fazendo dessa maneira e faz sentido quando você o aceita. A consistência é importante. Não é necessário quebrar isso no nome do ponto de vista "o separador entre linhas".
Joe
17
@WORMSS "Novo para mim" não é a mesma coisa que "uma nova convenção". É como descobrir qualquer outro tipo de convenção de programação. Você apenas vai com isso. Você pode se desviar, mas está apenas se isolando. (Ou, neste caso, realmente quebrando ferramentas.) Pense em quantas outras pessoas descobriram alguma convenção do Rails, ou PEP8, e quão consistentes essas comunidades permaneceram como um todo porque cederam - apesar de terem escrito código ao contrário.
Joe
100

Não é apenas um estilo ruim, pode levar a um comportamento inesperado ao usar outras ferramentas no arquivo.

Aqui está test.txt:

first line
second line

Não há caracteres de nova linha na última linha. Vamos ver quantas linhas estão no arquivo:

$ wc -l test.txt
1 test.txt

Talvez seja isso que você deseja, mas na maioria dos casos você provavelmente esperaria haver duas linhas no arquivo.

Além disso, se você quiser combinar arquivos, pode não se comportar da maneira que você esperaria:

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

Finalmente, isso tornaria suas diferenças um pouco mais barulhentas se você adicionasse uma nova linha. Se você adicionou uma terceira linha, ela mostrará uma edição na segunda linha e também na nova adição.

reitor
fonte
4
O resultado de cat está ok, mas o parâmetro wc "-l, --lines" está errado. Até o manual diz "imprima a contagem da nova linha" e não "imprima a contagem da linha".
O incrível Jan
E eu não consigo nem reproduzir isso (wc e cat) com o recente util linux (util-linux 2.34).
Wget #
1
@ wget Estou no util-linux 2.34 e pode confirmar que o que esta resposta descreve é ​​o comportamento atual. Meu palpite é que seu editor adicionou o caractere "\ n".
stephanos
29

A única razão é que o Unix historicamente tinha uma convenção de todos os arquivos de texto legíveis por humanos, terminando em uma nova linha. Na época, isso evitava processamento extra ao exibir ou ingressar em arquivos de texto e tratava os arquivos de texto de maneira diferente dos arquivos que continham outros tipos de dados (por exemplo, dados binários brutos que não são legíveis por humanos).

Por causa dessa convenção, muitas ferramentas daquela época esperam a nova linha final, incluindo editores de texto, ferramentas de difusão e outras ferramentas de processamento de texto. O Mac OS X foi desenvolvido no BSD Unix e o Linux foi desenvolvido para ser compatível com o Unix; portanto, ambos os sistemas operacionais herdaram a mesma convenção, comportamento e ferramentas.

O Windows não foi desenvolvido para ser compatível com Unix, portanto, não possui a mesma convenção, e a maioria dos softwares do Windows lida perfeitamente sem nenhuma nova linha.

Mas, desde que o Git foi desenvolvido primeiro para Linux, e muitos softwares de código aberto são criados em sistemas compatíveis com Unix, como Linux, Mac OS X, FreeBSD, etc., a maioria das comunidades de código aberto e suas ferramentas (incluindo linguagens de programação) continuam seguir essas convenções.

Existem razões técnicas que faziam sentido em 1971, mas nesta época é principalmente convenção e manutenção da compatibilidade com as ferramentas existentes.

Nathan Craike
fonte
23

Se você adicionar uma nova linha de texto no final do arquivo existente que ainda não possui um newline characterno final, o diff mostrará a última linha antiga como tendo sido modificada, mesmo que conceitualmente não fosse.

Esse é pelo menos um bom motivo para adicionar um newline characterno final.

Exemplo

Um arquivo contém:

A() {
    // do something
}

Hexdump:

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

Agora você o edita para

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

O diff do git mostrará:

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

Em outras palavras, mostra uma diferença maior do que conceitualmente ocorreu. Isso mostra que você excluiu a linha }e a adicionou }\n. Isso foi, de fato, o que aconteceu, mas não foi o que aconteceu conceitualmente , portanto pode ser confuso.

Jaseem
fonte
2
Podemos escrever a mesma coisa na outra direção: Se você remover uma nova linha no final do arquivo existente que já possui uma nova linha no final, o diff mostrará a última linha antiga também como modificada, quando conceitualmente não for. Pelo menos um bom motivo para remover uma nova linha no final.
gentiane 8/09/16
3
@gentiane Você está confundindo "uma nova linha" (uma nova linha) e "uma nova linha" (1 ou 2 caracteres que delimitam o final de uma linha)
minexew 6/17/17
@minexew Não, gentiane não é. Talvez você simplesmente não perceba que "uma nova linha" é o mesmo que "uma nova linha".
O incrível Jan
3
@TheincredibleJan Da maneira como são usados ​​na resposta, os dois termos têm significados distintos. Não sei se você está tentando ser espertinho ou está apenas entendendo mal o que está acontecendo.
minexew
18

Apenas indica que o final do arquivo não possui uma nova linha. Não é uma catástrofe, é apenas uma mensagem para deixar mais claro que não há uma quando se olha para uma diferença na linha de comando.

JohnD
fonte
10

A razão pela qual essa convenção entrou em prática é porque, em sistemas operacionais do tipo UNIX, um caractere de nova linha é tratado como um terminador de linha e / ou limite de mensagem (isso inclui canalização entre processos, buffer de linha, etc.).

Considere, por exemplo, que um arquivo com apenas um caractere de nova linha seja tratado como uma única linha vazia. Por outro lado, um arquivo com comprimento de zero bytes é na verdade um arquivo vazio com zero linhas. Isso pode ser confirmado de acordo com o wc -lcomando.

No total, esse comportamento é razoável, porque não haveria outra maneira de distinguir entre um arquivo de texto vazio e um arquivo de texto com uma única linha vazia se o \ncaractere fosse apenas um separador de linhas em vez de um terminador de linha. Portanto, os arquivos de texto válidos sempre devem terminar com um caractere de nova linha. A única exceção é se o arquivo de texto estiver vazio (sem linhas).

Leslie Krause
fonte
1
Por que estou com voto negativo -2? Eu apontei não apenas a confirmação do que outras respostas afirmaram (ou seja, ferramentas padrão baseadas em UNIX esperam uma nova linha como terminador de linhas), mas também que não há como distinguir um arquivo vazio de uma única linha vazia, o que é absolutamente verdadeiro. . Respondi especificamente à pergunta original "Qual é o significado da mensagem e o que ela está tentando nos dizer?"
Leslie Krause
Não diminuí a votação, mas essa resposta parece ser específica para sistemas do tipo Unix, pois só se aplica quando uma nova linha é apenas o caractere da nova linha. Não está claro que isso se aplica aqui. Além disso, o aviso parece inútil se o arquivo consistir em apenas uma linha vazia. No entanto, evito o Stackoverflow porque as pessoas muitas vezes votam sem explicação.
user34660
9

Há uma coisa que não vejo nas respostas anteriores. Aviso sobre nenhum final de linha pode ser um aviso quando uma parte de um arquivo for truncada. Pode ser um sintoma de falta de dados.

user34660
fonte
Bom ponto em geral, mas não acho que faça sentido no contexto dessa questão em particular.
precisa saber é o seguinte
@ cst1992 As respostas no Stackoverflow devem ser tão úteis quanto possível, o que significa que devem se aplicar a todas as possibilidades. A pergunta é curta e não vejo onde exclui a possibilidade que sugeri.
user34660
7

O principal problema é o que você define linha e se a sequência de caracteres final on-line faz parte da linha ou não. Editores baseados em UNIX (como VIM) ou ferramentas (como Git) usam a seqüência de caracteres EOL como terminador de linha, portanto, isso faz parte da linha. É semelhante ao uso de ponto e vírgula (;) em C e Pascal. No ponto-e-vírgula C termina as instruções, em Pascal as separa.

mmcorrelo
fonte
4

Na verdade, isso causa um problema, porque as terminações de linha são modificadas automaticamente e sujam os arquivos sem fazer nenhuma alteração neles. Veja este post para resolução.

git substituindo LF por CRLF

Brian Blum
fonte
3

Os arquivos de origem geralmente são concatenados por ferramentas (C, C ++: arquivos de cabeçalho, Javascript: empacotadores). Se você omitir o caractere de nova linha, poderá introduzir erros desagradáveis ​​(onde a última linha de uma fonte é concatenada com a primeira linha do próximo arquivo de origem). Felizmente, todas as ferramentas de concatenação do código-fonte por aí inserem uma nova linha entre os arquivos concatenados, mas isso nem sempre parece ser o caso.

O cerne da questão é - na maioria dos idiomas, as novas linhas têm significado semântico e o final do arquivo não é uma alternativa definida pelo idioma para o caractere da nova linha. Portanto, você deve encerrar cada declaração / expressão com um caractere de nova linha - incluindo o último.

Doug Coburn
fonte
1
Em C / C ++, você pode escrever todo o seu projeto em uma linha. Não há necessidade de nova linha.
O incrível Jan
Você pode escrever todo o seu projeto em uma linha ... se você não usar um //comentário de estilo no meio do código.
Doug Coburn
2

Seu arquivo original provavelmente não tinha nenhum caractere de nova linha.

No entanto, alguns editores como o gedit no linux silenciosamente adicionam nova linha no final do arquivo. Você não pode se livrar dessa mensagem enquanto estiver usando esse tipo de editor.

O que tentei superar esse problema é abrir um arquivo com o editor de código do visual studio

Este editor mostra claramente a última linha e você pode excluir a linha como desejar.

Berkay92
fonte
0

Pelo que vale, eu encontrei isso quando criei um projeto IntelliJ em um Mac e depois mudei o projeto para a minha máquina Windows. Eu tive que abrir manualmente todos os arquivos e alterar a configuração de codificação na parte inferior direita da janela do IntelliJ. Provavelmente não está acontecendo com a maioria, se alguém que leu esta pergunta, mas que poderia ter me poupado algumas horas de trabalho ...

Lou Morda
fonte