git-diff para ignorar ^ M

474

Em um projeto em que alguns dos arquivos contêm ^ M como separadores de nova linha. A difusão desses arquivos é aparentemente impossível, pois o git-diff vê como o arquivo inteiro é apenas uma única linha.

Como alguém se diferencia da versão anterior?

Existe uma opção como "tratar ^ M como nova linha ao diferir"?

prompt> git-diff "HEAD^" -- MyFile.as 
diff --git a/myproject/MyFile.as b/myproject/MyFile.as
index be78321..a393ba3 100644
--- a/myproject/MyFile.cpp
+++ b/myproject/MyFile.cpp
@@ -1 +1 @@
-<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
+<U+FEFF>import flash.events.MouseEvent;^Mimport mx.controls.*;^Mimport mx.utils.Delegate
\ No newline at end of file
prompt>

ATUALIZAR:

agora escrevi um script Ruby que verifica as últimas 10 revisões e converte CR em LF.

require 'fileutils'

if ARGV.size != 3
  puts "a git-path must be provided"
  puts "a filename must be provided"
  puts "a result-dir must be provided"
  puts "example:"
  puts "ruby gitcrdiff.rb project/dir1/dir2/dir3/ SomeFile.cpp tmp_somefile"
  exit(1)
end

gitpath = ARGV[0]
filename = ARGV[1]
resultdir = ARGV[2]

unless FileTest.exist?(".git")
  puts "this command must be run in the same dir as where .git resides"
  exit(1)
end

if FileTest.exist?(resultdir)
  puts "the result dir must not exist"
  exit(1)
end
FileUtils.mkdir(resultdir)

10.times do |i|
  revision = "^" * i
  cmd = "git show HEAD#{revision}:#{gitpath}#{filename} | tr '\\r' '\\n' > #{resultdir}/#{filename}_rev#{i}"
  puts cmd 
  system cmd
end
neoneye
fonte
7
você pode ter querido git diff -b- Mostrei isso em stackoverflow.com/a/46265081/58794
Jason Pyeron
6
Com o Git 2.16 (primeiro trimestre de 2018), você terá git diff --ignore-cr-at-eol. Veja minha resposta abaixo .
VonC 29/11
7
@ JasonPyeron e para futuros Googlers: eu tive que procurar que git diff -bé idêntico git diff --ignore-space-change.
Gogowitsch 30/12/19

Respostas:

392

O GitHub sugere que você deve usar \ n apenas como um caractere de nova linha em repositórios manipulados por git. Há uma opção para converter automaticamente:

$ git config --global core.autocrlf true

Obviamente, isso é dito para converter crlf em lf, enquanto você deseja converter crlf em lf. Espero que isso ainda funcione ...

E depois converta seus arquivos:

# Remove everything from the index
$ git rm --cached -r .

# Re-add all the deleted files to the index
# You should get lots of messages like: "warning: CRLF will be replaced by LF in <file>."
$ git diff --cached --name-only -z | xargs -0 git add

# Commit
$ git commit -m "Fix CRLF"

core.autocrlf é descrito na página do manual .

nes1983
fonte
1
Não, claro que não, uma vez que a configuração esteja lá, ela será convertida silenciosamente após a confirmação. Se tudo funciona da maneira que eu acho que funciona, é…
nes1983 11/12/09
1
O problema é que eu já tenho alguns arquivos no repositório que possuem terminações CRLF e outros que não. Eu suspeito que o Adobe Flash adicione CRLF mesmo que eu esteja usando a versão Mac. Preciso comparar com revisões mais antigas desses arquivos. A conversão de terminações de linha a partir de agora não resolve o problema com revisões mais antigas: - /
neoneye
65
Você não está trabalhando com arquivos CRLF aqui, pelo menos não no exemplo que você postou. Esse é um arquivo mac à moda antiga (apenas usa \ r para EOL). É por isso que o diff está sendo mostrado em uma linha. Um arquivo usando dos EOL mostraria cada linha distintamente com um ^ M à direita, que você poderia dizer para manipular via git config core.whitespace cr-at-eol.
jamessan
12
Eu estou tentando isso, mas eu continuo recebendo warning: LF will be replaced by CRLFem vez de warning: CRLF will be replaced by LF, e eu estou em Linux. Alguma idéia do porquê? Quero que tudo termine com LF, não com CRLF!
trusktr 23/02
5
@trusktr, aconteceu o mesmo comigo. No linux, com CRLF acidental, use git config --global core.autocrlf input, execute as etapas nesta resposta (rm, adicione, confirme) e você obterá warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Remova os arquivos (porque eles têm o CRLF original errado) e faça o check-out novamente do último commit "Fix CRLF".
jmmut
370

Desenvolvendo no Windows, encontrei esse problema ao usar git tfs. Eu resolvi assim:

git config --global core.whitespace cr-at-eol

Isso basicamente diz ao Git que um CR de fim de linha não é um erro. Como um resultado, essas irritantes ^Mcaracteres já não aparecem no fim das linhas no git diff, git showetc.

Parece deixar outras configurações como estão; por exemplo, espaços extras no final de uma linha ainda aparecem como erros (destacados em vermelho) no diff.

(Outras respostas aludiram a isso, mas o acima é exatamente como definir a configuração. Para definir a configuração para apenas um projeto, omita o --global.)

EDIT :

Depois de muitas tarefas de final de linha, tive a melhor sorte, ao trabalhar em uma equipe .NET, com estas configurações:

  • SEM configuração core.eol
  • SEM configuração core.whitespace
  • NENHUMA configuração core.autocrlf
  • Ao executar o instalador do Git para Windows, você terá estas três opções:
    • Faça checkout no estilo Windows, confirme finais de linha no estilo Unix <- escolha este
    • Faça o checkout como está, confirme finais de linha no estilo Unix
    • Fazer check-out como está, confirmar como está

Se você precisar usar a configuração de espaço em branco, provavelmente deverá ativá-la somente por projeto, se precisar interagir com o TFS. Apenas omita o --global:

git config core.whitespace cr-at-eol

Se você precisar remover algumas configurações principais. *, A maneira mais fácil é executar este comando:

git config --global -e

Isso abre seu arquivo .gitconfig global em um editor de texto e você pode excluir facilmente as linhas que deseja remover. (Ou você pode colocar '#' na frente deles para comentar.)

Ryan Lundy
fonte
30
Para aqueles que acham isso agora, vale a pena notar que a Caixa de estilo Windows, Unix comprometer-estilo finais de linha auto-sets core.autocrlfparatrue
K. Carpenter
14
Observe que a linha git config --global core.whitespace cr-at-eoldesativaria outras configurações padrão. Existem três padrões: espaço em branco na etiqueta, espaço em branco e espaço antes da guia. Portanto, para ativar o cr-at-eol, mantendo os outros que você precisaria usar git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Zitrax 27/09
2
Para o meu projeto (foi finalizado no Windows e estou visualizando no Linux), acabei me cr-at-eollivrando ^Mno final das linhas git diff, mas o GIT ainda mostrava essas linhas como diferentes, embora o final da linha fosse a única diferença.
Jānis Elmeris
O SourceInsight continua pressionando o caractere ^ M, e o git ainda mostra a diferença nos finais de linha. O comando do @ Zitrax é a resposta certa para o meu caso, git diff show, saída agradável e limpa.
Lê Quang Duy
3
Acho que o git precisa de um pouco mais de complexidade, mais algumas configurações conflitantes para o fim da linha. Eu acho que o git deveria estar mais preocupado com meus espaços em branco. Por exemplo, lance um erro fatal não relacionado e deixe o repositório em um estado corrompido ao encontrar terminações de linha Mac em uma máquina Windows (mas não Linux). Quero dizer, por que eu usaria um VCS que se importaria com os negócios e me deixasse usar qualquer final de linha que eu quisesse? Vejo que eles estão tentando, mas devem lançar mais meia dúzia de comportamentos de final de linha, para resolver um problema que não existe. Eles estão quase lá! Mantem.
Rolf
125

Tente git diff --ignore-space-at-eol, ou git diff --ignore-space-change, ou git diff --ignore-all-space.

Jakub Narębski
fonte
22
Nada disso realmente afeta o personagem que identifica a nova linha.
Ns1983
4
Eu também tentei com "-w", mas sem sorte, ainda o trata como uma única linha. No próximo projeto, devo me lembrar de nunca inserir nenhum CR no código-fonte.
11555 neoneye
3
Lembre-se de git config --global core.autocrlf true, ou insira o pessoal do git até que ele se torne o padrão :) :)
nes1983
10
Isso resolveu meu problema sem precisar alterar minhas autocrlfconfigurações. Obrigado!
N15
11
essas bandeiras não têm nenhum efeito para mim ... ainda mostra ^ M como diffs
Magnus
103

Veja também:

core.whitespace = cr-at-eol

ou equivalente,

[core]
    whitespace = cr-at-eol

onde whitespaceé precedido por um caractere de tabulação .

Vladimir Panteleev
fonte
4
Sim, isso fez a ferramenta git diff (também usada em git show) parar de me incomodar com os ^Ms nas linhas alteradas! :) #
31312 Rijk
2
por qualquer motivo, isso não funcionou para mim. Tentei tanto com = e no = sinal. git diffainda mostra ^ M caracteres.
Dennis
6
Duas maneiras de fazer isso: primeiro, adicione a linha acima literalmente ao seu .gitconfig em .git / config ou em ~ / .gitconfig; dois, git config --global core.whitespace cr-at-eol(onde --global é opcional, se você só quer que o repo você está no)
K. Carpenter
Isso funcionou para mim no Windows 7, embora eu apenas o tenha colocado [core]para substituir o core.prefixo por um caractere TAB.
Rufflewind 27/02
Esta questão estava acima de como esconder ^M-se git diff, não de como não colocar ^ M em primeiro lugar. Isso significa que a resposta aceita para a alteração core.autocrlfnão é a melhor porque altera silenciosamente os arquivos sem a confirmação do usuário.
Deddebme 3/17
45

Por que você os coloca ^Mno seu git diff?

No meu caso, eu estava trabalhando em um projeto desenvolvido no Windows e usei o OS X. Quando alterei algum código, vi ^Mno final das linhas adicionadas git diff. Eu acho ^Mque eles estavam aparecendo porque eram finais de linha diferentes dos demais arquivos. Como o restante do arquivo foi desenvolvido no Windows, ele utilizava CRfinais de linha e, no OS X, LFfinal de linha.

Aparentemente, o desenvolvedor do Windows não usou a opção "Fazer checkout no estilo Windows, confirmar finais de linha no estilo Unix " durante a instalação do Git.

Então, o que devemos fazer sobre isso?

Você pode fazer com que os usuários do Windows reinstale o git e use a opção " Checkout no estilo Windows, confirme finais de linha no estilo Unix ". É isso que eu preferiria, porque vejo o Windows como uma exceção em seus caracteres de final de linha e o Windows corrige seu próprio problema dessa maneira.

Se você optar por esta opção, deverá corrigir os arquivos atuais (porque eles ainda estão usando as CRterminações de linha). Eu fiz isso seguindo estas etapas:

  1. Remova todos os arquivos do repositório, mas não do seu sistema de arquivos.

    git rm --cached -r .
    
  2. Adicione um .gitattributesarquivo que imponha certos arquivos para usar um LFfinal de linha. Coloque isso no arquivo:

    *.ext text eol=crlf
    

    Substitua .extpelas extensões de arquivo que você deseja corresponder.

  3. Adicione todos os arquivos novamente.

    git add .
    

    Isso mostrará mensagens como esta:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. Você pode remover o .gitattributesarquivo, a menos que tenha usuários teimosos do Windows que não desejam usar a opção " Checkout no estilo Windows, confirmar finalizações de linha no estilo Unix ".

  5. Comprometa e empurre tudo.

  6. Remova e faça o check-out dos arquivos aplicáveis ​​em todos os sistemas em que são usados. Nos sistemas Windows, certifique-se de que agora eles usem a opção " Checkout no estilo Windows, confirme finais de linha no estilo Unix ". Você também deve fazer isso no sistema em que executou essas tarefas, porque quando você adicionou os arquivos, o git disse:

    The file will have its original line endings in your working directory.
    

    Você pode fazer algo assim para remover os arquivos:

    git ls | grep ".ext$" | xargs rm -f
    

    E então, para recuperá-los com as terminações de linha corretas:

    git ls | grep ".ext$" | xargs git checkout
    

    É claro que substituindo .extpela extensão que você deseja.

Agora, seu projeto usa apenas LFcaracteres para as terminações de linha, e os CRcaracteres desagradáveis nunca mais voltarão :).

A outra opção é aplicar as terminações de linha de estilo do Windows. Você também pode usar o .gitattributesarquivo para isso.

Mais informações: https://help.github.com/articles/dealing-with-line-endings/#platform-all

gitaarik
fonte
4
Para corrigir todas as terminações de linha em um arquivo específico, se você estiver usando Sublime Text, pode ir para View-> Line Endingse clicar em Unix.
Topher Hunt
O que exatamente isso ^Msignifica? É uma nova linha do Windows ou Linux? Ou é apenas uma nova linha "diferente" em comparação com as outras novas linhas no arquivo?
buhtz
Bom, eu acho que é apenas uma nova linha "diferente" (diferente da maioria dos outros)
gitaarik
-1 como reinstalar o git para realizar git config --global core.autocrlf trueé um exagero, e a anti-Windows / anti- CRcampaign parece tangencial à pergunta.
RJFalconer 29/01
41

Existe uma opção como "tratar ^ M como nova linha ao diferir"?

Haverá um com o Git 2.16 (primeiro trimestre de 2018), como o "diff família de comandos " aprendeu a ignorar as diferenças no retorno de carro no final da linha.

Veja commit e9282f0 (26 de outubro de 2017) por Junio ​​C Hamano ( gitster) .
Ajudado por: Johannes Schindelin ( dscho) .
(Mesclado por Junio ​​C Hamano - gitster- na confirmação 10f65c2 , 27 de novembro de 2017)

diff: --ignore-cr-at-eol

Uma nova opção --ignore-cr-at-eolinforma ao equipamento diff para tratar um retorno de carro no final de uma linha (completa) como se ela não existisse.

Assim como outras " --ignore-*" opções para ignorar vários tipos de diferenças de espaço em branco, isso ajudará a revisar as mudanças reais que você fez sem se distrair com CRLF<->LFconversões espúrias feitas pelo seu programa de edição.

VonC
fonte
@kaartic Obrigado por editar a resposta e referenciar o commit correto!
VonC 15/05/19
3
Embora geralmente seja uma boa prática definir git config --global core.autocrlf truecomo na resposta aceita, isso responde mais diretamente à pergunta do OP: 'Existe uma opção como "tratar ^ M como nova linha ao diferir"?
drkvogel
1
No Git 2.20, isso não oculta ^ M's
user1944491
@ user1944491 Não notei nenhuma regressão, o que significa que ela ainda ignora o eol ao diferenciar esta opção no Git 2.26.
VonC 01/04
@VonC O uso desse argumento no comando git diff não funcionou. Nem definir meu valor de core.whitespace, git version 2.20.1 (Apple Git-117)mas adicionar a resposta core.pager de Jason Pyeron, o corrigiu. YMMV obviamente.
user1944491 2/04
26

TL; DR

Mude core.pagerpara para "tr -d '\r' | less -REX", não para o código fonte

Isso é por que

Os incômodos ^ M mostrados são um artefato da colorização e do pager. insira a descrição da imagem aqui É causada por less -Ruma opção padrão do git pager. (o pager padrão do git é less -REX)

A primeira coisa a observar é que git diff -bnão mostrará alterações no espaço em branco (por exemplo, \ r \ n vs \ n)

configuração:

git clone https://github.com/CipherShed/CipherShed
cd CipherShed

Um teste rápido para criar um arquivo unix e alterar as terminações de linha não mostrará alterações com git diff -b:

echo -e 'The quick brown fox\njumped over the lazy\ndogs.' > test.txt
git add test.txt
unix2dos.exe test.txt
git diff -b test.txt

Observamos que forçar um tubo para menos não mostra o ^ M, mas ativando a cor e less -R:

git diff origin/v0.7.4.0 origin/v0.7.4.1 | less
git -c color.ui=always diff origin/v0.7.4.0 origin/v0.7.4.1 | less -R

A correção é mostrada usando um tubo para remover o \ r (^ M) da saída:

git diff origin/v0.7.4.0 origin/v0.7.4.1
git -c core.pager="tr -d '\r' | less -REX"  diff origin/v0.7.4.0 origin/v0.7.4.1

Uma alternativa imprudente é usar less -r, porque passará por todos os códigos de controle, não apenas pelos códigos de cores.

Se você quiser apenas editar seu arquivo de configuração git diretamente, esta é a entrada para atualizar / adicionar:

[core]
        pager = tr -d '\\r' | less -REX
Jason Pyeron
fonte
Tive esse problema em um repositório em que alguns dos arquivos tinham \r\nfinais de linha e outros tinham \nfinal de linha (não sei se isso é relevante); diffs do primeiro mostrou o ^Mnas linhas modificadas (ou seja, as +linhas). core.autocrlffoi definido como true. Correr git config core.pager "tr -d '\r' | less -REX"se livrou dos traquinas ^M. Obrigado!
labreuer
5
Obrigado por isso. Esta é a única resposta se você deve trabalhar com terminações de linhas diferentes nos seus repositórios - por exemplo, você usa o checkout como está, confirma como está, propositalmente.
1455 Mike
git diff -bé o que eu estava procurando, mas aprecio a explicação completa.
Martin Burch
Esta é a resposta! Obrigado. a bandeira -b não funcionou para mim.
Chris
Sim! De todas as respostas a esta pergunta, modificar a [core]seção do arquivo "config" do git adicionando pager = tr -d '\\r' | less -REXfoi a única resposta que funcionou para mim. Obrigado!
Rashiki
13

Eu lutei com esse problema por um longo tempo. De longe, a solução mais fácil é não se preocupar com os caracteres ^ M e apenas usar uma ferramenta visual diff que possa lidar com eles.

Em vez de digitar:

git diff <commitHash> <filename>

tentar:

git difftool <commitHash> <filename>
Ian Wojtowicz
fonte
1
Obrigado! Também executei o "git difftool" e ele basicamente comparou todos os arquivos alterados em um loop #
Bhanuprakash D
2

Conforme observado pelo VonC, isso já foi incluído no git 2.16+. Infelizmente, o nome da opção ( --ignore-cr-at-eol) difere daquele usado pelo GNU diff com o qual estou acostumado ( --strip-trailing-cr).

Quando fui confrontado com esse problema, minha solução foi chamar o GNU diff em vez do diff interno do git, porque meu git é mais antigo que 2.16. Eu fiz isso usando esta linha de comando:

GIT_EXTERNAL_DIFF='diff -u --strip-trailing-cr "$2" "$5";true;#' git diff --ext-diff

Isso permite o uso --strip-trailing-cre qualquer outra opção de diferença GNU.

Há também esta outra maneira:

git difftool -y -x 'diff -u --strip-trailing-cr'

mas não usa as configurações do pager, e é por isso que prefiro o primeiro.

Pedro Gimeno
fonte
Alternativa interessante para a minha resposta. Votado.
VonC 04/10/19