Posso far riconoscere a git un file UTF-16 come testo?


140

Sto monitorando un file di macchina virtuale Virtual PC (* .vmc) in git, e dopo aver apportato una modifica git ha identificato il file come binario e non lo differirebbe per me. Ho scoperto che il file è stato codificato in UTF-16.

Git può essere insegnato a riconoscere che questo file è di testo e gestirlo in modo appropriato?

Sto usando git sotto Cygwin, con core.autocrlf impostato su false. Potrei usare mSysGit o git sotto UNIX, se necessario.

Risposte:


83

Ho lottato con questo problema per un po 'e ho appena scoperto (per me) una soluzione perfetta:

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

git difftoolaccetta gli stessi argomenti di quanto git difffarebbe, ma esegue un programma diff a tua scelta anziché la GNU integrata diff. Quindi scegli un diff compatibile con multibyte (nel mio caso, vimin modalità diff) e usa git difftoolinvece invece di git diff.

Trova "difftool" troppo lungo per essere digitato? Nessun problema:

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

Git rock.


1
Non è una soluzione perfetta (preferirebbe avere un diff unificato a scorrimento), MA è il male minore date le scelte e la mia riluttanza a trovare qualcosa di nuovo da installare. "vimdiff", lo è! (sì, vim ... e git)
Roboprog,

1
Funziona anche per mettere in scena e impegnare solo blocchi di file UTF16?
Ortwin Gentz,

Uso Beyond Compare come strumento diff e merge. Da .gitconfig <pre> <code> [difftool "bc3"] percorso = c: / Programmi (x86) / Beyond Compare 3 / bcomp.exe [mergetool "bc3"] percorso = c: / Programmi (x86) / Beyond Compare 3 / bcomp.exe </code> </pre>
Tom Wilson,

@ Tom Wilson Spiacente, impossibile formattare il blocco di codice inserendo 4 spazi !?
Tom Wilson,

Ho una conoscenza di base di Git e non sono sicuro di come gestisca le modifiche ai file. È sempre come file binario o per il testo (ASCII) c'è un'elaborazione / rilevazione speciale delle modifiche?
i486,

63

Esiste una soluzione molto semplice che funziona immediatamente su Unices.

Ad esempio, con i .stringsfile Apple basta:

  1. Crea un .gitattributesfile nella radice del tuo repository con:

    *.strings diff=localizablestrings
    
  2. Aggiungi quanto segue al tuo ~/.gitconfigfile:

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

Fonte: file Diff .strings in Git (e post precedente del 2010).


L'ho fatto ma Git si rifiuta di inseguirlo. L'errore che ottengo è "file di configurazione 4 non valido in /Users/myusername/.gitconfig". Ho usato "git config --global --edit" per aprire il mio file gitconfig. È interessante notare che se rimuovo le righe aggiunte tutto funziona bene. Qualche indizio?
shshnk,

Ho intenzione di indovinare le virgolette intelligenti se copi / incolli. Ho modificato la risposta per risolverlo.
Lou Franco,

Funziona come un incantesimo, dovrebbe essere la risposta accettata per motivi di semplicità e per una migliore integrazione. Non vedo come "utilizzare un altro strumento" possa essere la risposta a "Posso fare in modo che git riconosca un file UTF-16 come testo?"
itMaxence

@itMaxence Strettamente, iconvè "un altro strumento" esattamente come Vim o Beyond Compare (non fa parte della suite git).
Agi Hammerthief

@AgiHammerthief sicuramente dopo aver letto di nuovo sono d'accordo, non so a cosa stavo pensando. FWIW vimdiffe iconvsono entrambi già presenti su macOS, quindi non devi preoccuparti di chiederli dove trovarli, e fanno il lavoro
Max

39

Hai provato a impostarlo .gitattributesper trattarlo come un file di testo?

per esempio:

*.vmc diff

Maggiori dettagli su http://www.git-scm.com/docs/gitattributes.html .


2
Funziona, ma per correttezza tieni presente che questo imposta due attributi: sete diff...
OK.

2
Questa soluzione è l'unica accettabile per me. Come da commento di @OK, il "set" è irrilevante qui, solo *.vmc diff, *.sql diffecc. È necessario per impostare l'attributo 'diff' per il percorso specificato. (Non riesco a modificare la risposta). 2 avvertenze tuttavia: le differenze sono mostrate con uno spazio tra ogni personaggio e non è possibile "mettere in scena il pezzo" o "scartare il pezzo" per quei file problematici.
Pac0,

30

Per impostazione predefinita, sembra gitche non funzionerà bene con UTF-16; per tale file devi assicurarti che nessuna CRLFelaborazione sia eseguita su di esso, ma vuoi diffe mergelavorare come un normale file di testo (questo ignora se il tuo terminale / editor è in grado di gestire UTF-16).

Ma guardando la .gitattributesmanpage , ecco l'attributo personalizzato che è binary:

[attr]binary -diff -crlf

Quindi mi sembra che potresti definire un attributo personalizzato nel tuo livello superiore .gitattributesper utf16(nota che aggiungo unisci qui per essere sicuro che sia trattato come testo):

[attr]utf16 diff merge -crlf

Da lì si sarebbe in grado di specificare in qualsiasi .gitattributesfile qualcosa come:

*.vmc utf16

Inoltre, dovresti essere ancora in grado di diffcreare un file, anche se gitpensa che sia binario con:

git diff --text

modificare

Questa risposta dice sostanzialmente che la differenza GNU con UTF-16 o anche UTF-8 non funziona molto bene. Se vuoi gitusare uno strumento diverso per vedere le differenze (via --ext-diff), quella risposta suggerisce Guiffy .

Ma ciò di cui probabilmente hai bisogno è solo diffun file UTF-16 che contiene solo caratteri ASCII. Un modo per farlo funzionare è usare --ext-diffil seguente script shell:

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

Nota che la conversione in UTF-8 potrebbe funzionare anche per l'unione, devi solo assicurarti che sia fatto in entrambe le direzioni.

Per quanto riguarda l'output al terminale quando si osserva un diff di un file UTF-16:

Cercare di diffondere in questo modo si traduce in immondizia binaria emessa sullo schermo. Se git sta usando GNU diff, sembrerebbe che GNU diff non sia compatibile con Unicode.

GNU diff non si preoccupa davvero dell'unicode, quindi quando usi diff --text si diffonde e genera il testo. Il problema è che il terminale in uso non è in grado di gestire l'UTF-16 emesso (combinato con i segni diff che sono caratteri ASCII).


Cercare di diffondere in questo modo si traduce in immondizia binaria emessa sullo schermo. Se git sta usando GNU diff, sembrerebbe che GNU diff non sia compatibile con unicode.
skiphoppy,

1
GNU diff non si preoccupa davvero dell'unicode, quindi quando usi diff --text si diffonde e genera il testo. Il problema è che il terminale in uso non è in grado di gestire l'UTF-16 emesso (combinato con i segni diff che sono caratteri ASCII).
Jared Oberhaus,

@ jared-oberhaus: esiste un modo per attivare questo script solo per determinati tipi di file (ovvero con una determinata estensione)?
Terry,

8

La soluzione è filtrare cmd.exe /c "type %1". Il typecomando incorporato di cmd eseguirà la conversione, quindi puoi usarlo con l'abilità textconv di git diff per abilitare la difformazione del testo dei file UTF-16 (dovrebbe funzionare anche con UTF-8, anche se non testato).

Citando dalla pagina man di gitattributes:


Esecuzione di diff di testo di file binari

A volte è desiderabile vedere il diff di una versione convertita in testo di alcuni file binari. Ad esempio, un documento di elaboratore di testi può essere convertito in una rappresentazione di testo ASCII e il diff del testo mostrato. Anche se questa conversione perde alcune informazioni, la diff risultante è utile per la visualizzazione umana (ma non può essere applicata direttamente).

L'opzione di configurazione textconv viene utilizzata per definire un programma per eseguire tale conversione. Il programma dovrebbe prendere un singolo argomento, il nome di un file da convertire, e produrre il testo risultante su stdout.

Ad esempio, per mostrare la diff delle informazioni exif di un file invece delle informazioni binarie (supponendo che tu abbia lo strumento exif installato), aggiungi la seguente sezione al tuo $GIT_DIR/configfile (o $HOME/.gitconfigfile):

[diff "jpg"]
        textconv = exif

Una soluzione per mingw32 , i fan di cygwin potrebbero dover modificare l'approccio. Il problema è passare il nome del file per convertirlo in cmd.exe: utilizzerà le barre in avanti e cmd presuppone i separatori di directory barra rovesciata.

Passo 1:

Crea lo script a argomento singolo che eseguirà la conversione in stdout. c: \ percorso \ to \ qualche \ script.sh:

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

Passo 2:

Configurare git per poter usare il file di script. All'interno della tua configurazione git ( ~/.gitconfigo .git/configo vedi man git-config), inserisci questo:

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

Passaggio 3:

Indica i file a cui applicare questa soluzione utilizzando i file .gitattributes (vedi man gitattributes (5)):

*vmc diff=cmdtype

quindi utilizzare git diffsui tuoi file.


Quasi come Tony Kuneck ma senza "c: /path/to/some/script.sh" entropy.ch/blog/Developer/2010/04/15/…
Alexey

Ho qualche problema con lo script come indicato sopra con Git per Windows, ma ho trovato il seguente è fine e anche in grado di trattare con spazi nel percorso: cmd //c type "${1//\//\\}" .
patthoyts,

Funzionerà senza la necessità di creare un file di script:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Jakub Berezanski,

5

git di recente ha iniziato a comprendere codifiche come utf16. Vedi documenti gitattributes , cercaworking-tree-encoding

[Assicurati che la tua pagina man corrisponda poiché è abbastanza nuova!]

Se (diciamo) il file è UTF-16 senza DBA sul computer Windows, aggiungere al .gitattributesfile

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

Se UTF-16 (con bom) su * nix, fallo:

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

(Sostituisci *.vmccon *.whateverper i whateverfile di tipo che devi gestire)

Vedere: Supporto della codifica working-tree "UTF-16LE-BOM" .


Aggiunto dopo

Dopo @Hackslash, è possibile che ciò sia insufficiente

 *.vmc text working-tree... 

Per ottenere buone differenze di testo è necessario

 *.vmc diff working-tree...

Mettere anche entrambe le opere

 *.vmc text diff working-tree... 

Ma è discutibile

  • Ridondante: eol=...implicatext
  • Verbose - un grande progetto potrebbe facilmente avere dozzine di diversi tipi di file di testo

Il problema

Git ha un attributo macro binary che significa -text -diff. Non +text +diffè disponibile il contrario, ma git fornisce gli strumenti (penso!) Per sintetizzarlo

La soluzione

Git consente di definire nuovi attributi macro.

Proporrei quella parte superiore del .gitattributesfile che hai

 [attr]textfile text diff

Quindi per tutti i percorsi che devono essere testo e diff

 path textfile working-tree-encoding= eol=...

Si noti che nella maggior parte dei casi vorremmo che la codifica predefinita (utf-8) e quella predefinita (nativo) venissero eliminate.

La maggior parte delle linee dovrebbe apparire come

textfile *.c
textfile *.py
Etc

Perché non usare semplicemente diff?

Pratico: nella maggior parte dei casi vogliamo eol nativo. Il che significa no eol=.... Quindi textnon verrà sottinteso e dovrà essere esplicitamente inserito.

Concettuale: il testo Vs binario è la distinzione fondamentale. eol, encoding, diff etc ne sono solo alcuni aspetti.

disconoscimento

A causa dei tempi bizzarri in cui viviamo, non ho una macchina con un sistema funzionante. Quindi al momento non riesco a controllare l'ultima aggiunta. Se qualcuno trova qualcosa di sbagliato, emetterò / rimuoverò.


Per far funzionare il mio file UTF-16LE-BOM ho dovuto usare*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash: grazie per l'heads-up. Immagino che stai dicendo da textsolo che non hai trovato differenze di testo interessanti? Potete per favore verificarlo con entrambi text e difftutto funziona bene? Nel qual caso farò una diversa raccomandazione
Rusi il

textRisultati corretti e soli nel confronto binario. Posso fare diffo text diffe funziona. Ho dovuto aggiungere -BOMsemplicemente perché il mio file aveva una DBA, YMMV.
HackSlash,

@HackSlash ho incorporato i tuoi risultati. Sarebbe bello se potessi dare un'occhiata!
Rusi,

Grazie @Rusi, ha senso per me.
HackSlash,

4

Ho scritto un piccolo driver git-diff to-utf8, che dovrebbe semplificare la diffusione di qualsiasi file codificato non ASCII / UTF-8. È possibile installarlo utilizzando le istruzioni qui: https://github.com/chaitanyagupta/gitutils#to-utf8 (lo to-utf8script è disponibile nello stesso repository).

Si noti che questo script richiede sia filee iconvcomandi per essere disponibile sul sistema.


2

Recentemente ho riscontrato questo problema su Windows e i contenitori dos2unixe unix2dosforniti con git per Windows hanno funzionato. Di default si trovano in C:\Program Files\Git\usr\bin\. Osserva che funzionerà solo se il tuo file non deve essere UTF-16. Ad esempio, qualcuno ha codificato accidentalmente un file Python come UTF-16 quando non era necessario (nel mio caso).

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

e

PS C:\Users\xxx> unix2dos my_file.py
unix2dos: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 DOS format...
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.