Чи можу я змусити git розпізнавати файл UTF-16 як текст?


140

Я відстежую файл віртуальної машини Virtual PC (* .vmc) в git, і після внесення зміни git визначив файл як бінарний і не став би для нього відмінним. Я виявив, що файл закодований в UTF-16.

Чи можна навчити Git розпізнавати, що цей файл - текст та обробляти його належним чином?

Я використовую git під Cygwin, з core.autocrlf встановлено на false. Я можу використовувати 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що і, але запускає різну програму на ваш вибір замість вбудованого GNU diff. Отож, виберіть різний байт (у моєму випадку vimу режимі розм.) Та просто використовуйте git difftoolзамість цього git diff.

Знайти "difftool" занадто довго, щоб набрати? Нема проблем:

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

Гіт скелі.


1
Це не ідеальне рішення (скоріше мати б єдину прокрутку прокрутки), АЛЕ, це менше зло, враховуючи вибір та моє небажання знайти щось нове для встановлення. "vimdiff", це так! (так, vim ... і git)
Робопрог

1
Це також працює для постановки та введення лише фрагментів файлів UTF16?
Ортвін Генц

Я використовую програму Beyond Compare як інструмент розрізнення та об'єднання. From .gitconfig <pre> <code> [difftool "bc3"] path = c: / Program Files (x86) / Beyond Compare 3 / bcomp.exe [mergetool "bc3"] path = c: / Файли програми (x86) / Beyond Compare 3 / bcomp.exe </code> </pre>
Том Вілсон,

@Tom Wilson Вибачте, не вдалося відформатувати блок коду шляхом відступу 4 пробілів !?
Том Вілсон,

Я маю основні знання щодо git і не впевнений, як він обробляє зміни файлів. Чи завжди це як бінарні файли чи для тексту (ASCII) є спеціальна обробка / виявлення змін?
i486

63

Існує дуже просте рішення, яке працює поза коробкою на Unices.

Наприклад, лише з .stringsфайлами Apple :

  1. Створіть .gitattributesфайл у корені вашого сховища за допомогою:

    *.strings diff=localizablestrings
    
  2. Додайте у ~/.gitconfigфайл наступне :

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

Джерело: Різні файли .strings у Gitстарша публікація з 2010 року).


Я зробив це, але git відмовляється працювати після цього. Отримана помилка - "неправильний файл конфігураційного рядка 4 у /Users/myusername/.gitconfig". Для відкриття файлу gitconfig я використав "git config --global --edit". Цікаво, що якщо я видаляю додані рядки, все працює добре. Будь-які підказки?
шшнк

Я збираюся відгадати розумні котирування, якщо ви копіюєте / вставляєте. Я відредагував відповідь, щоб виправити це.
Лу Франко

Це працює як шарм, це повинно бути прийнятою відповіддю заради простоти та кращої інтеграції. Я не бачу, як "використовувати інший інструмент" може відповісти на "Чи можу я змусити git розпізнати файл UTF-16 як текст?"
itMaxence

@itMaxence Строго, iconvце "інший інструмент" точно так само, як і Vim або "Порівнювати" (не є частиною набору git).
Агі Хаммертіф

@AgiHammerthief впевнений, що після повторного читання я згоден, не знаю, про що я думав. FWIW vimdiffі iconvобидва вже присутні на macOS, тому вам не потрібно турбуватися, де їх взяти, і вони виконують роботу
itMaxence

39

Чи спробували ви налаштувати так, .gitattributesщоб це трактувало як текстовий файл?

наприклад:

*.vmc diff

Детальніше на http://www.git-scm.com/docs/gitattributes.html .


2
Це працює, але для коректності врахуйте, що для цього встановлено два атрибути: setі diff...
Гаразд.

2
Це рішення є єдиним прийнятним для мене. Відповідно до коментаря @OK, "set" тут не має значення, просто *.vmc diffі *.sql diffт. Д. Потрібно встановити атрибут "diff" для вказаного шляху. (Я не можу відредагувати відповідь). 2 застереження, однак: відмінні кольори відображаються з пробілом між кожним символом, і неможливо "підключити" або "відкинути парку" для цих проблемних файлів.
Pac0

30

За замовчуванням, схоже, це gitне буде добре працювати з UTF-16; для такого файлу ви повинні переконатися, що на ньому не CRLFпроводиться жодна обробка, але ви хочете diffі mergeпрацювати як звичайний текстовий файл (це ігнорує, чи може ваш термінал / редактор обробляти UTF-16).

Але , дивлячись на .gitattributesсторінках керівництва , тут є призначений для користувача атрибут , який 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), ця відповідь підказує Гіффі .

Але, напевно, вам знадобиться лише 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:

Намагання відрізнити це призводить до того, що бінарне сміття викидається на екран. Якщо git використовує GNU diff, здається, що GNU diff не обізнаний з унікодом.

GNU diff насправді не дбає про unicode, тому при використанні diff --тексту він просто розрізняється та виводить текст. Проблема полягає в тому, що термінал, який ви використовуєте, не може обробляти UTF-16, що випромінюється (у поєднанні з позначками diff, що є символами ASCII).


Намагання відрізнити це призводить до того, що бінарне сміття викидається на екран. Якщо git використовує GNU diff, здається, що GNU diff не обізнаний з унікодом.
skiphoppy

1
GNU diff насправді не дбає про unicode, тому при використанні diff --тексту він просто розрізняється та виводить текст. Проблема полягає в тому, що термінал, який ви використовуєте, не може обробляти UTF-16, що випромінюється (у поєднанні з знаками diff, що символи ASCII).
Джаред Оберхаус

@ jared-oberhaus - чи є спосіб запустити цей скрипт лише для певних типів файлів (тобто з певним розширенням)?
Террі

8

Рішення - фільтрувати cmd.exe /c "type %1". cmd's typeвбудований здійснить перетворення, і тому ви можете використовувати це за допомогою textconv здатності git diff для ввімкнення тексту, що відрізняє файли UTF-16 (також має працювати з UTF-8, хоча і не перевірено).

Цитування зі сторінки gitattributes man:


Виконання тексту відрізняється від двійкових файлів

Іноді бажано бачити різницю текстово-перетвореної версії деяких бінарних файлів. Наприклад, документ текстового процесора може бути перетворений у представлення тексту ASCII та різницю зображеного тексту. Незважаючи на те, що це перетворення втрачає деяку інформацію, одержувана різниця є корисною для перегляду людиною (але не може бути застосована безпосередньо).

Параметр configconconconcept використовується для визначення програми для здійснення такого перетворення. Програма повинна взяти єдиний аргумент, ім'я файлу для конвертації та створити отриманий текст у stdout.

Наприклад, щоб показати різницю інформації про exif файлу замість двійкової інформації (якщо ви встановили інструмент exif), додайте у свій $GIT_DIR/configфайл (або $HOME/.gitconfigфайл) наступний розділ :

[diff "jpg"]
        textconv = exif

Вболівальникам mingw32 , любителям cygwin, можливо, доведеться змінити підхід. Проблема полягає у передачі імені файлу для перетворення в cmd.exe - це буде використовувати передні косої риси, а cmd передбачає розділення каталогів зворотної косої риски.

Крок 1:

Створіть єдиний скрипт аргументу, який зробить перетворення в stdout. c: \ шлях \ до \ деякий \ 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у своїх файлах.


Майже як Тоні Кунек, але без "c: /path/to/some/script.sh
Олексій Шумкін

У мене є деякі проблеми зі сценарієм , як показано вище , з Git для Windows , але я знайшов наступне в порядку , а також може мати справу з прогалинами в дорозі: cmd //c type "${1//\//\\}" .
patthoyts

Це спрацює без необхідності створення файлу сценарію:textconv = powershell -NoProfile -Command \"& {Get-Content \\$args[0]}\"
Якуб Березанський,

5

git нещодавно почав розуміти кодування, такі як utf16. Див. Gitattributes документи , шукайтеworking-tree-encoding

[Переконайтеся, що ваша сторінка чоловіка збігається, оскільки це зовсім нове!]

Якщо (скажімо), файл UTF-16 без BOM на машині Windows, тоді додайте до свого .gitattributes файлу

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

Якщо UTF-16 (з бомбою) на * 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
  • Багатослівний - великий проект міг легко мати десятки різних типів текстових файлів

Проблема

Git має макроатрибут, binary що означає -text -diff. Протилежність+text +diff вбудоване, але git дає інструменти (я думаю!) Для його синтезу

Рішення

Git дозволяє визначати нові атрибути макросу.

Я пропоную ту верхню частину .gitattributesфайлу, яку ви маєте

 [attr]textfile text diff

Тоді для всіх шляхів, які мають бути текстовими та різними

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

Зауважте, що в більшості випадків нам потрібно, щоб кодування за замовчуванням (utf-8) та eol за замовчуванням (нативно) було відмінено.

Більшість ліній має виглядати

textfile *.c
textfile *.py
Etc

Чому б просто не використовувати diff?

Практично. У більшості випадків ми хочемо рідного еолу. Що означає ні eol=.... Таким чином text, не мається на увазі, і це потрібно чітко ставити.

Концептуальна: Текст Vs бінарний - це основна відмінність. eol, кодування, відмінності тощо - лише деякі аспекти цього.

Відмова від відповідальності

Через химерні часи, в які ми живемо, у мене немає машини з поточною робочою щіткою. Тому я не в змозі перевірити останнє доповнення. Якщо хтось виявить щось не так, я виправляю / видаляю.


Щоб примусити мене працювати файл UTF-16LE-BOM*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash: Дякую за голову. Я думаю, що ти кажеш, що textсамотужки ти не отримав приємного тексту? Ви можете, будь ласка, перевірити, що з обома text і diffвсе працює добре? У такому випадку я дам іншу рекомендацію
Русі

Правильне, textпоодинці призводить до двійкового порівняння. Я можу зробити diffабо text diffце працює. Мені потрібно було додати -BOMпросто тому, що мій файл мав BOM, YMMV.
HackSlash

@HackSlash Я включив ваші висновки. Було б чудово, якби ви могли це перевірити!
Русі

Дякую @Rusi, має сенс для мене.
HackSlash

4

Я написав невеликий драйвер git-diff to-utf8, який повинен полегшити розмежування будь-яких файлів, кодованих не ASCII / UTF-8. Ви можете встановити його за допомогою інструкцій тут: https://github.com/chaitanyagupta/gitutils#to-utf8 ( to-utf8сценарій доступний у тому ж репо).

Зауважте, що цей сценарій вимагає, щоб в системі були доступні fileі iconvкоманди, і команди.


2

Якщо б ця проблема на Windows , в останній час , а dos2unixй unix2dosбункера , які поставляються з мерзотником для вікон зробили трюк. За замовчуванням вони розташовані в C:\Program Files\Git\usr\bin\. Зауважте, що це буде працювати лише у тому випадку, якщо для вашого файлу не має бути UTF-16. Наприклад, хтось випадково кодував файл python як 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...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.