Git-Diff zu ignorieren ^ M.

474

In einem Projekt, in dem einige der Dateien ^ M als Zeilenumbruchtrennzeichen enthalten. Das Differenzieren dieser Dateien ist anscheinend unmöglich, da git-diff dies als eine einzige Zeile ansieht.

Wie unterscheidet man sich von der Vorgängerversion?

Gibt es eine Option wie "^ M als Newline behandeln, wenn Sie sich unterscheiden"?

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>

AKTUALISIEREN:

Jetzt habe ich ein Ruby-Skript geschrieben, das die letzten 10 Revisionen überprüft und CR in LF konvertiert.

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
quelle
7
Sie wollten vielleicht git diff -b- ich habe dies in stackoverflow.com/a/46265081/58794 gezeigt
Jason Pyeron
6
Mit Git 2.16 (Q1 2018) haben Sie git diff --ignore-cr-at-eol. Siehe meine Antwort unten .
VonC
7
@ JasonPyeron und für zukünftige Googler: Ich musste nachschlagen, das git diff -bist identisch mit git diff --ignore-space-change.
Gogowitsch

Antworten:

392

GitHub schlägt vor, dass Sie sicherstellen sollten, dass Sie \ n nur als Zeilenumbruchzeichen in Repos verwenden, die mit Git behandelt werden. Es gibt eine Option zum automatischen Konvertieren:

$ git config --global core.autocrlf true

Natürlich soll dies crlf in lf konvertieren, während Sie cr in lf konvertieren möchten. Ich hoffe das funktioniert noch ...

Und dann konvertieren Sie Ihre Dateien:

# 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 wird auf der Manpage beschrieben .

nes1983
quelle
1
Nein, natürlich nicht, sobald die Einstellung vorhanden ist, wird sie beim Festschreiben stillschweigend konvertiert. Wenn alles so funktioniert, wie ich denke, dann…
nes1983
1
Das Problem ist, dass ich bereits einige Dateien im Repository habe, die CRLF-Endungen haben, und andere, die dies nicht tun. Ich vermute, dass Adobe Flash CRLF hinzufügt, obwohl ich die Mac-Version verwende. Ich muss mit älteren Revisionen dieser Dateien vergleichen. Das Konvertieren von Zeilenenden ab sofort löst das Problem mit älteren Revisionen nicht: - /
neoneye
65
Sie arbeiten hier nicht mit CRLF-Dateien, zumindest nicht in dem von Ihnen veröffentlichten Beispiel. Dies ist eine Mac-Datei im alten Stil (verwendet nur \ r für EOL). Deshalb wird der Unterschied in einer Zeile angezeigt. Eine Datei, die dos EOL verwendet, zeigt jede Zeile deutlich mit einem abschließenden ^ M an, über das Sie erfahren können, wie Sie damit umgehen sollen git config core.whitespace cr-at-eol.
Jamessan
12
Ich versuche, aber ich bekomme immer wieder warning: LF will be replaced by CRLFstatt warning: CRLF will be replaced by LF, und ich bin in Linux. Irgendeine Idee warum? Ich möchte, dass alles mit LF endet, nicht mit CRLF!
Trusktr
5
@trusktr, es ist mir genauso passiert. Führen Sie unter Linux mit versehentlichem CRLF git config --global core.autocrlf inputdie Schritte in dieser Antwort aus (rm, add, commit), und Sie erhalten warning: CRLF will be replaced by LF. The file will have its original line endings in your working directory.. Entfernen Sie die Dateien (da sie die ursprüngliche, falsche CRLF haben) und checken Sie sie erneut aus dem letzten Commit "Fix CRLF" aus.
Jmmut
370

Bei der Entwicklung unter Windows bin ich bei der Verwendung auf dieses Problem gestoßen git tfs. Ich habe es so gelöst:

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

Dies sagt Git im Grunde, dass ein CR am Ende der Zeile kein Fehler ist. Als Ergebnis die lästigen ^Merscheinen Zeichen nicht mehr am Ende der Zeilen git diff, git showusw.

Es scheint, als ob andere Einstellungen unverändert bleiben. Beispielsweise werden zusätzliche Leerzeichen am Ende einer Zeile weiterhin als Fehler (rot hervorgehoben) im Diff angezeigt.

(Andere Antworten haben darauf hingewiesen, aber oben wird genau beschrieben, wie die Einstellung festgelegt wird. Um die Einstellung nur für ein Projekt festzulegen, lassen Sie die Option weg --global.)

BEARBEITEN :

Nach vielen Schwierigkeiten am Zeilenende hatte ich das beste Glück, als ich in einem .NET-Team mit folgenden Einstellungen arbeitete:

  • KEINE core.eol Einstellung
  • KEINE core.whitespace-Einstellung
  • KEINE core.autocrlf Einstellung
  • Wenn Sie das Git-Installationsprogramm für Windows ausführen, erhalten Sie die folgenden drei Optionen:
    • Kasse Windows-Stil, Festschreiben von Zeilenenden im Unix-Stil <- Wählen Sie diese aus
    • Beim Auschecken unverändert Zeilenenden im Unix-Stil festschreiben
    • Kasse wie sie ist, Commit wie sie ist

Wenn Sie die Whitespace-Einstellung verwenden müssen, sollten Sie sie wahrscheinlich nur pro Projekt aktivieren, wenn Sie mit TFS interagieren müssen. Lassen Sie einfach das weg --global:

git config core.whitespace cr-at-eol

Wenn Sie einige Core. * -Einstellungen entfernen müssen, können Sie diesen Befehl am einfachsten ausführen:

git config --global -e

Dadurch wird Ihre globale .gitconfig-Datei in einem Texteditor geöffnet, und Sie können die zu entfernenden Zeilen problemlos löschen. (Oder Sie können '#' vor sie setzen, um sie zu kommentieren.)

Ryan Lundy
quelle
30
Für diejenigen, die dies jetzt finden, ist es erwähnenswert, dass Checkout Windows-Stil, Unix-Stil Zeilenenden automatisch setzt core.autocrlfauftrue
K. Carpenter
14
Beachten Sie, dass die Leitung git config --global core.whitespace cr-at-eolandere Standardeinstellungen deaktiviert. Es gibt drei Standardeinstellungen: blank-at-eol, blank-at-eof und Leerzeichen vor der Registerkarte. Um cr-at-eol zu aktivieren und gleichzeitig die anderen zu behalten, die Sie verwenden müssten git config --global core.whitespace blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol.
Zitrax
2
Für mein Projekt (es wurde auf Windows - Kasse und ich sehe es auf Linux), cr-at-eollosgeworden ^Min am Ende der Linien git diffalles in Ordnung, aber GIT noch diese Zeilen als andere zeigte, obwohl die Linie Ende der einzige Unterschied war.
Jānis Elmeris
SourceInsight drückt weiter auf das Zeichen ^ M, und git zeigt immer noch den Unterschied an den Zeilenenden an. @ Zitrax Befehl ist die richtige Antwort auf meinen Fall, Git Diff zeigen schöne und saubere Ausgabe.
Lê Quang Duy
3
Ich denke, Git braucht etwas mehr Komplexität, ein paar widersprüchlichere Einstellungen für das Zeilenende. Ich denke, Git sollte sich mehr Sorgen um meine Leerzeichen machen. Geben Sie beispielsweise einen schwerwiegenden Fehler aus und lassen Sie das Repository in einem beschädigten Zustand, wenn auf einem Windows-Computer (aber nicht unter Linux) Mac-Zeilenenden auftreten. Ich meine, warum sollte ich ein VCS verwenden, das sich um das Geschäft kümmert, und mich die gewünschten Zeilenenden verwenden lassen? Ich sehe, dass sie es versuchen, aber sie sollten ein halbes Dutzend weitere Verhaltensweisen am Zeilenende einbringen, um ein Problem zu lösen, das es nicht gibt. Sie sind fast da! Mach weiter.
Rolf
125

Versuchen Sie git diff --ignore-space-at-eol, oder git diff --ignore-space-change, oder git diff --ignore-all-space.

Jakub Narębski
quelle
22
Nichts davon wirkt sich wirklich auf das Zeichen aus, das die neue Zeile identifiziert.
nes1983
4
Ich habe es auch mit "-w" versucht, aber kein Glück, behandelt es immer noch als eine einzelne Zeile. Nächstes Projekt Ich muss daran denken, niemals CR in den Quellcode zu bekommen.
Neoneye
3
Denken Sie daran, git config --global core.autocrlf true, oder nerven Sie die Git-Leute, bis sie es als Standard
festlegen
10
Dies löste mein Problem, ohne dass ich meine autocrlfEinstellungen ändern musste . Vielen Dank!
Nneonneo
11
Diese Flaggen haben keine Wirkung für mich ... zeigt immer noch ^ M als Unterschiede
Magnus
103

Siehe auch:

core.whitespace = cr-at-eol

oder äquivalent,

[core]
    whitespace = cr-at-eol

wo whitespacesteht ein Tabulatorzeichen .

Vladimir Panteleev
quelle
4
Ja, das hat dazu geführt, dass das Git Diff Tool (das auch in verwendet wird git show) mich nicht mehr wegen des ^Ms in den geänderten Zeilen nervt ! :)
Rijk
2
Aus irgendeinem Grund hat das bei mir nicht funktioniert. Versuchte es sowohl mit = als auch ohne = Zeichen. git diffzeigt immer noch ^ M Zeichen.
Dennis
6
Zwei Möglichkeiten, dies zu tun: Erstens, fügen Sie die obige Zeile wörtlich zu Ihrer .gitconfig hinzu, entweder in .git / config oder in ~ / .gitconfig; zwei, git config --global core.whitespace cr-at-eol(wo --global optional ist, wenn Sie es nur auf dem Repo wollen, auf dem Sie sind)
K. Carpenter
Dies funktionierte für mich unter Windows 7, obwohl ich es nur unter gestellt habe, [core]damit ich das core.Präfix durch ein TAB-Zeichen ersetzen kann .
Rufflewind
Diese Frage war oben , wie man versteckt ^Min git diff, nicht darum , wie in ^ M in erster Linie nicht setzen. Das bedeutet, dass die akzeptierte Antwort auf Änderungen core.autocrlfnicht die beste ist, da sie die Dateien ohne Bestätigung des Benutzers stillschweigend ändert.
Deddebme
45

Warum bekommst du diese ^Min deine git diff?

In meinem Fall habe ich an einem Projekt gearbeitet, das unter Windows entwickelt wurde, und ich habe OS X verwendet. Als ich Code geändert habe, habe ich ^Mam Ende der Zeilen gesehen, die ich hinzugefügt habe git diff. Ich denke, die ^Mwurden angezeigt, weil sie andere Zeilenenden waren als der Rest der Datei. Da der Rest der Datei unter Windows entwickelt wurde, wurden CRZeilenenden und unter OS X LFZeilenenden verwendet .

Anscheinend hat der Windows-Entwickler bei der Installation von Git die Option " Windows-Stil auschecken, Zeilenenden im Unix-Stil festschreiben " nicht verwendet .

Was sollen wir also dagegen tun?

Sie können die Windows-Benutzer dazu bringen, git neu zu installieren und die Option " Windows-Stil auschecken, Zeilenenden im Unix-Stil festschreiben " zu verwenden. Dies ist, was ich bevorzugen würde, da ich Windows als Ausnahme in seinen Zeilenendezeichen sehe und Windows sein eigenes Problem auf diese Weise behebt.

Wenn Sie sich für diese Option entscheiden, sollten Sie jedoch die aktuellen Dateien korrigieren (da sie immer noch die CRZeilenenden verwenden). Ich habe dies getan, indem ich die folgenden Schritte ausgeführt habe:

  1. Entfernen Sie alle Dateien aus dem Repository, jedoch nicht aus Ihrem Dateisystem.

    git rm --cached -r .
    
  2. Fügen Sie eine .gitattributesDatei hinzu, die bestimmte Dateien dazu zwingt, a LFals Zeilenenden zu verwenden. Fügen Sie dies in die Datei ein:

    *.ext text eol=crlf
    

    Ersetzen Sie .extdurch die Dateierweiterungen, die Sie abgleichen möchten.

  3. Fügen Sie alle Dateien erneut hinzu.

    git add .
    

    Dies zeigt Nachrichten wie folgt an:

    warning: CRLF will be replaced by LF in <filename>.
    The file will have its original line endings in your working directory.
    
  4. Sie können die .gitattributesDatei entfernen , es sei denn, Sie haben hartnäckige Windows-Benutzer, die die Option " Windows-Stil auschecken, Zeilenenden im Unix-Stil festschreiben " nicht verwenden möchten .

  5. Alles festschreiben und vorantreiben.

  6. Entfernen und überprüfen Sie die entsprechenden Dateien auf allen Systemen, auf denen sie verwendet werden. Stellen Sie auf den Windows-Systemen sicher, dass sie jetzt die Option " Windows-Stil auschecken, Zeilenenden im Unix-Stil festschreiben " verwenden. Sie sollten dies auch auf dem System tun, auf dem Sie diese Aufgaben ausgeführt haben, da beim Hinzufügen der Dateien git sagte:

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

    Sie können Folgendes tun, um die Dateien zu entfernen:

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

    Und dann, um sie mit den richtigen Zeilenenden zurückzubekommen:

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

    Natürlich durch .extdie gewünschte Erweiterung ersetzen .

Jetzt verwendet Ihr Projekt nur noch LFZeichen für die Zeilenenden, und die bösen CRZeichen werden niemals wiederkommen :).

Die andere Option besteht darin, Zeilenenden im Windows-Stil zu erzwingen. Sie können die .gitattributesDatei auch dafür verwenden.

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

Gitaarik
quelle
4
Um alle Zeilenenden in einer bestimmten Datei zu korrigieren, können Sie bei Verwendung von Sublime Text zu View-> gehen Line Endingsund auf klicken Unix.
Topher Hunt
Was genau ^Mbedeutet das? Ist es eine Windows- oder Linux-Newline? Oder ist es nur eine "andere" Newline als die anderen Newlines in der Datei?
Buhtz
Gut, ich denke, es ist nur eine "andere" Newline (anders als die meisten anderen)
Gitaarik
-1 als Neuinstallation von Git zu erreichen git config --global core.autocrlf trueist übertrieben, und die Anti-Windows / Anti- CRKampagne scheint tangential zu der Frage.
RJFalconer
41

Gibt es eine Option wie "^ M als Newline behandeln, wenn Sie sich unterscheiden"?

Es wird einen mit Git 2.16 (Q1 2018) geben, da die diffBefehlsfamilie gelernt hat, Unterschiede im Wagenrücklauf am Zeilenende zu ignorieren.

Siehe Commit e9282f0 (26. Oktober 2017) von Junio ​​C Hamano ( gitster) .
Mit freundlicher Unterstützung von Johannes Schindelin ( dscho) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 10f65c2 , 27. November 2017)

diff: --ignore-cr-at-eol

Eine neue Option --ignore-cr-at-eolweist die Diff-Maschinerie an, einen Wagenrücklauf am Ende einer (vollständigen) Zeile so zu behandeln, als ob er nicht vorhanden wäre.

Genau wie bei anderen " --ignore-*" Optionen zum Ignorieren verschiedener Arten von Leerzeichenunterschieden hilft dies dabei, die tatsächlichen Änderungen zu überprüfen, die Sie vorgenommen haben, ohne durch falsche CRLF<->LFKonvertierungen Ihres Editor-Programms abgelenkt zu werden .

VonC
quelle
@kaartic Vielen Dank, dass Sie die Antwort bearbeitet und auf das richtige Commit verwiesen haben!
VonC
3
Während es im Allgemeinen eine gute Praxis ist, git config --global core.autocrlf truewie in der akzeptierten Antwort festzulegen, beantwortet dies die Frage des OP direkter: "Gibt es eine Option wie" ^ M als Newline behandeln, wenn es anders ist "?"
Drkvogel
1
Ab Git 2.20 verbirgt dies nicht ^ M's
user1944491
@ user1944491 Ich habe keine Regression bemerkt, was bedeutet, dass eol ignoriert wird, wenn diese Option in Git 2.26 verwendet wird.
VonC
@VonC Die Verwendung dieses Arguments im Befehl git diff hat nicht funktioniert. Das Festlegen meines core.whitespace-Werts durch git version 2.20.1 (Apple Git-117)das Hinzufügen der Antwort core.pager von Jason Pyeron wurde ebenfalls nicht behoben. YMMV offensichtlich.
user1944491
26

TL; DR

Ändern Sie den core.pagerin "tr -d '\r' | less -REX", nicht den Quellcode

Deshalb

Die gezeigten lästigen ^ M sind ein Artefakt der Kolorierung und des Pagers. Geben Sie hier die Bildbeschreibung ein Dies wird durch less -Reine Standard-Git-Pager-Option verursacht. (Der Standard-Pager von git ist less -REX)

Das erste, was zu beachten ist, ist, dass git diff -bkeine Änderungen im Leerraum angezeigt werden (z. B. \ r \ n vs \ n).

installieren:

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

Ein schneller Test zum Erstellen einer Unix-Datei und zum Ändern der Zeilenenden zeigt keine Änderungen mit 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

Wir stellen fest, dass das Erzwingen einer Pipe auf weniger nicht das ^ M anzeigt, sondern die Farbe aktiviert und less -RFolgendes bewirkt:

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

Die Korrektur wird mithilfe einer Pipe angezeigt, um das \ r (^ M) von der Ausgabe zu entfernen:

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

Eine unkluge Alternative ist die Verwendung less -r, da alle Steuercodes und nicht nur die Farbcodes durchlaufen werden.

Wenn Sie nur Ihre Git-Konfigurationsdatei direkt bearbeiten möchten, ist dies der Eintrag zum Aktualisieren / Hinzufügen:

[core]
        pager = tr -d '\\r' | less -REX
Jason Pyeron
quelle
Ich hatte dieses Problem in einem Repo, in dem einige der Dateien \r\nZeilenenden und einige \nZeilenenden hatten (ich weiß nicht, ob das relevant ist). Unterschiede der ersteren zeigten die ^Min den modifizierten Linien ( dh die +Linien). core.autocrlfwurde auf gesetzt true. Laufen git config core.pager "tr -d '\r' | less -REX"hat die nervigen ^Ms losgeworden . Vielen Dank!
Labreuer
5
Danke dafür. Dies ist die einzige Antwort, wenn Sie in Ihren Repos mit unterschiedlichen Zeilenenden arbeiten müssen - z. B. verwenden Sie Checkout unverändert, Commit as is, absichtlich.
Mike
git diff -bist das, wonach ich gesucht habe, aber ich schätze die gründliche Erklärung.
Martin Burch
Das ist die Antwort! Vielen Dank. Die Flagge -b hat bei mir nicht funktioniert.
Chris
Ja! Von allen Antworten auf diese Frage war das Ändern des [core]Abschnitts der git "config" -Datei durch Hinzufügen pager = tr -d '\\r' | less -REXdie einzige Antwort, die für mich funktioniert hat. Vielen Dank!
Rashiki
13

Ich hatte lange mit diesem Problem zu kämpfen. Die bei weitem einfachste Lösung besteht darin, sich keine Gedanken über die ^ M-Zeichen zu machen und nur ein visuelles Diff-Tool zu verwenden, das sie verarbeiten kann.

Anstatt zu tippen:

git diff <commitHash> <filename>

Versuchen:

git difftool <commitHash> <filename>
Ian Wojtowicz
quelle
1
Vielen Dank! Außerdem habe ich gerade "git difftool" ausgeführt und im Grunde alle geänderten Dateien in einer Schleife verglichen
Bhanuprakash D
2

Wie von VonC festgestellt, ist dies bereits in Git 2.16+ enthalten. Leider unterscheidet sich der Name der Option ( --ignore-cr-at-eol) von dem von GNU diff verwendeten Namen, den ich gewohnt bin ( --strip-trailing-cr).

Als ich mit diesem Problem konfrontiert wurde, bestand meine Lösung darin, GNU diff anstelle des integrierten Git-Diff aufzurufen, da mein Git älter als 2.16 ist. Ich habe das mit dieser Kommandozeile gemacht:

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

Dies ermöglicht die Verwendung --strip-trailing-crund anderer GNU-Diff-Optionen.

Es gibt auch diesen anderen Weg:

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

Die konfigurierten Pager-Einstellungen werden jedoch nicht verwendet, weshalb ich die ersteren bevorzuge.

Pedro Gimeno
quelle
Interessante Alternative zu meiner Antwort. Upvoted.
VonC