git-diff per ignorare ^ M


474

In un progetto in cui alcuni file contengono ^ M come separatori newline. Diffondere questi file è apparentemente impossibile, dal momento che git-diff lo vede come l'intero file è solo una singola riga.

In che modo si differenzia dalla versione precedente?

Esiste un'opzione come "tratta ^ M come newline quando diffing"?

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>

AGGIORNARE:

ora ho scritto uno script di Ruby che verifica le ultime 10 revisioni e converte CR in 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

7
si può avere voluto git diff -b- ho mostrato questo in stackoverflow.com/a/46265081/58794
Jason Pyeron

6
Con Git 2.16 (Q1 2018), avrai git diff --ignore-cr-at-eol. Vedi la mia risposta qui sotto .
VonC,

7
@JasonPyeron e per i futuri Googler: ho dovuto cercare git diff -bidentico a git diff --ignore-space-change.
Gogowitsch,

Risposte:


392

GitHub suggerisce che dovresti assicurarti di usare \ n solo come carattere di nuova riga nei repository gestiti da git. C'è un'opzione per la conversione automatica:

$ git config --global core.autocrlf true

Naturalmente, si dice che converta crlf in lf, mentre tu vuoi convertire cr in lf. Spero che funzioni ancora ...

E poi converti i tuoi file:

# 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 è descritto nella pagina man .


1
No, ovviamente no, una volta che l'impostazione è lì, si convertirà silenziosamente al commit. Se tutto funziona come penso, cioè ...
nes1983,

1
Il problema è che ho già alcuni file nel repository che hanno terminazioni CRLF e altri che no. Sospetto che Adobe Flash aggiunga CRLF anche se sto usando la versione per Mac. Devo confrontare con le versioni precedenti di questi file. La conversione delle terminazioni di linea a partire da ora in poi non risolve il problema con le revisioni precedenti: - /
neoneye,

65
Non stai lavorando con i file CRLF qui, almeno non nell'esempio che hai pubblicato. Questo è un file mac vecchio stile (usa solo \ r per EOL). Ecco perché il diff viene mostrato su una riga. Un file che utilizza dos EOL mostrerebbe ogni riga in modo distinto con un ^ M finale, che potresti dire ottenere da gestire tramite git config core.whitespace cr-at-eol.
Jamessan,

12
Ci sto provando, ma continuo a ricevere warning: LF will be replaced by CRLFinvece di warning: CRLF will be replaced by LF, e sono su Linux. Qualche idea sul perché? Voglio che tutto finisca con LF, non con CRLF!
trusktr,

5
@trusktr, è successo lo stesso a me. In linux, con CRLF accidentale, usa git config --global core.autocrlf input, fai i passaggi in questa risposta (rm, aggiungi, commit), e otterrai warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Rimuovere i file (perché hanno il CRLF originale errato) e ricontrollarli dall'ultimo commit "Correggi CRLF".
jmmut,

370

Sviluppandomi su Windows, ho riscontrato questo problema durante l'utilizzo git tfs. L'ho risolto in questo modo:

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

Questo sostanzialmente dice a Git che un CR di fine linea non è un errore. Di conseguenza, quei fastidiosi ^Mcaratteri non appaiono più alla fine di linee in git diff, git showecc

Sembra lasciare le altre impostazioni così come sono; ad esempio, gli spazi extra alla fine di una riga vengono comunque visualizzati come errori (evidenziati in rosso) nel diff.

(Altre risposte hanno fatto allusione a questo, ma quanto sopra è esattamente come impostare l'impostazione. Per impostare un'impostazione per un solo progetto, omettere il --global.)

MODIFICA :

Dopo molti travagli di fine riga, ho avuto la migliore fortuna, lavorando su un team .NET, con queste impostazioni:

  • NO impostazione core.eol
  • NESSUNA impostazione core.whitespace
  • NO impostazione core.autocrlf
  • Quando esegui il programma di installazione di Git per Windows, otterrai queste tre opzioni:
    • Acquista in stile Windows, esegui il commit delle terminazioni di linea in stile Unix <- scegli questa
    • Acquista così com'è, impegna le terminazioni di linea in stile Unix
    • Acquista così com'è, esegui il commit così com'è

Se è necessario utilizzare l'impostazione degli spazi bianchi, probabilmente è necessario abilitarla solo per progetto se è necessario interagire con TFS. Ometti il --global:

git config core.whitespace cr-at-eol

Se è necessario rimuovere alcune impostazioni di base. *, Il modo più semplice è eseguire questo comando:

git config --global -e

Questo apre il tuo file .gitconfig globale in un editor di testo e puoi facilmente eliminare le righe che vuoi rimuovere. (Oppure puoi mettere '#' davanti a loro per commentarli.)


30
Per coloro che trovano questo momento, vale la pena notare che Checkout in stile Windows, commettono linea terminazioni in stile Unix auto-set core.autocrlfatrue
K. Carpenter

14
Si noti che la linea git config --global core.whitespace cr-at-eoldisattiverà altre impostazioni predefinite. Esistono tre valori predefiniti: blank-at-eol, blank-at-eof e space-before-tab. Quindi per abilitare cr-at-eol mantenendo gli altri che dovresti usare git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Zitrax,

2
Per il mio progetto (era il checkout su Windows e lo sto visualizzando su Linux), mi cr-at-eolsono sbarazzato della ^Mfine delle linee git diff, ma GIT ha comunque mostrato quelle linee come diverse, anche se il finale era l'unica differenza.
Jānis Elmeris,

SourceInsight continua a spingere il carattere ^ M e git mostra ancora la differenza alla fine della riga. @ Il comando di Zitrax è la risposta giusta al mio caso, git diff mostra un output piacevole e pulito.
Lê Quang Duy,

3
Penso che git abbia bisogno di un po 'più di complessità, alcune impostazioni più contrastanti per la fine della linea. Penso che Git dovrebbe essere più preoccupato per i miei spazi bianchi. Ad esempio, genera un errore irreversibile non correlato e lascia il repository in uno stato corrotto quando si verificano terminazioni di linea Mac su un computer Windows (ma non Linux). Voglio dire, perché dovrei usare un VCS che si preoccuperebbe degli affari e mi permetta di usare qualsiasi terminazione di linea che voglio? Vedo che ci stanno provando, ma dovrebbero lanciare una mezza dozzina di comportamenti di fine linea per risolvere un problema che non esiste. Sono quasi arrivati! Continuate così.
Rolf,

125

Prova git diff --ignore-space-at-eol, o git diff --ignore-space-change, o git diff --ignore-all-space.


22
Niente di tutto ciò influisce sul personaggio che identifica la nuova riga.
nes1983,

4
Ho anche provato con "-w", ma senza fortuna, lo tratta ancora come una riga singola. Prossimo progetto devo ricordare di non avere mai alcun CR nel codice sorgente.
Neoneye,

3
Ricorda solo git config --global core.autocrlf true, o bug the git people fino a quando non lo rendono predefinito :)
nes1983,

10
Ciò ha risolto il mio problema senza dover modificare le mie autocrlfimpostazioni. Grazie!
nneonneo,

11
queste bandiere non hanno alcun effetto per me ... mostrano ancora ^ M come diff
Magnus

103

Vedi anche:

core.whitespace = cr-at-eol

o equivalentemente,

[core]
    whitespace = cr-at-eol

dove whitespaceè preceduto da un carattere di tabulazione .


4
Sì, questo ha fatto sì che lo strumento git diff (usato anche in git show) smettesse di darmi fastidio sulle ^Ms sulle linee modificate! :)
Rijk,

2
per qualunque motivo questo non ha funzionato per me. Ho provato entrambi con il segno = e no =. git diffmostra ancora ^ M caratteri.
Dennis,

6
Due modi per farlo: uno, aggiungi la riga sopra alla lettera .gitconfig in .git / config o in ~ / .gitconfig; due, git config --global core.whitespace cr-at-eol(dove --global è facoltativo se lo vuoi solo sul repository in cui ti trovi)
K. Carpenter il

Questo ha funzionato per me su Windows 7, anche se l'ho messo in [core]modo da poter sostituire il core.prefisso con un carattere TAB.
Rufflewind,

Questa domanda è stata al di sopra come nascondere ^Min git diff, non di come non mettere in ^ M, in primo luogo. Ciò significa che la risposta accettata alla modifica core.autocrlfnon è la migliore perché altera silenziosamente i file senza la conferma dell'utente.
deddebme,

45

Perché hai questi ^Mnel tuo git diff?

Nel mio caso stavo lavorando a un progetto sviluppato in Windows e ho usato OS X. Quando ho cambiato del codice, ho visto ^Malla fine delle righe che ho aggiunto git diff. Penso che si ^Mstessero presentando perché erano terminazioni di linea diverse rispetto al resto del file. Poiché il resto del file è stato sviluppato in Windows, utilizzava le CRterminazioni di linea e in OS X utilizza le LFterminazioni di linea.

Apparentemente, lo sviluppatore di Windows non ha utilizzato l'opzione " Verifica in stile Windows, esegui il commit di terminazioni di linea in stile Unix " durante l'installazione di Git.

Quindi cosa dovremmo fare al riguardo?

Puoi fare in modo che gli utenti Windows reinstallino git e utilizzare l' opzione " Verifica stile Windows, commit terminazioni di linea in stile Unix ". Questo è ciò che preferirei, perché vedo Windows come un'eccezione nei caratteri di fine riga e Windows risolve il proprio problema in questo modo.

Se scegli questa opzione, dovresti comunque correggere i file correnti (perché stanno ancora usando le CRterminazioni di riga). L'ho fatto seguendo questi passaggi:

  1. Rimuovi tutti i file dal repository, ma non dal tuo filesystem.

    git rm --cached -r .
    
  2. Aggiungi un .gitattributesfile che impone a determinati file di utilizzare un LFfinale di riga. Metti questo nel file:

    *.ext text eol=crlf
    

    Sostituisci .extcon le estensioni dei file che desideri abbinare.

  3. Aggiungi di nuovo tutti i file.

    git add .
    

    Questo mostrerà messaggi come questo:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. È possibile rimuovere il .gitattributesfile a meno che non si disponga di utenti Windows testardi che non desiderano utilizzare l' opzione " Verifica stile Windows, commit terminazioni di linea in stile Unix ".

  5. Impegnati e spingi tutto.

  6. Rimuovere e verificare i file applicabili su tutti i sistemi in cui vengono utilizzati. Sui sistemi Windows, assicurati che ora utilizzino l' opzione " Verifica in stile Windows, esegui il commit di terminazioni di linea in stile Unix ". Dovresti anche farlo sul sistema in cui hai eseguito queste attività perché quando hai aggiunto i file git ha detto:

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

    Puoi fare qualcosa del genere per rimuovere i file:

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

    E quindi questo per ripristinarli con le terminazioni di riga corrette:

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

    Ovviamente sostituendolo .extcon l'estensione desiderata.

Ora il tuo progetto usa solo LFpersonaggi per i finali di linea e i CRpersonaggi cattivi non torneranno mai più :).

L'altra opzione è quella di applicare le terminazioni di linea in stile Windows. Puoi anche usare il .gitattributesfile per questo.

Maggiori informazioni: https://help.github.com/articles/dealing-with-line-endings/#platform-all


4
Per correggere tutte le terminazioni di riga in un file specifico, se si utilizza Sublime Text, è possibile accedere a View-> Line Endingse fare clic su Unix.
Topher Hunt,

Cosa significa esattamente ^M? È una nuova riga di Windows o Linux? O è solo una newline "diversa" rispetto alle altre newline nel file?
buhtz,

Bene, penso sia solo una newline "diversa" (diversa dalla maggior parte degli altri)
gitaarik,

-1 poiché la reinstallazione di git da eseguire git config --global core.autocrlf trueè eccessiva e l'anti-Windows / anti- CRcampagna sembra tangente alla domanda.
RJFalconer

41

Esiste un'opzione come "tratta ^ M come newline quando diffing"?

Ce ne sarà uno con Git 2.16 (Q1 2018), poiché la " diff" famiglia di comandi ha imparato a ignorare le differenze nel ritorno a capo alla fine della riga.

Vedi commit e9282f0 (26 ott 2017) di Junio ​​C Hamano ( gitster) .
Assistito da: Johannes Schindelin (dscho ) .
(Unita da Junio ​​C Hamano - gitster- in commit 10f65c2 , 27 nov 2017)

diff: --ignore-cr-at-eol

Una nuova opzione --ignore-cr-at-eoldice al macchinario diff di trattare un ritorno a capo alla fine di una linea (completa) come se non esistesse.

Proprio come gli altri "--ignore-* " opzioni per ignorare vari tipi di differenze di spazi bianchi, questo ti aiuterà a rivedere le reali modifiche apportate senza essere distratto dalla CRLF<->LFconversione spuria effettuata dal tuo programma di editor.


@kaartic Grazie per aver modificato la risposta e fatto riferimento al commit giusto!
VonC,

3
Sebbene sia generalmente buona norma impostare git config --global core.autocrlf truecome nella risposta accettata, ciò risponde più direttamente alla domanda del PO: "Esiste un'opzione del tipo" tratta ^ M come newline in caso di differenza "?"
drkvogel,

1
A partire da Git 2.20 questo non nasconde ^ M's
user1944491

@ user1944491 Non ho notato alcuna regressione, il che significa che ignora eol quando si differenzia con questa opzione in Git 2.26.
VonC

@VonC L'uso di questo argomento nel comando git diff non ha funzionato. Né impostare il mio valore core.whitespace su git version 2.20.1 (Apple Git-117)ma aggiungendo la risposta core.pager di Jason Pyeron è stato risolto. YMMV ovviamente.
user1944491

26

TL; DR

Cambia il core.pagerin "tr -d '\r' | less -REX", non il codice sorgente

Ecco perché

Quelle fastidiose ^ M mostrate sono un artefatto della colorizzazione e del cercapersone. inserisci qui la descrizione dell'immagine È causato da less -Run'opzione cercapersone git predefinita. (il pager predefinito di git è less -REX)

La prima cosa da notare è che git diff -bnon mostrerà cambiamenti nello spazio bianco (ad es. \ R \ n vs \ n)

impostare:

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

Un rapido test per creare un file unix e modificare le terminazioni di riga non mostrerà modifiche con 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

Notiamo che forzare una pipe a meno non mostra ^ M, ma abilita il colore e less -Rfa:

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

La correzione viene mostrata usando una pipe per rimuovere \ r (^ M) dall'output:

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

Un'alternativa poco saggia è usare less -r, perché passerà attraverso tutti i codici di controllo, non solo i codici colore.

Se vuoi semplicemente modificare direttamente il tuo file git config, questa è la voce per aggiornare / aggiungere:

[core]
        pager = tr -d '\\r' | less -REX

Ho avuto questo problema in un repository in cui alcuni dei file avevano \r\nterminazioni di riga e alcuni avevano \nterminazioni di riga (non so se sia rilevante); le differenze del primo mostravano le ^Mlinee modificate (ovvero le +linee). core.autocrlfera impostato su true. La corsa git config core.pager "tr -d '\r' | less -REX"si è sbarazzata delle fastidiose ^Ms. Grazie!
labreuer,

5
Grazie per questo. Questa è l'unica risposta se devi lavorare con diversi finali di linea nei tuoi repository (p. Es.) Usi checkout così com'è, commit così com'è, intenzionalmente.
Mike

git diff -bè quello che stavo cercando, ma apprezzo la spiegazione approfondita.
Martin Burch,

Questa è la risposta! Grazie. la bandiera -b non ha funzionato per me.
Chris,

Sì! Di tutte le risposte a questa domanda, la modifica della [core]sezione del file "config" con l' aggiunta è pager = tr -d '\\r' | less -REXstata l'unica risposta che ha funzionato per me. Grazie!
Rashiki,

13

Ho lottato con questo problema per molto tempo. Di gran lunga la soluzione più semplice è quella di non preoccuparsi dei caratteri ^ M e usare semplicemente uno strumento di visualizzazione visiva in grado di gestirli.

Invece di digitare:

git diff <commitHash> <filename>

provare:

git difftool <commitHash> <filename>

1
Grazie! Inoltre ho appena eseguito "git difftool" e fondamentalmente ha confrontato tutti i file modificati in un ciclo
Bhanuprakash D


2

Come notato da VonC, questo è già stato incluso in git 2.16+. Sfortunatamente, il nome dell'opzione ( --ignore-cr-at-eol) differisce da quello usato da GNU diff a cui sono abituato ( --strip-trailing-cr).

Quando mi sono trovato di fronte a questo problema, la mia soluzione era quella di invocare GNU diff invece del diff incorporato di git, perché il mio git è più vecchio di 2.16. L'ho fatto usando questa riga di comando:

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

Ciò consente l'utilizzo --strip-trailing-cre qualsiasi altra opzione diff GNU.

C'è anche questo altro modo:

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

ma non utilizza le impostazioni del cercapersone configurate, motivo per cui preferisco la prima.


Alternativa interessante alla mia risposta. Upvoted.
VonC,
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.