Tôi có thể làm cho git nhận ra tệp UTF-16 dưới dạng văn bản không?


140

Tôi đang theo dõi tệp máy ảo Virtual PC (* .vmc) trong git và sau khi thực hiện thay đổi, git đã xác định tệp là nhị phân và sẽ không làm cho tôi khác. Tôi phát hiện ra rằng tập tin được mã hóa theo UTF-16.

Git có thể được dạy để nhận ra rằng tập tin này là văn bản và xử lý nó một cách thích hợp?

Tôi đang sử dụng git theo Cygwin, với core.autocrlf được đặt thành false. Tôi có thể sử dụng mSysGit hoặc git trong UNIX, nếu cần.

Câu trả lời:


83

Tôi đã vật lộn với vấn đề này một thời gian và chỉ cần phát hiện ra (đối với tôi) một giải pháp hoàn hảo:

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

git difftoolnhận các đối số tương tự như git diffvậy, nhưng chạy một chương trình khác theo lựa chọn của bạn thay vì GNU tích hợp diff. Vì vậy, chọn một diff nhận biết đa bào (trong trường hợp của tôi, vimở chế độ khác) và chỉ sử dụng git difftoolthay vì git diff.

Tìm "Difftool" quá lâu để gõ? Không vấn đề gì:

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

Đá Git.


1
Không phải là một giải pháp hoàn hảo (thà có một sự khác biệt di chuyển thống nhất), NHƯNG, đó là cái ác ít hơn được đưa ra các lựa chọn và tôi không muốn tìm một cái gì đó mới để cài đặt. "Vimdiff", nó là vậy! (vâng, vim ... và git)
Roboprog

1
Điều này cũng hoạt động đến giai đoạn và chỉ cam kết các khối tệp UTF16?
Ortwin Gentz

Tôi sử dụng Beyond So sánh như một công cụ khác biệt và hợp nhất. Từ .gitconfig <pre> <code> [Difftool "bc3"] path = c: / Chương trình tệp (x86) / Beyond So sánh 3 / bcomp.exe [mergetool "bc3"] path = c: / Tệp chương trình (x86) / Vượt ra ngoài so sánh 3 / bcomp.exe </ code> </ pre>
Tom Wilson

@Tom Wilson Xin lỗi vì không thể định dạng khối mã bằng cách thụt 4 khoảng trắng!?
Tom Wilson

Tôi có kiến ​​thức cơ bản cho git và không chắc nó xử lý các thay đổi tập tin như thế nào. Đây có phải luôn là tệp nhị phân hoặc cho văn bản (ASCII) có xử lý / phát hiện thay đổi đặc biệt không?
i486

63

Có một giải pháp rất đơn giản mà hiệu quả vượt trội trên Unices.

Ví dụ: với .stringscác tệp của Apple chỉ:

  1. Tạo một .gitattributestệp trong thư mục gốc của kho lưu trữ của bạn với:

    *.strings diff=localizablestrings
    
  2. Thêm phần sau vào ~/.gitconfigtập tin của bạn :

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

Nguồn: Các tệp Diff .strings trong Git (và bài cũ hơn từ năm 2010).


Tôi đã làm điều này nhưng git từ chối chạy sau này. Lỗi tôi nhận được là "dòng tệp cấu hình xấu 4 trong /Users/myusername/.gitconfig". Tôi đã sử dụng "git config --global --edit" để mở tệp gitconfig của mình. Thật thú vị nếu tôi loại bỏ các dòng thêm vào tất cả hoạt động tốt. Bất kì manh mối nào ?
shshnk

Tôi sẽ đoán các trích dẫn thông minh nếu bạn sao chép / dán. Tôi đã chỉnh sửa câu trả lời để khắc phục điều đó.
Lou Franco

Điều này hoạt động như một sự quyến rũ, nó nên là câu trả lời được chấp nhận vì đơn giản và để tích hợp tốt hơn. Tôi không thấy cách "sử dụng công cụ khác" có thể là câu trả lời cho "Tôi có thể khiến git nhận ra tệp UTF-16 dưới dạng văn bản không?"
itMaxence

@itMaxence Nghiêm túc, iconvlà "công cụ khác" theo cách tương tự như Vim hoặc Beyond So sánh (không phải là một phần của bộ git).
Búa búa Agi

@Agi Hammerthief chắc chắn sau khi đọc lại tôi đồng ý, dunno tôi đang nghĩ gì. FWIW vimdifficonvcả hai đều đã có mặt trên macOS, vì vậy bạn không cần bận tâm đến việc lấy chúng ở đâu và họ thực hiện công việc
itMaxence

39

Bạn đã thử thiết lập .gitattributesđể coi nó như một tệp văn bản chưa?

ví dụ:

*.vmc diff

Thêm chi tiết tại http://www.git-scm.com/docs/gitattribut.html .


2
Điều này hoạt động, nhưng để chính xác, xin lưu ý rằng điều này đặt hai thuộc tính: setdiff...
OK.

2
Giải pháp này là chấp nhận được duy nhất cho tôi. Theo nhận xét @OK, "bộ" không liên quan ở đây, chỉ *.vmc diff, *.sql diffv.v .. là cần thiết để đặt thuộc tính 'diff' cho đường dẫn được chỉ định. (Tôi không thể chỉnh sửa câu trả lời). Tuy nhiên, hãy cẩn thận: các khác biệt được hiển thị với khoảng trắng giữa mỗi ký tự và không thể "hunk sân khấu" hoặc "hunk hunk" cho các tệp có vấn đề.
Pac0

30

Theo mặc định, có vẻ như gitsẽ không hoạt động tốt với UTF-16; đối với một tệp như vậy, bạn phải đảm bảo rằng không CRLFxử lý được thực hiện trên tệp đó, nhưng bạn muốn diffmergehoạt động như một tệp văn bản thông thường (điều này bỏ qua việc thiết bị đầu cuối / trình soạn thảo của bạn có thể xử lý UTF-16 hay không).

Nhưng nhìn vào .gitattributestrang chủ , đây là thuộc tính tùy chỉnh đó là binary:

[attr]binary -diff -crlf

Vì vậy, có vẻ như với tôi rằng bạn có thể định nghĩa một thuộc tính tùy chỉnh trong cấp cao nhất của bạn .gitattributescho utf16(lưu ý rằng tôi thêm merge ở đây để chắc chắn rằng nó được xử lý dưới dạng văn bản):

[attr]utf16 diff merge -crlf

Từ đó bạn sẽ có thể chỉ định trong bất kỳ .gitattributestệp nào như:

*.vmc utf16

Cũng lưu ý rằng bạn vẫn có thể tạo diffmột tệp, ngay cả khi gitnghĩ rằng đó là tệp nhị phân với:

git diff --text

Biên tập

Câu trả lời này về cơ bản nói rằng GNU diff wth UTF-16 hoặc thậm chí UTF-8 không hoạt động tốt. Nếu bạn muốn gitsử dụng một công cụ khác để xem sự khác biệt (thông qua --ext-diff), câu trả lời đó gợi ý Guiffy .

Nhưng những gì bạn có thể cần chỉ là diffmột tệp UTF-16 chỉ chứa các ký tự ASCII. Một cách để làm việc đó là sử dụng --ext-diffvà tập lệnh shell sau:

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

Lưu ý rằng chuyển đổi sang UTF-8 cũng có thể hoạt động để hợp nhất, bạn chỉ cần đảm bảo rằng nó được thực hiện theo cả hai hướng.

Đối với đầu ra cho thiết bị đầu cuối khi nhìn vào độ lệch của tệp UTF-16:

Cố gắng khác biệt như vậy dẫn đến rác nhị phân phun ra màn hình. Nếu git đang sử dụng GNU diff, có vẻ như GNU diff không nhận biết được unicode.

GNU diff không thực sự quan tâm đến unicode, vì vậy khi bạn sử dụng diff --text, nó chỉ khác và xuất văn bản. Vấn đề là thiết bị đầu cuối bạn đang sử dụng không thể xử lý UTF-16 được phát ra (kết hợp với các dấu khác biệt là các ký tự ASCII).


Cố gắng khác biệt như vậy dẫn đến rác nhị phân phun ra màn hình. Nếu git đang sử dụng GNU diff, có vẻ như GNU diff không nhận biết được unicode.
Skiphoppy

1
GNU diff không thực sự quan tâm đến unicode, vì vậy khi bạn sử dụng diff --text, nó chỉ khác và xuất văn bản. Vấn đề là thiết bị đầu cuối bạn đang sử dụng không thể xử lý UTF-16 được phát ra (kết hợp với các dấu khác biệt là các ký tự ASCII).
Jared Oberhaus

@ jared-oberhaus - có cách nào để kích hoạt tập lệnh này chỉ cho một số loại tệp nhất định (nghĩa là có phần mở rộng nhất định) không?
Terry

8

Giải pháp là lọc qua cmd.exe /c "type %1". Nội dung của cmd typesẽ thực hiện chuyển đổi và do đó bạn có thể sử dụng tính năng đó với khả năng textconv của git diff để cho phép khuếch tán văn bản của các tệp UTF-16 (cũng nên hoạt động với UTF-8, mặc dù chưa được kiểm tra).

Trích dẫn từ trang gitattribut man:


Thực hiện khác văn bản của tệp nhị phân

Đôi khi, mong muốn thấy sự khác biệt của phiên bản chuyển đổi văn bản của một số tệp nhị phân. Ví dụ, một tài liệu xử lý văn bản có thể được chuyển đổi thành biểu diễn văn bản ASCII và khác biệt của văn bản được hiển thị. Mặc dù chuyển đổi này mất một số thông tin, nhưng khác biệt kết quả là hữu ích cho việc xem của con người (nhưng không thể được áp dụng trực tiếp).

Tùy chọn cấu hình textconv được sử dụng để xác định chương trình thực hiện chuyển đổi như vậy. Chương trình sẽ lấy một đối số duy nhất, tên của một tệp để chuyển đổi và tạo ra văn bản kết quả trên thiết bị xuất chuẩn.

Ví dụ: để hiển thị độ lệch của thông tin exif của tệp thay vì thông tin nhị phân (giả sử bạn đã cài đặt công cụ exif), hãy thêm phần sau vào $GIT_DIR/configtệp (hoặc $HOME/.gitconfigtệp) của bạn:

[diff "jpg"]
        textconv = exif

Một giải pháp cho mingw32 , người hâm mộ cygwin có thể phải thay đổi cách tiếp cận. Vấn đề là với việc chuyển tên tệp để chuyển đổi sang cmd.exe - nó sẽ được sử dụng dấu gạch chéo về phía trước và cmd giả định dấu phân cách thư mục dấu gạch chéo ngược.

Bước 1:

Tạo tập lệnh đối số duy nhất sẽ thực hiện chuyển đổi thành thiết bị xuất chuẩn. c: \ path \ đến \ some \ script.sh:

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

Bước 2:

Thiết lập git để có thể sử dụng tệp script. Bên trong cấu hình git của bạn ( ~/.gitconfighoặc .git/confighoặc xem man git-config), đặt này:

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

Bước 3:

Chỉ ra các tệp để áp dụng cách giải quyết này bằng cách sử dụng các tệp .gitattribut (xem man gitattribut (5)):

*vmc diff=cmdtype

sau đó sử dụng git difftrên các tập tin của bạn.


Gần như Tony Kuneck nhưng không có "c: /path/to/some/script.sh" entropy.ch/blog/Developer/2010/04/15/iêu
Alexey Shumkin

Tôi có một số vấn đề với tập lệnh như được hiển thị ở trên với Git cho Windows nhưng tôi thấy sau đây là ổn và cũng có thể xử lý các khoảng trắng trong đường dẫn : cmd //c type "${1//\//\\}" .
patthoyts

Điều này sẽ hoạt động mà không cần phải tạo tệp tập lệnh:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Jakub Berezanski

5

git gần đây đã bắt đầu hiểu các bảng mã như utf16. Xem tài liệu gitattribut , tìm kiếmworking-tree-encoding

[Hãy chắc chắn rằng trang người đàn ông của bạn phù hợp vì điều này khá mới!]

Nếu (giả sử) tệp là UTF-16 không có BOM trên máy Windows thì hãy thêm vào .gitattributestệp của bạn

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

Nếu UTF-16 (có bom) trên * nix, hãy tạo nó:

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

(Thay thế *.vmcbằng *.whatevercác whateverloại tệp bạn cần xử lý)

Xem: Hỗ trợ mã hóa cây làm việc "UTF-16LE-BOM" .


Đã thêm sau

Theo dõi @Hackslash, người ta có thể thấy rằng điều này là không đủ

 *.vmc text working-tree... 

Để có được các văn bản khác nhau, bạn cần

 *.vmc diff working-tree...

Đặt cả hai công việc là tốt

 *.vmc text diff working-tree... 

Nhưng nó được cho là

  • Dự phòng - eol=...ngụ ýtext
  • Verbose - một dự án lớn có thể dễ dàng có hàng tá loại tệp văn bản khác nhau

Vấn đề

Git có một thuộc tính vĩ mô binary có nghĩa là -text -diff. Ngược lại +text +diffkhông có sẵn nhưng git cung cấp các công cụ (tôi nghĩ vậy!) Để tổng hợp nó

Giải pháp

Git cho phép một người xác định các thuộc tính macro mới.

Tôi muốn đề xuất rằng đầu .gitattributestập tin bạn có

 [attr]textfile text diff

Sau đó, cho tất cả các đường dẫn cần phải là văn bản và diff

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

Lưu ý rằng trong hầu hết các trường hợp, chúng tôi sẽ muốn mã hóa mặc định (utf-8) và eol mặc định (gốc) và do đó có thể bị loại bỏ.

Hầu hết các dòng sẽ giống như

textfile *.c
textfile *.py
Etc

Tại sao không chỉ sử dụng diff?

Thực tế: Trong hầu hết các trường hợp, chúng tôi muốn eol bản địa. Có nghĩa là không eol=.... Vì vậy, textsẽ không được ngụ ý và cần phải được đặt rõ ràng.

Khái niệm: Văn bản Vs nhị phân là sự phân biệt cơ bản. eol, mã hóa, diff vv chỉ là một số khía cạnh của nó.

Khước từ

Do thời kỳ kỳ lạ mà chúng ta đang sống, tôi không có một chiếc máy với công việc hiện tại. Vì vậy, hiện tại tôi không thể kiểm tra bổ sung mới nhất. Nếu ai đó tìm thấy một cái gì đó sai, tôi sẽ phát / xóa.


Để làm cho tệp UTF-16LE-BOM của tôi hoạt động, tôi đã phải sử dụng*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash: Cảm ơn bạn đã ủng hộ. Tôi đoán bạn đang nói textmột mình bạn không nhận được văn bản khác? Bạn có thể kiểm tra xem với cả hai textdiffmọi thứ đều hoạt động tốt không? Trong trường hợp đó, tôi sẽ đưa ra một đề xuất khác
Rusi

Chính xác, textmột mình kết quả trong so sánh nhị phân. Tôi có thể làm diffhoặc text diffnó hoạt động. Tôi cần thêm -BOMđơn giản vì tập tin của tôi có BOM, YMMV.
HackSlash

@HackSlash Tôi đã kết hợp tìm kiếm của bạn. Sẽ thật tuyệt nếu bạn có thể kiểm tra!
Rusi

Cảm ơn @Rusi, có ý nghĩa với tôi.
HackSlash

4

Tôi đã viết một trình điều khiển git-diff nhỏ to-utf8, điều này sẽ giúp dễ dàng tìm khác biệt mọi tệp được mã hóa không phải ASCII / UTF-8. Bạn có thể cài đặt nó bằng hướng dẫn tại đây: https://github.com/chaitanyagupta/gitutils#to-utf8 ( to-utf8tập lệnh có sẵn trong cùng một repo).

Lưu ý rằng tập lệnh này yêu cầu cả hai fileiconvcác lệnh phải có sẵn trên hệ thống.


2

Có vấn đề này trên Windows gần đây, và dos2unixunix2dosthùng mà tàu với git cho các cửa sổ đã làm các trick. Theo mặc định, chúng nằm ở C:\Program Files\Git\usr\bin\. Quan sát điều này sẽ chỉ hoạt động nếu tệp của bạn không cần phải là UTF-16. Ví dụ, một người nào đó đã vô tình mã hóa một tệp python là UTF-16 khi không cần thiết (trong trường hợp của tôi).

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...
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.