ฉันสามารถทำให้ git รู้จักไฟล์ UTF-16 เป็นข้อความได้หรือไม่?


140

ฉันกำลังติดตามไฟล์เครื่องเสมือนพีซีเสมือน (* .vmc) ในคอมไพล์และหลังจากทำการเปลี่ยนแปลงคอมไพล์ระบุว่าไฟล์เป็นไบนารีและจะไม่แตกต่างกันสำหรับฉัน ฉันค้นพบว่าไฟล์ถูกเข้ารหัสใน UTF-16

สามารถสอนให้คอมไพล์ยอมรับว่าไฟล์นี้เป็นข้อความและจัดการได้อย่างเหมาะสมหรือไม่?

ฉันใช้คอมไพล์ภายใต้ Cygwin โดยมี core.autocrlf ตั้งค่าเป็นเท็จ ฉันสามารถใช้ mSysGit หรือ git ภายใต้ UNIX หากจำเป็น

คำตอบ:


83

ฉันดิ้นรนกับปัญหานี้มาระยะหนึ่งแล้วและเพิ่งค้นพบวิธีแก้ปัญหาที่สมบูรณ์แบบ (สำหรับฉัน):

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

git difftoolรับอาร์กิวเมนต์แบบเดียวกับที่ใช้git diffแต่รันโปรแกรม diff ที่คุณเลือกแทนที่จะเป็น GNU ในdiffตัว ดังนั้นให้เลือก diff หลายไบต์ที่รับรู้ (ในกรณีของฉันvimในโหมด diff) และใช้git difftoolแทนgit diffแทน

ค้นหา "difftool" ยาวเกินไปที่จะพิมพ์หรือไม่ ไม่มีปัญหา:

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

หินคอมไพล์


1
ไม่ใช่โซลูชันที่สมบูรณ์แบบ (ค่อนข้างจะมี diff ที่รวมเป็นหนึ่งเดียวแบบเลื่อน) แต่มันเป็นความชั่วที่น้อยกว่าที่ได้รับตัวเลือกและความไม่เต็มใจของฉันในการค้นหาสิ่งใหม่ที่จะติดตั้ง "vimdiff" มันเป็น! (ใช่เป็นกลุ่ม ... และคอมไพล์)
Roboprog

1
สิ่งนี้ยังใช้งานเป็นระยะและส่งเฉพาะไฟล์ UTF16 เท่านั้นหรือไม่
Ortwin Gentz

ฉันใช้Beyond Compareเป็นเครื่องมือ diff และผสาน จาก. gitconfig <pre> <code> [difftool "bc3"] path = c: / Program Files (x86) / Beyond เปรียบเทียบ 3 / bcomp.exe [mergetool "bc3"] path = c: / Program Files (x86) / นอกเหนือจากการเปรียบเทียบ 3 / bcomp.exe </code> </pre>
Tom Wilson

@Tom Wilson ขออภัยที่ไม่สามารถจัดรูปแบบรหัสบล็อกโดยเยื้องช่องว่าง 4!
Tom Wilson

ฉันมีความรู้พื้นฐานเกี่ยวกับคอมไพล์และไม่แน่ใจว่าจะจัดการกับการเปลี่ยนแปลงไฟล์ได้อย่างไร นี่เป็นไฟล์ไบนารี่เสมอหรือสำหรับข้อความ (ASCII) มีการประมวลผลพิเศษ / การตรวจจับการเปลี่ยนแปลงหรือไม่?
i486

63

มีวิธีแก้ปัญหาง่ายๆที่ทำงานนอกกรอบบน Unices

ตัวอย่างเช่นกับ.stringsไฟล์ของ Apple เพียง:

  1. สร้าง.gitattributesไฟล์ในรูทของที่เก็บของคุณด้วย:

    *.strings diff=localizablestrings
    
  2. เพิ่มสิ่งต่อไปนี้ใน~/.gitconfigไฟล์ของคุณ:

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

ที่มา: ไฟล์ Diff .strings ใน Git (และโพสต์ที่เก่ากว่าจาก 2010)


ฉันทำสิ่งนี้ แต่คอมไพล์ปฏิเสธที่จะทำงานหลังจากนี้ ข้อผิดพลาดที่ฉันได้รับคือ "ไฟล์กำหนดค่าบรรทัดที่ 4 ไม่ดีใน /Users/myusername/.gitconfig" ฉันใช้ "git config --global --edit" เพื่อเปิดไฟล์ gitconfig ของฉัน ที่น่าสนใจถ้าฉันลบบรรทัดที่เพิ่มทั้งหมดทำงานได้ดี เบาะแสใด ๆ
shshnk

ฉันจะเดาราคาฉลาดถ้าคุณคัดลอก / วาง ฉันแก้ไขคำตอบเพื่อแก้ไข
Lou Franco

มันใช้งานได้อย่างมีเสน่ห์มันควรเป็นคำตอบที่ได้รับการยอมรับเพื่อความเรียบง่ายและเพื่อการรวมที่ดีขึ้น ฉันไม่เห็นว่า "ใช้เครื่องมืออื่น" เป็นคำตอบของ "ฉันสามารถทำให้ git รู้จักไฟล์ UTF-16 เป็นข้อความได้หรือไม่"
itMaxence

@ itMaxence อย่างเคร่งครัดiconvคือ "เครื่องมืออีกอย่าง" ในลักษณะเดียวกับ Vim หรือ Beyond Compare คือ (ไม่ใช่ส่วนหนึ่งของชุด git)
Agi Hammerthief

@AgiHammerthief แน่ใจว่าหลังจากอ่านอีกครั้งฉันเห็นด้วยไม่เป็นสิ่งที่ฉันคิดเกี่ยวกับ FWIW vimdiffและiconvมีทั้งสองอยู่แล้วบน macOS ดังนั้นคุณไม่จำเป็นต้องกังวลว่าจะหาได้ที่ไหนและพวกเขาทำงานได้เลย
itMaxence

39

คุณลองตั้งค่าของคุณ .gitattributesให้มันเป็นไฟล์ข้อความหรือไม่?

เช่น:

*.vmc diff

รายละเอียดเพิ่มเติมที่http://www.git-scm.com/docs/gitattributes.html


2
วิธีนี้ใช้งานได้ แต่เพื่อความถูกต้องโปรดทราบว่านี่เป็นการกำหนดคุณลักษณะสองอย่าง : setและdiff...
ตกลง

2
ทางออกนี้เป็นที่ยอมรับสำหรับฉันเท่านั้น เป็นต่อ @OK ความคิดเห็นที่ "ชุด" ไม่เกี่ยวข้องที่นี่เพียง*.vmc diff, *.sql diffฯลฯ .. เป็นสิ่งจำเป็นในการตั้งค่าแอตทริบิวต์ 'ต่าง' สำหรับเส้นทางที่ระบุ (ฉันไม่สามารถแก้ไขคำตอบ) 2 caveats: diffs จะแสดงด้วยช่องว่างระหว่างตัวละครแต่ละตัวและเป็นไปไม่ได้ "ก้อนใหญ่เวที" หรือ "ทิ้งก้อนใหญ่" สำหรับไฟล์ที่มีปัญหาเหล่านั้น
Pac0

30

ตามค่าเริ่มต้นดูเหมือนว่าgitจะใช้งานไม่ได้กับ UTF-16 สำหรับไฟล์ดังกล่าวคุณต้องตรวจสอบให้แน่ใจว่าไม่มีCRLFการประมวลผลใด ๆเกิดขึ้น แต่คุณต้องการdiffและmergeทำงานเป็นไฟล์ข้อความปกติ (ไม่สนใจว่าเทอร์มินัล / บรรณาธิการของคุณสามารถรองรับ UTF-16 ได้หรือไม่

แต่ดู.gitattributesmanpageนี่คือแอตทริบิวต์แบบกำหนดเองที่binary:

[attr]binary -diff -crlf

ดังนั้นสำหรับฉันคุณสามารถกำหนดแอตทริบิวต์ที่กำหนดเองในระดับบนสุดของคุณ.gitattributesสำหรับutf16(โปรดทราบว่าฉันเพิ่มการรวมที่นี่เพื่อให้แน่ใจว่ามันจะถือว่าเป็นข้อความ):

[attr]utf16 diff merge -crlf

จากตรงนั้นคุณจะสามารถระบุ.gitattributesไฟล์ใด ๆ ที่คล้ายกับ:

*.vmc utf16

นอกจากนี้โปรดทราบว่าคุณควรจะสามารถdiffใช้ไฟล์ได้แม้ว่าจะgitคิดว่าเป็นไบนารีด้วย:

git diff --text

แก้ไข

โดยทั่วไปคำตอบนี้บอกว่า GNU แตกต่างกับ UTF-16 หรือแม้แต่ UTF-8 ก็ใช้งานไม่ได้ หากคุณต้องการgitใช้เครื่องมือที่แตกต่างเพื่อดูความแตกต่าง (ผ่าน--ext-diff) คำตอบนั้นแนะนำGuiffy Guiffy

แต่สิ่งที่คุณต้องการคือdiffไฟล์ UTF-16 ที่มีเฉพาะอักขระ ASCII เท่านั้น วิธีที่จะทำให้การทำงานนั้นใช้งานได้--ext-diffและเชลล์สคริปต์ต่อไปนี้:

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

โปรดทราบว่าการแปลงเป็น UTF-8 อาจใช้งานได้สำหรับการผสานเช่นกันคุณเพียงแค่ต้องแน่ใจว่าทำเสร็จทั้งสองทิศทาง

สำหรับเอาต์พุตไปยังเทอร์มินัลเมื่อดูผลต่างของไฟล์ UTF-16:

พยายามที่จะแตกต่างเช่นนั้นส่งผลให้ในถังขยะไบนารี spewed ไปที่หน้าจอ ถ้า git ใช้ GNU diff จะดูเหมือนว่า GNU diff นั้นไม่ได้รับรู้ถึง Unicode

GNU diff ไม่สนใจยูนิโค้ดจริงๆดังนั้นเมื่อคุณใช้ diff - text มันแค่ diffs และเอาท์พุทข้อความ ปัญหาคือเทอร์มินัลที่คุณใช้ไม่สามารถจัดการ UTF-16 ที่ปล่อยออกมา (รวมกับเครื่องหมาย diff ที่เป็นอักขระ ASCII)


พยายามที่จะแตกต่างเช่นนั้นส่งผลให้ในถังขยะไบนารีพ่นไปที่หน้าจอ ถ้า git ใช้ GNU diff จะดูเหมือนว่า GNU diff นั้นไม่ได้รับรู้ถึง Unicode
skiphoppy

1
GNU diff ไม่สนใจยูนิโค้ดจริงๆดังนั้นเมื่อคุณใช้ diff - text มันแค่ diffs และเอาท์พุทข้อความ ปัญหาคือเทอร์มินัลที่คุณใช้ไม่สามารถจัดการ UTF-16 ที่ปล่อยออกมา (รวมกับเครื่องหมาย diff ที่เป็นอักขระ ASCII)
Jared Oberhaus

@ jared-oberhaus - มีวิธีที่จะเรียกสคริปต์นี้สำหรับไฟล์บางประเภทเท่านั้น (เช่นได้รับนามสกุลบางอย่าง) หรือไม่?
เทอร์รี่

8

cmd.exe /c "type %1"แก้ปัญหาคือการกรองผ่าน คำสั่งของtype builtinจะทำการแปลงดังนั้นคุณสามารถใช้ความสามารถ textconv ของ git diff เพื่อเปิดใช้งานการกระจายข้อความของไฟล์ UTF-16 (ควรทำงานกับ UTF-8 เช่นกันแม้ว่าจะยังไม่ได้ทดสอบ)

การอ้างอิงจาก gitattributes man page:


การแสดงข้อความต่างกันของไฟล์ไบนารี

บางครั้งก็เป็นที่พึงปรารถนาที่จะเห็นความแตกต่างของไฟล์ไบนารีบางไฟล์ ตัวอย่างเช่นเอกสารเวิร์ดโปรเซสเซอร์สามารถแปลงเป็นการนำเสนอข้อความ ASCII และส่วนต่างของข้อความที่แสดง แม้ว่าการแปลงนี้จะสูญเสียข้อมูลบางส่วนความแตกต่างที่เกิดขึ้นมีประโยชน์สำหรับการรับชมของมนุษย์ (แต่ไม่สามารถนำมาใช้โดยตรง)

ตัวเลือกการกำหนดค่า textconv ใช้เพื่อกำหนดโปรแกรมสำหรับการดำเนินการแปลง โปรแกรมควรใช้อาร์กิวเมนต์ตัวเดียวชื่อของไฟล์ที่จะแปลงและสร้างข้อความที่เป็นผลลัพธ์ใน stdout

ตัวอย่างเช่นหากต้องการแสดงความแตกต่างของข้อมูล exif ของไฟล์แทนข้อมูลไบนารี่ (สมมติว่าคุณติดตั้งเครื่องมือ exif) ให้เพิ่มส่วนต่อไปนี้ลงใน$GIT_DIR/configไฟล์ (หรือ$HOME/.gitconfigไฟล์):

[diff "jpg"]
        textconv = exif

ทางออกสำหรับ mingw32แฟน cygwin อาจต้องเปลี่ยนวิธีการ ปัญหานี้เกิดจากการส่งชื่อไฟล์เพื่อแปลงเป็น cmd.exe - มันจะใช้เครื่องหมายทับซ้ายและ cmd ถือว่าตัวคั่นไดเรกทอรีแบ็กสแลช

ขั้นตอนที่ 1:

สร้างสคริปต์อาร์กิวเมนต์เดี่ยวที่จะทำการแปลงเป็น stdout C: \ เส้นทาง \ to \ บาง \ script.sh:

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

ขั้นตอนที่ 2:

ตั้งค่า git เพื่อให้สามารถใช้ไฟล์สคริปต์ ภายในกำหนดค่าคอมไพล์ของคุณ ( ~/.gitconfigหรือ.git/configหรือดูman git-config) ใส่นี้:

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

ขั้นตอนที่ 3:

ชี้ไฟล์ที่จะใช้วิธีแก้ปัญหานี้กับโดยใช้ไฟล์. gitattributes (ดู man gitattributes (5)):

*vmc diff=cmdtype

จากนั้นใช้git diffไฟล์ของคุณ


เกือบเป็นของ Tony Kuneck แต่ไม่มี "c: /path/to/some/script.sh
Alexey Shumkin

ฉันมีปัญหาบางอย่างกับสคริปต์ที่แสดงข้างต้นกับ Git สำหรับ Windows cmd //c type "${1//\//\\}" แต่ผมพบว่าต่อไปนี้เป็นเรื่องปกติและยังสามารถจัดการกับช่องว่างในเส้นทาง:
patthoyts

สิ่งนี้จะใช้งานได้โดยไม่จำเป็นต้องสร้างไฟล์สคริปต์:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Jakub Berezanski

5

git เมื่อเร็ว ๆ นี้ได้เริ่มเข้าใจการเข้ารหัสเช่น utf16 ดูเอกสารgitattributesค้นหาworking-tree-encoding

[ตรวจสอบให้แน่ใจว่าหน้าคนของคุณตรงกันเพราะนี่ค่อนข้างใหม่!]

ถ้า (พูด) ไฟล์เป็น UTF-16 ที่ไม่มี BOM บนเครื่อง Windows ให้เพิ่ม.gitattributesไฟล์ของคุณ

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

หาก UTF-16 (ที่มี bom) บน * nix ให้ทำ:

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

(แทนที่*.vmcด้วย*.whateverสำหรับwhateverไฟล์ประเภทที่คุณต้องจัดการ)

ดู: การสนับสนุนการทำงานต้นไม้เข้ารหัส "UTF-16LE-BOM"


เพิ่มในภายหลัง

การติดตาม @Hackslash อาจพบว่านี่ไม่เพียงพอ

 *.vmc text working-tree... 

เพื่อให้ได้ข้อความที่แตกต่างที่คุณต้องการ

 *.vmc diff working-tree...

วางทั้งงานเช่นกัน

 *.vmc text diff working-tree... 

แต่มันเป็นเนื้อหา

  • ซ้ำซ้อน - eol=...แสดงถึงtext
  • Verbose - โครงการขนาดใหญ่สามารถมีไฟล์ข้อความได้หลายสิบชนิด

ปัญหา

Git มีมหภาคแอตทริบิวต์ ซึ่งหมายความว่าbinary -text -diffตรงข้าม+text +diffไม่มีในตัว แต่คอมไพล์ให้เครื่องมือ (ฉันคิดว่า!) สำหรับการสังเคราะห์

การแก้ไขปัญหา

Git อนุญาตให้หนึ่งเพื่อกำหนดแอตทริบิวต์แมโครใหม่

ฉันขอเสนอด้านบนของ.gitattributesไฟล์ที่คุณมี

 [attr]textfile text diff

จากนั้นสำหรับเส้นทางทั้งหมดที่จะต้องมีข้อความและแตกต่างกัน

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

โปรดทราบว่าในกรณีส่วนใหญ่เราต้องการการเข้ารหัสเริ่มต้น (utf-8) และ eol เริ่มต้น (ดั้งเดิม) และอื่น ๆอาจลดลง

บรรทัดส่วนใหญ่ควรมีลักษณะดังนี้

textfile *.c
textfile *.py
Etc

ทำไมไม่ใช้ความแตกต่าง

ในทางปฏิบัติ: ในกรณีส่วนใหญ่เราต้องการ eol ดั้งเดิม eol=...ซึ่งหมายความว่าไม่มี ดังนั้นtextจะไม่ได้รับโดยนัยและจะต้องใส่อย่างชัดเจน

แนวคิด: ข้อความ Vs binary เป็นความแตกต่างพื้นฐาน eol, การเข้ารหัส, diff ฯลฯ เป็นเพียงบางส่วนของมัน

คำปฏิเสธ

เนื่องจากเวลาที่แปลกประหลาดที่เราอาศัยอยู่ฉันไม่มีเครื่องจักรที่มีคอมไพล์ทำงานอยู่ในปัจจุบัน ดังนั้นฉันไม่สามารถตรวจสอบการเพิ่มล่าสุดได้ในขณะนี้ หากมีคนพบสิ่งผิดปกติฉันจะส่ง / ลบ


ที่จะได้รับไฟล์ UTF-16LE-BOM ของฉันไปทำงานผมใช้*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash: ขอบคุณที่เฮดอัพ ฉันเดาว่าคุณกำลังพูดtextอยู่คนเดียวคุณไม่ได้รับข้อความที่ดีใช่ไหม คุณช่วยกรุณาตรวจสอบว่ามีทั้งสอง textและdiffการทำงานทุกอย่างดี? ในกรณีนี้ฉันจะให้คำแนะนำที่แตกต่าง
Rusi

ถูกต้องtextเพียงอย่างเดียวส่งผลให้ในการเปรียบเทียบแบบไบนารี ฉันสามารถทำdiffหรือtext diffใช้งานได้ ฉันต้องการเพิ่ม-BOMเพียงเพราะไฟล์ของฉันมี BOM, YMMV
HackSlash

@HackSlash ฉันได้รวมสิ่งที่คุณค้นหาแล้ว มันจะดีถ้าคุณสามารถตรวจสอบออก!
Rusi

ขอบคุณ @Rusi ทำให้รู้สึกถึงฉัน
HackSlash

4

ฉันเขียนไดรเวอร์ git-diff ขนาดเล็กto-utf8ซึ่งควรทำให้ง่ายต่อการ diff ไฟล์ที่เข้ารหัสที่ไม่ใช่ ASCII / UTF-8 คุณสามารถติดตั้งได้โดยใช้คำแนะนำที่นี่: https://github.com/chaitanyagupta/gitutils#to-utf8 (to-utf8สคริปต์มีอยู่ใน repo เดียวกัน)

โปรดทราบว่าสคริปต์นี้ต้องมีทั้งคำสั่งfileและiconvพร้อมใช้งานบนระบบ


2

มีปัญหานี้ใน Windows เมื่อเร็ว ๆ นี้และdos2unixและunix2dosถังขยะที่มาพร้อมกับคอมไพล์สำหรับ windows ได้ทำเคล็ดลับ C:\Program Files\Git\usr\bin\โดยค่าเริ่มต้นที่พวกเขากำลังอยู่ใน สังเกตว่าสิ่งนี้จะใช้งานได้หากไฟล์ของคุณไม่ได้จำเป็นต้องเป็น UTF-16 ตัวอย่างเช่นมีคนเข้ารหัสไฟล์หลามโดยบังเอิญเป็น UTF-16 เมื่อมันไม่จำเป็นต้องเป็น (ในกรณีของฉัน)

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

และ

PS C:\Users\xxx> unix2dos my_file.py
unix2dos: converting UTF-16LE file my_file.py to ANSI_X3.4-1968 DOS format...
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.