Kann ich Git dazu bringen, eine UTF-16-Datei als Text zu erkennen?

140

Ich verfolge eine virtuelle PC-Maschinendatei (* .vmc) in git und nach einer Änderung identifizierte git die Datei als binär und würde sie für mich nicht unterscheiden. Ich habe festgestellt, dass die Datei in UTF-16 codiert wurde.

Kann man Git beibringen, zu erkennen, dass es sich bei dieser Datei um Text handelt, und sie angemessen zu behandeln?

Ich verwende git unter Cygwin, wobei core.autocrlf auf false gesetzt ist. Bei Bedarf kann ich mSysGit oder git unter UNIX verwenden.

Skiphoppy
quelle

Antworten:

83

Ich habe eine Weile mit diesem Problem zu kämpfen und gerade (für mich) eine perfekte Lösung gefunden:

$ git config --global diff.tool vimdiff      # or merge.tool to get merging too!
$ git difftool commit1 commit2

git difftoolverwendet die gleichen Argumente wie git diffwürde, führt jedoch anstelle der integrierten GNU ein Diff-Programm Ihrer Wahl aus diff. Wählen Sie also ein Multibyte-fähiges Diff (in meinem Fall vimim Diff-Modus) und verwenden Sie es git difftoolstattdessen anstelle von git diff.

Finden Sie "difftool" zu lang zum Tippen? Kein Problem:

$ git config --global alias.dt difftool
$ git dt commit1 commit2

Git rockt.

Sam Stokes
quelle
1
Keine perfekte Lösung (hätte lieber ein einheitliches Scrolling-Diff), ABER es ist das geringere Übel angesichts der Auswahl und meiner Unwilligkeit, etwas Neues für die Installation zu finden. "vimdiff" ist es! (Ja, vim ... und git)
Roboprog
1
Funktioniert dies auch, um nur Teile von UTF16-Dateien bereitzustellen und festzuschreiben?
Ortwin Gentz
Ich verwende Beyond Compare als Diff- und Merge-Tool. Von .gitconfig <pre> <code> [difftool "bc3"] path = c: / Programme (x86) / Beyond Compare 3 / bcomp.exe [mergetool "bc3"] path = c: / Programme (x86) / Beyond Compare 3 / bcomp.exe </ code> </ pre>
Tom Wilson
@ Tom Wilson Leider kann der Codeblock nicht durch Einrücken von 4 Leerzeichen formatiert werden!?
Tom Wilson
Ich habe Grundkenntnisse für Git und bin mir nicht sicher, wie es mit Dateiänderungen umgeht. Ist dies immer eine Binärdatei oder gibt es für Text (ASCII) eine spezielle Verarbeitung / Erkennung von Änderungen?
i486
63

Es gibt eine sehr einfache Lösung, die bei Unices sofort funktioniert.

Zum Beispiel mit Apples .stringsDateien nur:

  1. Erstellen Sie eine .gitattributesDatei im Stammverzeichnis Ihres Repositorys mit:

    *.strings diff=localizablestrings
    
  2. Fügen Sie Ihrer ~/.gitconfigDatei Folgendes hinzu :

    [diff "localizablestrings"]
    textconv = "iconv -f utf-16 -t utf-8"
    

Quelle: Diff .strings-Dateien in Git (und älterer Beitrag von 2010).

IlDan
quelle
Ich habe das getan, aber Git weigert sich, danach zu rennen. Der Fehler, den ich erhalte, ist "fehlerhafte Konfigurationsdatei Zeile 4 in /Users/myusername/.gitconfig". Ich habe "git config --global --edit" verwendet, um meine gitconfig-Datei zu öffnen. Interessanterweise funktioniert alles einwandfrei, wenn ich die hinzugefügten Zeilen entferne. Irgendwelche Hinweise ?
Shshnk
Ich werde die intelligenten Anführungszeichen erraten, wenn Sie kopieren / einfügen. Ich habe die Antwort bearbeitet, um das zu beheben.
Lou Franco
Dies funktioniert wie ein Zauber, es sollte der Einfachheit halber und für eine bessere Integration die akzeptierte Antwort sein. Ich verstehe nicht, wie "ein anderes Tool verwenden" die Antwort auf "Kann ich Git dazu bringen, eine UTF-16-Datei als Text zu erkennen?" Sein kann.
itMaxence
@itMaxence Streng genommen iconvist "ein anderes Tool" genauso wie Vim oder Beyond Compare (nicht Teil der Git-Suite).
Agi Hammerthief
@AgiHammerthief sicher, nachdem ich wieder gelesen habe, stimme ich zu, weiß nicht, woran ich dachte. FWIW vimdiffund iconvbeide sind bereits auf macOS vorhanden, sodass Sie sich nicht fragen müssen, wo sie erhältlich sind, und sie erledigen den Job
itMaxence
39

Haben Sie versucht, Ihre .gitattributesso einzustellen, dass sie als Textdatei behandelt wird?

z.B:

*.vmc diff

Weitere Informationen finden Sie unter http://www.git-scm.com/docs/gitattributes.html .

Chealion
quelle
2
Dies funktioniert, aber für die Richtigkeit beachten Sie bitte, dass dies zwei Attribute festlegt : setund diff...
OK.
2
Diese Lösung ist für mich nur akzeptabel. Wie pro @OK Kommentar ist der „Satz“ hier irrelevant, nur *.vmc diff, *.sql diffetc .. benötigt wird , um das ‚diff‘ Attribut für den Pfad angegeben einzustellen. (Ich kann die Antwort nicht bearbeiten). 2 Vorbehalte: Unterschiede werden mit einem Leerzeichen zwischen den einzelnen Zeichen angezeigt und es ist nicht möglich, für diese problematischen Dateien "Stage Hunk" oder "Discard Hunk" zu erstellen.
Pac0
30

Standardmäßig scheint es gitmit UTF-16 nicht gut zu funktionieren. Für eine solche Datei müssen Sie sicherstellen, dass keine CRLFVerarbeitung durchgeführt wird, aber Sie möchten diffund mergewie eine normale Textdatei arbeiten (dies ignoriert, ob Ihr Terminal / Editor UTF-16 verarbeiten kann oder nicht).

.gitattributesWenn Sie sich jedoch die Manpage ansehen , sehen Sie hier das benutzerdefinierte Attribut binary:

[attr]binary -diff -crlf

Daher scheint es mir, dass Sie ein benutzerdefiniertes Attribut in Ihrer obersten Ebene .gitattributesfür definieren können utf16(beachten Sie, dass ich hier Zusammenführung hinzufüge, um sicherzustellen, dass es als Text behandelt wird):

[attr]utf16 diff merge -crlf

Von dort aus können Sie in jeder .gitattributesDatei Folgendes angeben :

*.vmc utf16

Beachten Sie auch, dass Sie weiterhin in der Lage sein sollten, diffeine Datei zu erstellen, auch wenn gitSie der Meinung sind , dass sie binär ist mit:

git diff --text

Bearbeiten

Diese Antwort besagt im Grunde, dass GNU diff mit UTF-16 oder sogar UTF-8 nicht sehr gut funktioniert. Wenn Sie gitein anderes Tool verwenden möchten, um Unterschiede (über --ext-diff) zu erkennen, schlägt diese Antwort Guiffy vor .

Was Sie aber wahrscheinlich brauchen, ist nur diffeine UTF-16-Datei, die nur ASCII-Zeichen enthält. Eine Möglichkeit, dies zum Laufen zu bringen, ist die Verwendung --ext-diffdes folgenden Shell-Skripts:

#!/bin/bash
diff <(iconv -f utf-16 -t utf-8 "$1") <(iconv -f utf-16 -t utf-8 "$2")

Beachten Sie, dass die Konvertierung in UTF-8 möglicherweise auch zum Zusammenführen funktioniert. Sie müssen lediglich sicherstellen, dass die Konvertierung in beide Richtungen erfolgt.

Wie für die Ausgabe an das Terminal, wenn ein Diff einer UTF-16-Datei betrachtet wird:

Der Versuch, sich so zu unterscheiden, führt dazu, dass binärer Müll auf den Bildschirm gespuckt wird. Wenn git GNU diff verwendet, scheint es, dass GNU diff nicht Unicode-fähig ist.

GNU diff kümmert sich nicht wirklich um Unicode. Wenn Sie also diff --text verwenden, unterscheidet es sich nur und gibt den Text aus. Das Problem ist, dass das von Ihnen verwendete Terminal das ausgegebene UTF-16 nicht verarbeiten kann (kombiniert mit den Diff-Markierungen, die ASCII-Zeichen sind).

Jared Oberhaus
quelle
Der Versuch, sich so zu unterscheiden, führt dazu, dass binärer Müll auf den Bildschirm gespuckt wird. Wenn git GNU diff verwendet, scheint es, dass GNU diff nicht Unicode-fähig ist.
Skiphoppy
1
GNU diff kümmert sich nicht wirklich um Unicode. Wenn Sie also diff - text verwenden, unterscheidet es sich nur und gibt den Text aus. Das Problem ist, dass das von Ihnen verwendete Terminal das ausgegebene UTF-16 nicht verarbeiten kann (kombiniert mit den Diff-Markierungen, die ASCII-Zeichen sind).
Jared Oberhaus
@ jared-oberhaus - gibt es eine Möglichkeit, dieses Skript nur für bestimmte Dateitypen auszulösen (dh mit einer bestimmten Erweiterung)?
Terry
8

Die Lösung besteht darin, durch zu filtern cmd.exe /c "type %1". Die typeintegrierte Konvertierung von cmd führt die Konvertierung durch. Daher können Sie diese mit der Textkonv-Funktion von git diff verwenden, um die Textdifferenzierung von UTF-16-Dateien zu aktivieren (sollte auch mit UTF-8 funktionieren, obwohl nicht getestet).

Zitat aus der Manpage von gitattributes:


Durchführen von Textunterschieden von Binärdateien

Manchmal ist es wünschenswert, den Unterschied einer textkonvertierten Version einiger Binärdateien zu sehen. Beispielsweise kann ein Textverarbeitungsdokument in eine ASCII-Textdarstellung konvertiert und der Unterschied des Textes angezeigt werden. Obwohl diese Konvertierung einige Informationen verliert, ist das resultierende Diff für die menschliche Betrachtung nützlich (kann jedoch nicht direkt angewendet werden).

Mit der Option textconv config wird ein Programm zum Durchführen einer solchen Konvertierung definiert. Das Programm sollte ein einzelnes Argument verwenden, den Namen einer zu konvertierenden Datei, und den resultierenden Text auf stdout erzeugen.

Fügen Sie Ihrer $GIT_DIR/configDatei (oder $HOME/.gitconfigDatei) den folgenden Abschnitt hinzu, um beispielsweise den Unterschied der Exif-Informationen einer Datei anstelle der Binärinformationen anzuzeigen (vorausgesetzt, Sie haben das Exif-Tool installiert ):

[diff "jpg"]
        textconv = exif

Als Lösung für mingw32 müssen Cygwin-Fans möglicherweise den Ansatz ändern. Das Problem besteht darin, den Dateinamen für die Konvertierung in cmd.exe zu übergeben. Dabei werden Schrägstriche verwendet, und cmd geht von Backslash-Verzeichnis-Trennzeichen aus.

Schritt 1:

Erstellen Sie das Skript mit einem Argument, das die Konvertierung in stdout durchführt. c: \ path \ to \ some \ script.sh:

#!/bin/bash
SED='s/\//\\\\\\\\/g'
FILE=\`echo $1 | sed -e "$SED"\`
cmd.exe /c "type $FILE"

Schritt 2:

Richten Sie git so ein, dass die Skriptdatei verwendet werden kann. Fügen Sie in Ihre Git-Konfiguration ( ~/.gitconfigoder .git/configoder siehe man git-config) Folgendes ein:

[diff "cmdtype"]
textconv = c:/path/to/some/script.sh

Schritt 3:

Weisen Sie auf Dateien hin, auf die diese Problemumgehung angewendet werden soll, indem Sie .gitattributes-Dateien verwenden (siehe man gitattributes (5)):

*vmc diff=cmdtype

Verwenden git diffSie dann für Ihre Dateien.

Gilles 'SO - hör auf böse zu sein'
quelle
Fast wie Tony Kunecks, aber ohne "c: /path/to/some/script.sh" entropy.ch/blog/Developer/2010/04/15/…
Alexey Shumkin
Ich habe ein Problem mit dem oben gezeigten Skript mit Git für Windows, aber ich fand, dass Folgendes in Ordnung ist und auch mit Leerzeichen im Pfad umgehen kann : cmd //c type "${1//\//\\}" .
Patthoyts
Dies wird funktionieren, ohne dass eine Skriptdatei erstellt werden muss:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Jakub Berezanski
5

Git hat vor kurzem begonnen, Codierungen wie utf16 zu verstehen. Siehe gitattributes docs, suchen nachworking-tree-encoding

[Stellen Sie sicher, dass Ihre Manpage übereinstimmt, da dies ziemlich neu ist!]

Wenn (sagen wir) die Datei UTF-16 ohne Stückliste auf einem Windows-Computer ist, fügen Sie sie Ihrer .gitattributesDatei hinzu

*.vmc text working-tree-encoding=UTF-16LE eol=CRLF

Wenn UTF-16 (mit bom) auf * nix es macht:

*.vmc text working-tree-encoding=UTF-16 eol=LF

(Ersetzen Sie *.vmcdurch *.whateverfür whateverTypdateien, die Sie verarbeiten müssen)

Siehe: Unterstützung der Arbeitsbaumcodierung "UTF-16LE-BOM" .

Rusi
quelle
Um meine UTF-16LE-BOM-Datei zum *.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
Laufen
@ HackSlash: Danke für das Heads-up. Ich denke du sagst textalleine, du hast keine schönen Textunterschiede bekommen? Können Sie das bitte mit beiden überprüfen textund diffalles funktioniert gut? In diesem Fall werde ich eine andere Empfehlung
aussprechen
Richtig, textallein führt zu einem binären Vergleich. Ich kann diffoder text diffund es funktioniert. Ich musste -BOMeinfach hinzufügen , weil meine Datei eine Stückliste, YMMV, hatte.
HackSlash vor
4

Ich habe einen kleinen Git-Diff-Treiber geschrieben, to-utf8der es einfach machen soll, nicht ASCII / UTF-8-codierte Dateien zu unterscheiden. Sie können es mithilfe der folgenden Anweisungen installieren: https://github.com/chaitanyagupta/gitutils#to-utf8 (theto-utf8 Skript ist im selben Repo verfügbar).

Beachten Sie, dass für dieses Skript sowohl fileals auch iconvBefehle auf dem System verfügbar sein müssen.

Chaitanya Gupta
quelle
2

Hatte dieses Problem kürzlich unter Windows und die dos2unixund unix2dosBins, die mit Git für Windows geliefert werden, haben den Trick gemacht. Standardmäßig befinden sie sich in C:\Program Files\Git\usr\bin\. Beachten Sie, dass dies nur funktioniert, wenn Ihre Datei nicht UTF-16 sein muss. Zum Beispiel hat jemand versehentlich eine Python-Datei als UTF-16 codiert, wenn dies nicht erforderlich war (in meinem Fall).

PS C:\Users\xxx> dos2unix my_file.py
dos2unix: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 Unix format...

und

PS C:\Users\xxx> unix2dos my_file.py
unix2dos: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 DOS format...
Matt Messersmith
quelle