Bisakah saya membuat git mengenali file UTF-16 sebagai teks?


140

Saya melacak file mesin virtual PC Virtual (* .vmc) di git, dan setelah melakukan perubahan git mengidentifikasi file tersebut sebagai biner dan tidak akan membedakannya untuk saya. Saya menemukan bahwa file itu dikodekan dalam UTF-16.

Bisakah git diajarkan untuk mengenali bahwa file ini adalah teks dan menanganinya dengan tepat?

Saya menggunakan git di bawah Cygwin, dengan core.autocrlf disetel ke false. Saya bisa menggunakan mSysGit atau git di bawah UNIX, jika perlu.

Jawaban:


83

Saya telah berjuang dengan masalah ini untuk sementara waktu, dan baru saja menemukan (untuk saya) solusi yang sempurna:

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

git difftoolmengambil argumen yang sama seperti git diffakan, tetapi menjalankan program berbeda dari pilihan Anda alih-alih GNU bawaan diff. Jadi pilih diff multibyte-aware (dalam kasus saya, vimdalam mode diff) dan gunakan git difftoolsaja git diff.

Cari "difftool" terlalu panjang untuk diketik? Tidak masalah:

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

Batu git.


1
Bukan solusi yang sempurna (lebih suka memiliki scrolling unified diff), TETAPI, itu adalah kejahatan yang kurang diberikan pilihan dan keengganan saya untuk menemukan sesuatu yang baru untuk diinstal. "vimdiff", benar! (ya, vim ... dan git)
Roboprog

1
Apakah ini juga berfungsi untuk melakukan stage dan hanya melakukan potongan file UTF16?
Ortwin Gentz

Saya menggunakan Beyond Compare sebagai alat diff dan merge. Dari .gitconfig <pre> <code> [difftool "bc3"] path = c: / Program Files (x86) / Melampaui Pembandingan 3 / bcomp.exe [mergetool "bc3"] path = c: / Program Files (x86) / Melampaui Bandingkan 3 / bcomp.exe </code> </pre>
Tom Wilson

@ Tom Wilson Maaf tidak dapat memformat blok kode dengan memasukkan 4 spasi !?
Tom Wilson

Saya memiliki pengetahuan dasar untuk git dan tidak yakin bagaimana menangani perubahan file. Apakah ini selalu sebagai file biner atau untuk teks (ASCII) ada pemrosesan / deteksi perubahan khusus?
i486

63

Ada solusi yang sangat sederhana yang berfungsi di luar kotak pada Unices.

Misalnya, dengan .stringsfile Apple, cukup:

  1. Buat .gitattributesfile di root repositori Anda dengan:

    *.strings diff=localizablestrings
    
  2. Tambahkan yang berikut ke ~/.gitconfigfile Anda :

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

Sumber: Diff .strings file dalam Git (dan posting lama dari 2010).


Saya melakukan ini tetapi git menolak untuk menjalankan setelah ini. Kesalahan yang saya dapatkan adalah "file konfigurasi buruk baris 4 di / Pengguna / nama pengguna/.gitconfig". Saya menggunakan "git config --global --edit" untuk membuka file gitconfig saya. Menariknya jika saya menghapus baris yang ditambahkan semuanya berfungsi dengan baik. Ada petunjuk?
shshnk

Saya akan menebak kutipan pintar jika Anda menyalin / menempel. Saya mengedit jawaban untuk memperbaikinya.
Lou Franco

Ini berfungsi seperti pesona, itu harus menjadi jawaban yang diterima demi kesederhanaan dan untuk integrasi yang lebih baik. Saya tidak melihat bagaimana "menggunakan alat lain" bisa menjadi jawaban untuk "Bisakah saya membuat git mengenali file UTF-16 sebagai teks?"
itMaxence

@itMaxence Strictly, iconvadalah "alat lain" dengan cara yang sama seperti Vim atau Beyond Compare (bukan bagian dari git suite).
Agi Hammerthief

@AgiHammerthief yakin setelah membaca lagi saya setuju, tidak tahu apa yang saya pikirkan. FWIW vimdiffdan iconvkeduanya sudah ada di macOS sehingga Anda tidak perlu repot bertanya-tanya di mana mendapatkannya, dan mereka melakukan pekerjaan
itMaxence

39

Sudahkah Anda mencoba mengatur Anda .gitattributesuntuk memperlakukannya sebagai file teks?

misalnya:

*.vmc diff

Detail lebih lanjut di http://www.git-scm.com/docs/gitattributes.html .


2
Ini berfungsi, tetapi untuk kebenaran harap diperhatikan bahwa ini menetapkan dua atribut: setdan diff...
OK.

2
Solusi ini adalah satu-satunya yang dapat diterima bagi saya. Sesuai komentar @OK, "set" tidak relevan di sini, hanya *.vmc diff, *.sql diffdll. Diperlukan untuk mengatur atribut 'diff' untuk path yang ditentukan. (Saya tidak dapat mengedit jawabannya). Namun 2 peringatan: diff ditampilkan dengan spasi di antara masing-masing karakter, dan tidak mungkin untuk "stage hunk" atau "discus hunk" untuk file-file bermasalah.
Pac0

30

Secara default, sepertinya gittidak akan bekerja dengan baik dengan UTF-16; untuk file seperti itu Anda harus memastikan bahwa tidak ada CRLFpemrosesan yang dilakukan padanya, tetapi Anda ingin diffdan mergeberfungsi sebagai file teks biasa (ini mengabaikan apakah terminal / editor Anda dapat menangani UTF-16).

Tetapi melihat .gitattributesmanualnya , berikut adalah atribut khusus yaitu binary:

[attr]binary -diff -crlf

Jadi menurut saya Anda dapat mendefinisikan atribut khusus di tingkat atas Anda .gitattributesuntuk utf16(perhatikan bahwa saya menambahkan gabungan di sini untuk memastikan itu diperlakukan sebagai teks):

[attr]utf16 diff merge -crlf

Dari sana Anda akan dapat menentukan .gitattributessesuatu dalam file apa saja seperti:

*.vmc utf16

Perhatikan juga bahwa Anda masih bisa diffmendapatkan file, meskipun gitdianggap biner dengan:

git diff --text

Edit

Jawaban ini pada dasarnya mengatakan bahwa GNU berbeda dengan UTF-16 atau bahkan UTF-8 tidak bekerja dengan baik. Jika Anda ingin gitmenggunakan alat yang berbeda untuk melihat perbedaan (via --ext-diff), jawaban itu menyarankan Guiffy .

Tapi apa yang Anda butuhkan mungkin hanya untuk difffile UTF-16 yang hanya berisi karakter ASCII. Cara untuk membuatnya berfungsi adalah dengan menggunakan --ext-diffdan skrip shell berikut:

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

Perhatikan bahwa mengonversi ke UTF-8 mungkin bekerja untuk penggabungan juga, Anda hanya perlu memastikan itu dilakukan di kedua arah.

Adapun output ke terminal ketika melihat perbedaan file UTF-16:

Mencoba beda seperti itu menghasilkan sampah biner yang dimuntahkan ke layar. Jika git menggunakan GNU diff, nampaknya GNU diff bukan unicode-aware.

GNU diff tidak terlalu peduli tentang unicode, jadi ketika Anda menggunakan diff --text itu hanya diffs dan menampilkan teks. Masalahnya adalah bahwa terminal yang Anda gunakan tidak dapat menangani UTF-16 yang dipancarkan (dikombinasikan dengan tanda diff yang merupakan karakter ASCII).


Mencoba beda seperti itu menghasilkan sampah biner yang dimuntahkan ke layar. Jika git menggunakan GNU diff, nampaknya GNU diff bukan unicode-aware.
skiphoppy

1
GNU diff tidak terlalu peduli tentang unicode, jadi ketika Anda menggunakan diff --text itu hanya diffs dan menampilkan teks. Masalahnya adalah bahwa terminal yang Anda gunakan tidak dapat menangani UTF-16 yang dipancarkan (dikombinasikan dengan tanda diff yang merupakan karakter ASCII).
Jared Oberhaus

@ jared-oberhaus - adakah cara untuk memicu skrip ini hanya untuk jenis file tertentu (misalnya diberi ekstensi tertentu)?
Terry

8

Solusinya adalah dengan menyaring cmd.exe /c "type %1". cmd's typebuiltin akan melakukan konversi, sehingga Anda dapat menggunakannya dengan kemampuan textconv dari git diff untuk mengaktifkan pembedaan teks dari file UTF-16 (harus bekerja dengan UTF-8 juga, walaupun belum diuji).

Mengutip dari halaman manual gitattributes:


Melakukan perbedaan teks dari file biner

Kadang-kadang diinginkan untuk melihat perbedaan versi teks-dikonversi dari beberapa file biner. Misalnya, dokumen pengolah kata dapat dikonversi ke representasi teks ASCII, dan perbedaan teks yang ditampilkan. Meskipun konversi ini kehilangan beberapa informasi, perbedaan yang dihasilkan berguna untuk dilihat manusia (tetapi tidak dapat diterapkan secara langsung).

Opsi konfigurasi textconv digunakan untuk menentukan program untuk melakukan konversi tersebut. Program harus mengambil argumen tunggal, nama file yang akan dikonversi, dan menghasilkan teks yang dihasilkan pada stdout.

Misalnya, untuk memperlihatkan perbedaan informasi exif dari file dan bukan dengan informasi biner (dengan asumsi Anda menginstal alat exif), tambahkan bagian berikut ke $GIT_DIR/configfile Anda (atau $HOME/.gitconfigfile):

[diff "jpg"]
        textconv = exif

Sebuah solusi untuk mingw32 , penggemar cygwin mungkin harus mengubah pendekatannya. Masalahnya adalah dengan meneruskan nama file untuk dikonversi ke cmd.exe - itu akan menggunakan garis miring ke depan, dan cmd mengasumsikan pemisah direktori backslash.

Langkah 1:

Buat skrip argumen tunggal yang akan melakukan konversi ke stdout. c: \ path \ to \ some \ script.sh:

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

Langkah 2:

Atur git untuk dapat menggunakan file skrip. Di dalam konfigurasi git Anda ( ~/.gitconfigatau .git/configatau lihat man git-config), menempatkan ini:

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

Langkah 3:

Tunjukkan file untuk menerapkan workarond ini dengan menggunakan file .gitattributes (lihat man gitattributes (5)):

*vmc diff=cmdtype

kemudian gunakan git diffpada file Anda.


Hampir seperti Tony Kuneck tetapi tanpa "c: /path/to/some/script.sh" entropy.ch/blog/Developer/2010/04/15/…
Alexey Shumkin

Saya memiliki beberapa masalah dengan script seperti yang ditunjukkan di atas dengan Git untuk Windows tapi saya menemukan berikut baik-baik saja dan juga dapat menangani ruang di jalan: cmd //c type "${1//\//\\}" .
patthoyts

Ini akan berfungsi tanpa perlu membuat file skrip:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Jakub Berezanski

5

git baru-baru ini mulai memahami pengkodean seperti utf16. Lihat dokumentasi gitattributes , cariworking-tree-encoding

[Pastikan halaman manualmu cocok karena ini cukup baru!]

Jika (katakanlah) file tersebut adalah UTF-16 tanpa BOM pada mesin Windows kemudian tambahkan ke .gitattributesfile Anda

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

Jika UTF-16 (dengan bom) pada * nix membuatnya:

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

(Ganti *.vmcdengan *.whateveruntuk whateverjenis file yang perlu Anda tangani)

Lihat: Mendukung pengkodean pohon-kerja "UTF-16LE-BOM" .


Ditambahkan nanti

Mengikuti @ Hacklash, orang mungkin menemukan bahwa ini tidak cukup

 *.vmc text working-tree... 

Untuk mendapatkan perbedaan teks yang Anda butuhkan

 *.vmc diff working-tree...

Puting keduanya bekerja juga

 *.vmc text diff working-tree... 

Tapi itu bisa dibilang

  • Redundan - eol=...menyiratkantext
  • Verbose - proyek besar dapat dengan mudah memiliki lusinan jenis file teks yang berbeda

Masalah

Git memiliki atribut makro binary yang artinya -text -diff. Sebaliknya +text +difftidak tersedia built-in tetapi git memberikan alat (saya pikir!) Untuk mensintesisnya

Solusinya

Git memungkinkan seseorang untuk mendefinisikan atribut makro baru.

Saya akan mengusulkan bagian atas .gitattributesfile yang Anda miliki

 [attr]textfile text diff

Kemudian untuk semua jalur yang perlu dilakukan adalah teks dan diff

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

Perhatikan bahwa dalam kebanyakan kasus, kita menginginkan penyandian default (utf-8) dan default eol (asli) dan karenanya dapat dihapus.

Sebagian besar garis akan terlihat seperti

textfile *.c
textfile *.py
Etc

Mengapa tidak menggunakan diff saja?

Praktis: Dalam kebanyakan kasus, kami menginginkan asli eol. Yang berarti tidak eol=.... Jadi texttidak akan tersirat dan perlu dimasukkan secara eksplisit.

Konseptual: Teks Vs biner adalah perbedaan mendasar. eol, encoding, diff dll hanyalah beberapa aspeknya.

Penolakan

Karena masa aneh yang kita tinggali, aku tidak punya mesin dengan git yang berfungsi saat ini. Jadi saya saat ini tidak dapat memeriksa penambahan terbaru. Jika seseorang menemukan sesuatu yang salah, saya akan memperbaiki / menghapus.


Untuk mendapatkan file UTF-16LE-BOM saya berfungsi, saya harus menggunakan*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash: Terima kasih atas bantuannya. Saya kira Anda mengatakan dengan textsendirian Anda tidak mendapatkan perbedaan teks yang bagus? Bisakah Anda memeriksanya dengan keduanya text dan diffsemuanya berfungsi dengan baik? Dalam hal ini saya akan membuat rekomendasi yang berbeda
Rusi

Benar, texthasil saja dalam membandingkan biner. Aku bisa melakukannya diffatau text diffdan bekerja. Saya perlu menambahkan -BOMhanya karena file saya punya BOM, YMMV.
HackSlash

@ HackSlash Saya sudah memasukkan temuan Anda. Akan lebih bagus jika Anda bisa memeriksanya!
Rusi

Terima kasih @Rusi, masuk akal bagi saya.
HackSlash

4

Saya telah menulis driver git-diff kecil to-utf8,, yang seharusnya memudahkan untuk melakukan diff file non-ASCII / UTF-8. Anda dapat menginstalnya menggunakan instruksi di sini: https://github.com/chaitanyagupta/gitutils#to-utf8 ( to-utf8skrip tersedia dalam repo yang sama).

Perhatikan bahwa skrip ini membutuhkan keduanya filedan iconvperintah harus tersedia di sistem.


2

Punya masalah ini pada Windows baru-baru ini, dan dos2unixdan unix2dossampah yang dikirimkan dengan git untuk windows melakukan trik. Secara default mereka berlokasi di C:\Program Files\Git\usr\bin\. Perhatikan ini hanya akan berfungsi jika file Anda tidak perlu UTF-16. Sebagai contoh, seseorang secara tidak sengaja menyandikan file python sebagai UTF-16 ketika tidak perlu (dalam kasus saya).

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

dan

PS C:\Users\xxx> unix2dos my_file.py
unix2dos: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 DOS format...
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.