Dlaczego Git traktuje ten plik tekstowy jako plik binarny?

150

Zastanawiam się, dlaczego git mi to mówi :?

$ 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

Czy nie są to pliki tekstowe?

Sprawdziłem .gitattributes i jest pusty. Dlaczego otrzymuję tę wiadomość? Nie mogę już uzyskać różnic, tak jak używam

DODANY:

Zauważyłem, że @w pliku są uprawnienia, co to jest? Czy to może być powód?

$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
nacho4d
źródło
4
Może to być plik zakodowany w UTF-8.
Marnix van Valen
Ma to być little endian LF UTF16
nacho4d
1
Ze strony lspodręcznika w systemie Mac OS X: Jeśli plik lub katalog ma rozszerzone atrybuty, po polu uprawnień wyświetlanym przez -lopcję występuje @znak . Użyj opcji, -@aby zobaczyć te rozszerzone atrybuty.
adl
Myślę, że to może być błąd gita. Usunąłem rozszerzone atrybuty i teraz wszystko jest w porządku.
nacho4d
4
@ nacho4d: To dziwne, ponieważ git nie powinien nawet wiedzieć, że istnieją jakieś rozszerzone atrybuty. Gdybyś mógł to odtworzyć, warto by było znaleźć się na liście mailingowej git. Jak jest dobrym zwyczajem na vger.kernel.orglistach, nie musisz zapisywać się do postów (ludzie będą Cię informować o odpowiedziach) i raczej nie powinni brać pod uwagę dość dużej objętości [email protected]listy.
Jan Hudec

Odpowiedzi:

76

Oznacza to po prostu, że kiedy git sprawdza rzeczywistą zawartość pliku (nie wie, że żadne dane rozszerzenie nie jest plikiem binarnym - możesz użyć pliku atrybutów, jeśli chcesz to wyraźnie powiedzieć - zobacz strony podręcznika).

Po sprawdzeniu zawartości pliku zobaczył rzeczy, które nie są w podstawowych znakach ascii. Będąc UTF16, spodziewam się, że będzie miał „zabawne” postacie, więc uważa, że ​​jest binarny.

Istnieją sposoby, aby powiedzieć gitowi, czy masz internacjonalizację (i18n) lub rozszerzone formaty znaków dla pliku. Nie mam wystarczającej wiedzy na temat dokładnej metody ustawienia tego - być może będziesz musiał RT [Full] M ;-)

Edycja: szybkie wyszukiwanie znalezionego SO can-i-make-git-aware-a-utf-16-file-as-text, co powinno dać ci kilka wskazówek.

Philip Oakley
źródło
10
Prawie się nie mylisz, ale nie całkiem. Git sprawdził aktualne pliki i zobaczył tam „zabawne” postacie. Jednak nie "myśli", że UTF-16 jest binarny. To jest binarny, ponieważ tekst jest zdefiniowany jako ASCII oparte (to jedyna rzecz wbudowanego diff da użytecznych wyników dla) i UTF-16 nie jest. Tak, istnieje sposób, aby powiedzieć gitowi, aby używał specjalnego porównania dla plików ze zdefiniowanym wzorcem (używając .gitattributes).
Jan Hudec
2
Powinienem dodać, że „zabawne postacie” naprawdę oznaczają zero bajtów.
Jan Hudec
4
Oboje mamy rację, ale z różnych perspektyw. Obaj mówimy „Git sprawdza zawartość, aby określić jej typ”. Obaj mówimy, że aby git wiedział, że powinien być traktowany jako UTF16, użytkownik musi powiedzieć gitowi za pośrednictwem .gitattributesitp.
Philip Oakley
7
@JanHudec: Twoim zdaniem WSZYSTKIE pliki są binarne.
stolsvik
2
@stolosvik (i JanH) Jest to bardziej subtelny środek, ponieważ UTF-8 zawiera zarówno podstawowe znaki 0-127 ASCII, jak i wszystkie inne znaki Unicode, bez potrzeby bajtu null (00h) dla czegokolwiek innego niż znak zerowy (terminator ciągu „C”). Tak więc definicja tekstu Gita jest taka, że ​​zawartość (dobrze pierwszy kilobajt 1kb) nie powinna mieć bajtu zerowego, gdy jest zakodowana w utf-8. Wypróbuj stackoverflow.com/questions/2241348/ ... dla przyjemnej lektury. Mój pierwotny komentarz odnosi się do przypadku, gdy dane zakodowane w UTF-16 są postrzegane jako pary bajtów, więc starszy bajt dla punktów kodowych ascii to 00.
Philip Oakley
41

Jeśli nie ustawiłeś typu pliku, Git spróbuje określić go automatycznie i plik z naprawdę długimi liniami i być może kilka szerokich znaków (np. Unicode) jest traktowany jako binarny. Za pomocą pliku .gitattributes możesz zdefiniować, w jaki sposób Git interpretuje plik. Ręczne ustawienie atrybutu diff pozwala Gitowi zinterpretować zawartość pliku jako tekst i wykona zwykłe porównanie.

Po prostu dodaj .gitattributes do głównego folderu repozytorium i ustaw atrybut diff na ścieżki lub pliki. Oto przykład:

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

Jeśli chcesz sprawdzić, czy plik ma ustawione atrybuty, możesz to zrobić za pomocą git check-attr

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

Kolejne fajne odniesienie do atrybutów Git można znaleźć tutaj .

naitsirch
źródło
1
Było to pomocne, ale w rzeczywistości jest niepoprawne - właściwy atrybut już diffnie text. textAtrybut nie powiedzieć git diff pomocą tekstu, ale zamiast kontroli jak zakończeń linii są obsługiwane (normalizację do LF). Zobacz swój link do .gitattributes, aby uzyskać więcej informacji.
ErikE,
Dzięki @ErikE. Zaktualizowałem swój post zgodnie z Twoim komentarzem i dokumentacją Git.
naitsirch
4
Dodatkowo możesz ustawić, jaki rodzaj różnic ma być wykonywany. Na przykład, jeśli jest to plik xml, możesz użyć diff=xmlzamiast tylko diff.
Sandy Chapman
1
Czym jest przeciwieństwo check-attr - czy istnieje atrybut set? Pierwotnie przypadkowo zapisałem plik jako UTF-16, następnie zatwierdziłem go i pchnąłem, a teraz BitBucket widzi go jako UTF-16, nawet po ponownym zapisaniu go jako UTF-8, zatwierdzeniu i ponownym wysłaniu. Zasadniczo uniemożliwia to odczytanie moich żądań pull, ponieważ recenzenci muszą kliknąć każdy komentarz, aby dodać komentarze do recenzji.
John Zabroski
21

Miałem ten problem, w którym Git GUI i SourceTree traktowały pliki Java / JS jako binarne i dlatego nie widziałem różnicy

Utworzenie pliku o nazwie „attributes” w folderze .git \ info z następującą zawartością rozwiązało problem

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

Jeśli chcesz wprowadzić tę zmianę dla wszystkich repozytoriów, możesz dodać plik atrybutów w następującej lokalizacji $ HOME / .config / git / attributes

Hemant
źródło
1
Zwróć także uwagę na <project-root>/.gitattributesplik, co powoduje, że zmiana jest aktywna dla wszystkich współtwórców i tylko dla odpowiedniego projektu.
jpaugh
Dodanie * diffbyło dla mnie pomocne: pokazuje różnicę we wszystkich typach plików. Ale twoje rozwiązanie jest lepsze, ponieważ unika się wyświetlania niepotrzebnych różnic w dużych plikach binarnych.
Boolean_Type
Tak! To pomaga!
WildCat
19

Git ustali nawet, że jest binarny, jeśli masz jedną bardzo długą linię w pliku tekstowym. Zerwałem długi ciąg znaków, zamieniając go na kilka linii kodu źródłowego i nagle plik zmienił się z binarnego w plik tekstowy, który widziałem (w SmartGit).

Więc nie pisz zbyt daleko w prawo bez naciskania „Enter” w edytorze - w przeciwnym razie Git pomyśli, że utworzyłeś plik binarny.

Chris Murphy
źródło
1
To jest poprawna informacja. Próbowałem kontrolować różnice w bardzo dużym Dump MySQL (plik .sql), ale git traktuje go jako plik binarny, nawet jeśli zawiera tylko dane ASCII / UTF8. Powodem jest to, że wiersze są bardzo długie (wstaw wartości (jeden), (dwa), (trzy), (...), (3 miliony ...) ;. O dziwo, dla każdego zatwierdzenia repozytorium git nie zwiększy się o 1,7 GB, ale tylko ~ 350 MB. Być może git kompresuje plik „binarny” przed zapisaniem go.
Alexandre T.
@AlexandreT. Git rzeczywiście kompresuje pliki blob (używając GZip, IIRC).
jpaugh
11

Miałem ten sam problem po edycji jednego z moich plików w nowym edytorze. Okazuje się, że nowy edytor używał innego kodowania (Unicode) niż mój stary edytor (UTF-8). Więc po prostu powiedziałem mojemu nowemu edytorowi, aby zapisał moje pliki w UTF-8, a następnie git ponownie pokazał moje zmiany i nie zobaczył tego jako pliku binarnego.

Myślę, że problem polegał na tym, że git nie wie, jak porównać pliki o różnych typach kodowania. Tak więc typ kodowania, którego używasz, naprawdę nie ma znaczenia, o ile pozostaje spójny.

Nie testowałem tego, ale jestem pewien, że gdybym po prostu zatwierdził mój plik z nowym kodowaniem Unicode, następnym razem, gdybym wprowadził zmiany w tym pliku, pokazałby zmiany poprawnie i nie wykryłby go jako binarnego, ponieważ wtedy porównywałoby dwa pliki zakodowane w Unicode, a nie plik UTF-8 z plikiem Unicode.

Możesz użyć aplikacji takiej jak Notepad ++, aby łatwo zobaczyć i zmienić typ kodowania pliku tekstowego; Otwórz plik w Notepad ++ i użyj menu Kodowanie na pasku narzędzi.

śmiertelny pies
źródło
1
Unicode nie jest kodowaniem. Jest to zestaw znaków, a UTF-8 jest jednym z jego kodowania, czyli sposobem kodowania punktu
kodowego
1
Nie rozwiązuje to problemu, a jedynie go pozwala. Problem polega na tym, że git lub jego narzędzie do porównywania nie rozpoznaje poprawnie plików tekstowych lub nie pozwala łatwo użytkownikowi zmienić jego zachowania.
Preza8
6

Miałem ten sam problem. Znalazłem wątek, szukając rozwiązania w Google, nadal nie znajduję żadnej wskazówki. Ale myślę, że znalazłem powód po przestudiowaniu, poniższy przykład wyjaśni jasno moją wskazówkę.

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

na razie plik nowy.txt jest traktowany jako plik tekstowy.

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

otrzymasz ten wynik

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

i spróbuj tego

git diff -a

dostaniesz się poniżej

    diff --git a/new.txt b/new.txt
    index fa49b07..9664e3f 100644
    --- a/new.txt
    +++ b/new.txt
    @@ -1 +1 @@
    -new file
    +newer text^@
Howard
źródło
5

Mieliśmy taki przypadek, w którym plik .html był postrzegany jako binarny za każdym razem, gdy próbowaliśmy wprowadzić w nim zmiany. Bardzo niefajne, aby nie widzieć różnic. Szczerze mówiąc, nie sprawdziłem tutaj wszystkich rozwiązań, ale zadziałało u nas następujące:

  1. Usunąłem plik (faktycznie przeniosłem go na mój pulpit) i zatwierdziłem git deletion. Mówi GitDeleted file with mode 100644 (Regular) Binary file differs
  2. Ponownie dodałem plik (faktycznie przeniosłem go z mojego pulpitu z powrotem do projektu). Git mówi, że New file with mode 100644 (Regular) 1 chunk, 135 insertions, 0 deletionsplik jest teraz dodawany jako zwykły plik tekstowy

Odtąd wszelkie zmiany, które wprowadziłem w pliku, są widoczne jako zwykłe różnice tekstowe. Możesz również zmiażdżyć te zatwierdzenia (1, 2 i 3 to faktyczna zmiana, którą wprowadzasz), ale wolę móc zobaczyć w przyszłości, co zrobiłem. Zgniatanie 1 i 2 pokaże zmianę binarną.

StuFF mc
źródło
Podobnie jest z jednym lub dwoma (pomyślnie skompilowanymi) plikami cpp przekazanymi z VS. Renderuje GUI Github dla porównania niedorzeczne. Nie chciałoby się być muchą na dzwonku w takiej wymianie ding dong, - VS z jednej strony mówi, że to Github, az drugiej strony Github mówi, że to VS. :(
Laurie Stearn
4

Korzystając z tej przydatnej odpowiedzi , możesz bezpośrednio zapytać Gita, dlaczego traktuje plik w określony sposób:

cd directory/of/interest
file *

Daje użyteczne dane wyjściowe, takie jak:

$ 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
patricktokeeffe
źródło
6
filenie jest poleceniem git. Jest to całkowicie oddzielne narzędzie dostarczane z git dla systemu Windows. Czy istnieje dokumentacja pokazująca, że ​​właśnie tego używa git do wykrywania plików binarnych?
Max
4

Jest to również spowodowane (przynajmniej w systemie Windows) plikami tekstowymi z kodowaniem UTF-8 z kodowaniem BOM . Zmiana kodowania na zwykłe UTF-8 natychmiast sprawiła, że ​​Git zobaczył plik jako type = text

Robba
źródło
1

Miałem przypadek, w którym celowo .gitignorezawierał podwójną \rsekwencję (powrót karetki).

Ten plik został zidentyfikowany jako binarny przez git. Dodanie .gitattributespliku pomogło.

# .gitattributes file
.gitignore diff
Erik Zivkovic
źródło
1
Pracował. Miałem również podwójny plik \ r, aby zignorować plik „Icon \ r \ r” systemu operacyjnego. Dobrze jest poznać przyczynę i rozwiązanie.
hsandt
1

Jeśli git check-attr --all -- src/my_file.txtwskazuje, że plik jest oflagowany jako binarny, a nie ustawiłeś go jako binarny .gitattributes, sprawdź, czy jest w nim /.git/info/attributes.

coberlin
źródło
0

Zmień Aux.js na inną nazwę, na przykład Sig.js.

Drzewo źródłowe nadal przedstawia go jako plik binarny, ale można go umieścić na etapie (dodać) i zatwierdzić.

Oscar Zhou1989
źródło
0

Miałem podobny problem, gdy wkleiłem tekst z binarnej wiadomości Kafki, która wstawiła niewidoczny znak i spowodowała, że ​​git pomyślał, że plik jest binarny.

Znalazłem obraźliwe znaki, przeszukując plik za pomocą wyrażenia regularnego [^ -~\n\r\t]+.

  • [ dopasuj znaki w tym zestawie
  • ^ dopasuj znaki spoza tego zestawu
  • -~ dopasowuje wszystkie znaki od „” (spacja) do „~”
  • \n Nowa linia
  • \r powrót karetki
  • \t patka
  • ] zamknij zestaw
  • + dopasuj jeden lub więcej z tych znaków
Martyn Davis
źródło
-2

Właśnie spędziłem kilka godzin przeglądając wszystko z tej listy, próbując zrozumieć, dlaczego jeden z projektów testowych w moim rozwiązaniu nie dodał żadnych testów do eksploratora.

Okazało się w moim przypadku, że w jakiś sposób (prawdopodobnie z powodu złego gdzieś scalania gitów), że VS całkowicie stracił odniesienie do projektu. Wciąż się budował, ale zauważyłem, że budował tylko zależności.

Potem zauważyłem, że nie pojawia się on na samej liście zależności, więc usunąłem i ponownie dodałem projekt testowy i wszystkie moje testy wreszcie się pojawiły.

cirrus
źródło
2
Visual Studio naprawdę nie ma tutaj znaczenia.
jpaugh