Tại sao Git coi tệp văn bản này là tệp nhị phân?


150

Tôi tự hỏi tại sao git nói với tôi điều này :?

$ git diff MyFile.txt
diff --git a/MyFile.txt b/MyFile.txt
index d41a4f3..15dcfa2 100644
Binary files a/MyFile.txt and b/MyFile.txt differ

Họ không tập tin văn bản?

Tôi đã kiểm tra .gitattribut và nó trống. Tại sao tôi nhận được tin nhắn này? Tôi không thể nhận được khác biệt khi tôi sử dụng để nữa

THÊM:

Tôi đã nhận thấy có một quyền @trong tập tin, đây là gì? Điều này có thể là lý do?

$ls -all
drwxr-xr-x   5 nacho4d  staff    170 28 Jul 17:07 .
drwxr-xr-x  16 nacho4d  staff    544 28 Jul 16:39 ..
-rw-r--r--@  1 nacho4d  staff   6148 28 Jul 16:15 .DS_Store
-rw-r--r--@  1 nacho4d  staff    746 28 Jul 17:07 MyFile.txt
-rw-r--r--   1 nacho4d  staff  22538  5 Apr 16:18 OtherFile.txt

4
Nó có thể là một tệp được mã hóa UTF-8.
Marnix van Valen

Nó được cho là UTF16 nhỏ endian LF
nacho4d

1
Từ lstrang chủ trên Mac OS X: Nếu tệp hoặc thư mục có thuộc tính mở rộng, trường quyền được in bởi -ltùy chọn được theo sau bởi một @ký tự . Sử dụng tùy chọn -@để xem các thuộc tính mở rộng này.
adl

Tôi nghĩ rằng đây có thể là một lỗi của git. Tôi đã xóa các thuộc tính mở rộng và bây giờ mọi thứ đã ổn trở lại.
nacho4d

4
@ nacho4d: Điều đó thật lạ, bởi vì git thậm chí không biết rằng có bất kỳ thuộc tính mở rộng nào. Nếu bạn có thể sao chép nó, nó sẽ có giá trị đưa lên danh sách gửi thư git. Như một tùy chỉnh tốt trong vger.kernel.orgdanh sách, bạn không phải đăng ký để đăng bài (mọi người sẽ giữ cho bạn CC'ed để trả lời) và được cho là không đưa ra khối lượng khá cao của git@vger.kernel.orgdanh sách.
Jan Hudec

Câu trả lời:


76

Điều đó chỉ có nghĩa là khi git kiểm tra nội dung thực tế của tệp (không biết rằng bất kỳ tiện ích mở rộng nào không phải là tệp nhị phân - bạn có thể sử dụng tệp thuộc tính nếu bạn muốn nói rõ ràng - xem các trang hướng dẫn).

Khi kiểm tra nội dung của tệp, nó đã thấy những thứ không có trong các ký tự ascii cơ bản. Là UTF16 Tôi hy vọng rằng nó sẽ có các ký tự 'hài hước' để nó nghĩ rằng đó là nhị phân.

Có nhiều cách để nói với git nếu bạn có các định dạng ký tự quốc tế (i18n) hoặc mở rộng cho tệp. Tôi không đủ phương pháp chính xác để thiết lập điều đó - bạn có thể cần RT [Full] M ;-)

Chỉnh sửa: tìm kiếm nhanh SO tìm thấy can-i-make-git-Recogn-a-utf-16-file-as-text sẽ cung cấp cho bạn một vài manh mối.


10
Bạn gần như nhưng không hoàn toàn không sai. Git đã kiểm tra các tập tin thực tế và đã thấy các nhân vật 'hài hước' ở đó. Tuy nhiên, nó không "nghĩ" UTF-16 là nhị phân. Nó nhị phân, bởi vì văn bản được định nghĩa là dựa trên ASCII (đó là điều duy nhất mà diff tích hợp sẽ cho kết quả có thể sử dụng được) và UTF-16 thì không. Có, có một cách để bảo git sử dụng diff khác biệt cho các tệp được xác định mẫu (sử dụng .gitattributes).
Jan Hudec

2
Tôi nên thêm, 'nhân vật hài hước' thực sự có nghĩa là không byte.
Jan Hudec

4
Chúng tôi đều đúng, nhưng từ những quan điểm khác nhau. Cả hai chúng tôi đều nói "Git kiểm tra nội dung để xác định loại của nó." Cả hai chúng tôi đều nói rằng để làm cho git biết nó nên được coi là UTF16, người dùng cần nói với git qua .gitattributesvv
Philip Oakley

7
@JanHudec: Theo quan điểm của bạn, TẤT CẢ các tệp là nhị phân.
stolsvik

2
@stolosvik, (và JanH) Đó là một nền tảng trung gian tinh tế hơn trong UTF-8 bao gồm cả các ký tự ASCII 0-127 cơ bản và tất cả các ký tự Unicode khác, không cần byte (00h) cho bất kỳ thứ gì khác ngoài char nul (bộ kết thúc chuỗi 'C'). Do đó, định nghĩa văn bản của Git là nội dung (cũng là 1k byte đầu tiên) không nên có byte rỗng khi được mã hóa utf-8. Hãy thử stackoverflow.com/questions/2241348/ cấp để đọc cho vui. Nhận xét ban đầu của tôi đề cập đến trường hợp khi dữ liệu được mã hóa UTF-16 được xem dưới dạng cặp byte, do đó, byte cao cho các điểm mã ascii sẽ là 00.
Philip Oakley

41

Nếu bạn chưa đặt loại tệp, Git sẽ tự động xác định tệp đó và một tệp có các dòng thực sự dài và có thể một số ký tự rộng (ví dụ Unicode) được coi là nhị phân. Với tệp .gitattribut, bạn có thể xác định cách Git diễn giải tệp. Đặt độ lệch thuộc tính theo cách thủ công cho phép Git diễn giải nội dung tệp dưới dạng văn bản và sẽ thực hiện một khác biệt thông thường.

Chỉ cần thêm một .gitattribut vào thư mục gốc của kho lưu trữ của bạn và đặt thuộc tính diff cho các đường dẫn hoặc tệp. Đây là một ví dụ:

src/Acme/DemoBundle/Resources/public/js/i18n/* diff
doc/Help/NothingToSay.yml                      diff
*.css                                          diff

Nếu bạn muốn kiểm tra xem có thuộc tính nào được đặt trên một tệp không, bạn có thể làm điều đó với sự trợ giúp của git check-attr

git check-attr --all -- src/my_file.txt

Một tài liệu tham khảo thú vị khác về các thuộc tính Git có thể được tìm thấy ở đây .


1
Điều này rất hữu ích, nhưng thực sự không chính xác - thuộc tính đúng là diffkhông text. Các textthuộc tính không nói git để diff sử dụng văn bản, nhưng thay vì kiểm soát như thế nào kết thúc dòng được xử lý (bình thường để LF). Xem liên kết của bạn đến .gitattribut để biết thêm chi tiết.
ErikE

Cảm ơn @ErikE. Tôi đã cập nhật bài viết của mình theo nhận xét của bạn và tài liệu Git.
naitsirch

4
Ngoài ra, bạn có thể đặt loại khác nên được thực hiện. Ví dụ: nếu đó là tệp xml, bạn có thể sử dụng diff=xmlthay vì chỉ diff.
Sandy Chapman

1
Điều ngược lại với check-attr - có set-attr không? Ban đầu, tôi đã vô tình lưu một tệp dưới dạng UTF-16, sau đó cam kết và đẩy nó, và bây giờ BitBucket thấy nó là UTF-16, ngay cả sau khi lưu lại dưới dạng UTF-8, cam kết và đẩy lại. Điều này về cơ bản làm cho các yêu cầu kéo của tôi không thể đọc được vì người đánh giá cần nhấp vào từng nhận xét riêng lẻ để thêm nhận xét đánh giá.
John Zabroski

21

Tôi đã gặp vấn đề này khi GUI Git và SourceTree đang coi các tệp Java / JS là nhị phân và do đó không thể thấy sự khác biệt

Tạo tệp có tên "thuộc tính" trong thư mục .git \ thông tin với nội dung sau đã giải quyết được vấn đề

*.java diff
*.js diff
*.pl diff
*.txt diff
*.ts diff
*.html diff

Nếu bạn muốn thực hiện thay đổi này cho tất cả các kho lưu trữ thì bạn có thể thêm tệp thuộc tính ở vị trí sau $ HOME / .config / git / thuộc tính


1
Cũng lưu ý <project-root>/.gitattributestệp, làm cho thay đổi hoạt động cho tất cả những người đóng góp và chỉ cho dự án có liên quan.
jpaugh

Thêm * difflà hữu ích cho tôi: nó cho thấy sự khác biệt trong tất cả các loại tệp. Nhưng giải pháp của bạn là tốt hơn, vì tránh hiển thị sự khác biệt không cần thiết trong các tệp nhị phân lớn.
Boolean_Type

Vâng! Điều này có ích!
WildCat

19

Git thậm chí sẽ xác định rằng đó là nhị phân nếu bạn có một dòng siêu dài trong tệp văn bản của mình. Tôi đã phá vỡ một Chuỗi dài, biến nó thành một số dòng mã nguồn và đột nhiên tệp chuyển từ 'nhị phân' sang tệp văn bản mà tôi có thể thấy (trong SmartGit).

Vì vậy, đừng tiếp tục gõ quá xa về bên phải mà không nhấn 'Enter' trong trình chỉnh sửa của bạn - nếu không, sau này trên Git sẽ nghĩ rằng bạn đã tạo một tệp nhị phân.


1
Đây là một thông tin chính xác. Tôi đã cố gắng kiểm soát các khác biệt với một tệp kết xuất MySQL (tệp .sql) cực lớn, nhưng git coi nó như một tệp nhị phân, ngay cả khi nó chỉ có dữ liệu ASCII / UTF8 trên đó. Lý do, là các dòng siêu dài (chèn giá trị (một), (hai), (ba), (...), (3 triệu ...);. Thật kỳ lạ, với mỗi cam kết, kho git thực hiện không tăng thêm 1.7gb, nhưng chỉ ~ 350mb. Có lẽ, git đang nén tệp "nhị phân" trước khi lưu nó.
Alexandre T.

@AlexandreT. Git thực sự nén các đốm màu tập tin (sử dụng GZip, IIRC).
jpaugh

11

Tôi gặp vấn đề tương tự sau khi chỉnh sửa một trong các tệp của mình trong trình chỉnh sửa mới. Hóa ra trình soạn thảo mới đã sử dụng một mã hóa (Unicode) khác với trình soạn thảo cũ của tôi (UTF-8). Vì vậy, tôi chỉ đơn giản nói với biên tập viên mới của mình lưu các tệp của mình bằng UTF-8 và sau đó git đã hiển thị lại các thay đổi của tôi một cách chính xác và không xem đó là tệp nhị phân.

Tôi nghĩ vấn đề chỉ đơn giản là git không biết cách so sánh các tệp thuộc các loại mã hóa khác nhau. Vì vậy, loại mã hóa mà bạn sử dụng thực sự không thành vấn đề, miễn là nó vẫn nhất quán.

Tôi đã không kiểm tra nó, nhưng tôi chắc chắn rằng nếu tôi đã cam kết tệp của mình với mã hóa Unicode mới, lần sau khi tôi thay đổi tệp đó, nó sẽ hiển thị các thay đổi chính xác và không phát hiện ra đó là nhị phân, vì sau đó, nó đã được so sánh hai tệp được mã hóa Unicode, và không phải là tệp UTF-8 với tệp Unicode.

Bạn có thể sử dụng một ứng dụng như Notepad ++ để dễ dàng xem và thay đổi loại mã hóa của tệp văn bản; Mở tệp trong Notepad ++ và sử dụng menu Mã hóa trên thanh công cụ.


1
Unicode không phải là mã hóa. Đó là một bộ ký tự và UTF-8 là một trong những mã hóa của nó, tức là cách để mã hóa một bảng mã Unicode
phuclv

1
Điều này không giải quyết vấn đề, chỉ tránh nó. Vấn đề là git hoặc công cụ tìm khác biệt của nó không nhận dạng đúng các tệp văn bản hoặc không dễ dàng cho phép người dùng ghi đè hành vi của nó.
Preza8

6

Tôi đã có vấn đề tương tự. Tôi đã tìm thấy chủ đề khi tôi tìm kiếm giải pháp trên google, nhưng tôi vẫn không tìm thấy bất kỳ manh mối nào. Nhưng tôi nghĩ rằng tôi đã tìm thấy lý do sau khi nghiên cứu, ví dụ dưới đây sẽ giải thích rõ ràng manh mối của tôi.

    echo "new text" > new.txt
    git add new.txt
    git commit -m "dummy"

hiện tại, tệp new.txt được coi là một tệp văn bản.

    echo -e "newer text\000" > new.txt
    git diff

bạn sẽ nhận được kết quả này

diff --git a/new.txt b/new.txt
index fa49b07..410428c 100644
Binary files a/new.txt and b/new.txt differ

và thử cái này

git diff -a

bạn sẽ nhận được dưới đây

    diff --git a/new.txt b/new.txt
    index fa49b07..9664e3f 100644
    --- a/new.txt
    +++ b/new.txt
    @@ -1 +1 @@
    -new file
    +newer text^@

5

Chúng tôi đã gặp trường hợp này khi một tệp .html được xem là nhị phân bất cứ khi nào chúng tôi cố gắng thay đổi nó. Rất không đẹp để không thấy khác biệt. Thành thật mà nói, tôi đã không kiểm tra tất cả các giải pháp ở đây nhưng những gì làm việc cho chúng tôi là như sau:

  1. Đã xóa tệp (thực sự đã chuyển nó vào Bàn làm việc của tôi) và cam kết git deletion. Git nóiDeleted file with mode 100644 (Regular) Binary file differs
  2. Đã thêm lại tệp (thực sự đã chuyển nó từ Máy tính để bàn của tôi trở lại dự án). Git nói New file with mode 100644 (Regular) 1 chunk, 135 insertions, 0 deletionsTệp hiện được thêm dưới dạng tệp văn bản thông thường

Từ giờ trở đi, mọi thay đổi tôi thực hiện trong tệp được xem là một văn bản khác thường. Bạn cũng có thể xóa các cam kết này (1, 2 và 3 là thay đổi thực tế bạn thực hiện) nhưng tôi thích có thể thấy trong tương lai những gì tôi đã làm. Bóp 1 & 2 sẽ hiển thị thay đổi nhị phân.


Tương tự với một hoặc hai tệp cpp (được biên dịch thành công) được đẩy lên từ VS. Hiển thị gui Github để so sánh lố bịch. Người ta sẽ không muốn trở thành một người bay trên chuông trong một trao đổi ding dong như vậy, - một bên nói rằng đó là Github, và ở bên kia Github nói rằng đó là VS. :(
Laurie Stearn

4

Mỗi câu trả lời hữu ích này , bạn có thể hỏi trực tiếp Git tại sao nó đối xử với một tập tin trong một cách đặc biệt:

cd directory/of/interest
file *

Nó tạo ra đầu ra hữu ích như thế này:

$ file *
CR6Series_stats resaved.dat: ASCII text, with very long lines, with CRLF line terminators
CR6Series_stats utf8.dat:    UTF-8 Unicode (with BOM) text, with very long lines, with CRLF line terminators
CR6Series_stats.dat:         ASCII text, with very long lines, with CRLF line terminators
readme.md:                   ASCII text, with CRLF line terminators

6
filekhông phải là một lệnh git. Đây là một công cụ hoàn toàn riêng biệt được đóng gói bằng git trên Windows. Có tài liệu cho thấy đây là những gì git sử dụng để phát hiện tệp nhị phân?
Tối đa

4

Điều này cũng được gây ra (trên Windows ít nhất) bởi các tệp văn bản có UTF-8 với mã hóa BOM . Việc thay đổi mã hóa thành UTF-8 thông thường ngay lập tức khiến Git thấy tệp dưới dạng type = text


1

Tôi đã có một ví dụ .gitignorechứa một đôi\r (trở về vận chuyển) theo mục đích.

Tập tin đó được xác định là nhị phân bởi git. Thêm một .gitattributestập tin giúp.

# .gitattributes file
.gitignore diff

1
Đã làm việc. Tôi cũng đã có một đôi \ r để bỏ qua một số tệp "Biểu tượng \ r \ r" của hệ điều hành. Tốt để biết nguyên nhân cũng như sửa chữa.
hsandt

1

Nếu git check-attr --all -- src/my_file.txtchỉ ra rằng tệp của bạn được gắn cờ là nhị phân và bạn chưa đặt tệp đó là nhị phân .gitattributes, hãy kiểm tra tệp đó /.git/info/attributes.


0

Thay đổi Aux.js thành một tên khác, như Sig.js.

Cây nguồn vẫn hiển thị nó dưới dạng tệp nhị phân, nhưng bạn có thể tạo (thêm) nó và cam kết.


0

Tôi gặp vấn đề tương tự khi tôi dán một số văn bản từ tin nhắn Kafka nhị phân, đã chèn ký tự không nhìn thấy và khiến git nghĩ rằng tệp là nhị phân.

Tôi tìm thấy các ký tự vi phạm bằng cách tìm kiếm tệp bằng regex [^ -~\n\r\t]+.

  • [ khớp các nhân vật trong bộ này
  • ^ khớp các ký tự không có trong bộ này
  • -~ khớp tất cả các ký tự từ '' (dấu cách) đến '~'
  • \n dòng mới
  • \r vận chuyển trở lại
  • \t chuyển hướng
  • ] đóng bộ
  • + phù hợp với một hoặc nhiều nhân vật

-2

Tôi chỉ mất vài giờ để xem tất cả mọi thứ trong danh sách này để cố gắng tìm ra lý do tại sao một trong những dự án thử nghiệm trong giải pháp của tôi không thêm bất kỳ thử nghiệm nào vào trình thám hiểm.

Trong trường hợp của tôi, hóa ra là bằng cách nào đó (có lẽ do sự hợp nhất git kém ở đâu đó) mà VS đã mất hoàn toàn một tài liệu tham khảo dự án. Nó vẫn đang xây dựng nhưng tôi nhận thấy rằng nó chỉ xây dựng các phụ thuộc.

Sau đó tôi nhận thấy rằng nó không hiển thị trong danh sách phụ thuộc, vì vậy tôi đã xóa và thêm lại dự án thử nghiệm và tất cả các thử nghiệm của tôi đã xuất hiện cuối cùng.


2
Visual Studio thực sự không liên quan ở đây.
jpaugh
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.