Могу ли я заставить git распознавать файл UTF-16 как текст?


140

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

Можно ли научить git распознавать, что это текстовый файл, и обрабатывать его соответствующим образом?

Я использую git под Cygwin, для core.autocrlf установлено значение false. При необходимости я мог бы использовать mSysGit или git под UNIX.

Ответы:


84

Некоторое время я боролся с этой проблемой и только что нашел (для меня) идеальное решение:

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

git difftoolпринимает те же аргументы, что и git diffобычно, но запускает программу сравнения по вашему выбору вместо встроенного GNU diff. Так что выберите многобайтовый diff (в моем случае vimв режиме diff) и просто используйте git difftoolвместо git diff.

Находите "difftool" слишком долго для ввода? Нет проблем:

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

Git Rock.


1
Не идеальное решение (я бы предпочел объединенную прокрутку), НО, это меньшее зло, учитывая выбор и мое нежелание находить что-то новое для установки. "vimdiff", это так! (да, vim ... и git)
Roboprog 03

1
Работает ли это также для создания и фиксации только фрагментов файлов UTF16?
Ортвин Генц

Я использую Beyond Compare как инструмент сравнения и слияния. Из .gitconfig <pre> <code> [difftool "bc3"] path = c: / Program Files (x86) / Beyond Compare 3 / bcomp.exe [mergetool "bc3"] path = c: / Program Files (x86) / Beyond Compare 3 / bcomp.exe </code> </pre>
Том Уилсон,

@Tom Wilson: Извините, не удалось отформатировать блок кода, сделав отступ в 4 пробела !?
Tom Wilson

У меня есть базовые знания о git и я не уверен, как он обрабатывает изменения файлов. Всегда ли это как двоичные файлы или для текста (ASCII) есть специальная обработка / обнаружение изменений?
i486

64

Существует очень простое решение, которое "из коробки" работает в Unices.

Например, с .stringsфайлами Apple просто:

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

    *.strings diff=localizablestrings
    
  2. Добавьте в свой ~/.gitconfigфайл следующее:

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

Источник: файлы Diff .strings в Gitболее ранняя публикация 2010 г.).


Я сделал это, но после этого git отказывается запускаться. Я получаю сообщение об ошибке: «Плохая строка 4 файла конфигурации в /Users/myusername/.gitconfig». Я использовал "git config --global --edit", чтобы открыть файл gitconfig. Интересно, что если я удалю добавленные строки, все будет работать нормально. Какие-нибудь подсказки?
shshnk

Я собираюсь угадать умные цитаты, если вы скопируете / вставите. Я отредактировал ответ, чтобы исправить это.
Лу Франко

Это работает как шарм, это должен быть принятый ответ для простоты и лучшей интеграции. Я не понимаю, как «использовать другой инструмент» может быть ответом на вопрос «Могу ли я заставить git распознавать файл UTF-16 как текст?»
itMaxence 06

@itMaxence Строго говоря, iconvэто «еще один инструмент», точно так же, как Vim или Beyond Compare (не входит в набор git).
Agi Hammerthief

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

40

Вы пытались настроить его так, .gitattributesчтобы он воспринимался как текстовый файл?

например:

*.vmc diff

Подробнее см. Http://www.git-scm.com/docs/gitattributes.html .


2
Это работает, но имейте в виду, что здесь устанавливаются два атрибута: setи diff...
ОК.

2
Это решение единственно приемлемое для меня. Согласно комментарию @OK, "set" здесь не имеет значения, просто *.vmc diffи *.sql diffт. Д. Необходимо установить атрибут 'diff' для указанного пути. (Не могу редактировать ответ). Однако есть два предостережения: различия отображаются с пробелом между каждым символом, и невозможно «сгруппировать фрагмент» или «отбросить фрагмент» для этих проблемных файлов.
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 diff с 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 может работать и для слияния, вам просто нужно убедиться, что это сделано в обоих направлениях.

Что касается вывода на терминал при просмотре diff файла UTF-16:

Попытка провести такое различие приводит к выбросу двоичного мусора на экран. Если git использует GNU diff, может показаться, что GNU diff не поддерживает Unicode.

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


Попытка провести такое различие приводит к выбросу двоичного мусора на экран. Если git использует GNU diff, может показаться, что GNU diff не поддерживает Unicode.
skiphoppy

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

@ jared-oberhaus - есть ли способ запустить этот скрипт только для определенных типов файлов (т.е. с определенным расширением)?
Терри

8

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

Цитата из справочной страницы gitattributes:


Выполнение текстовых различий бинарных файлов

Иногда желательно увидеть разницу между текстовыми версиями некоторых двоичных файлов. Например, документ текстового процессора можно преобразовать в текстовое представление ASCII и показать различие текста. Несмотря на то, что это преобразование теряет некоторую информацию, полученное различие полезно для просмотра человеком (но не может применяться напрямую).

Параметр конфигурации textconv используется для определения программы для выполнения такого преобразования. Программа должна принимать единственный аргумент, имя файла, который нужно преобразовать, и выдавать результирующий текст на стандартный вывод.

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

[diff "jpg"]
        textconv = exif

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

Шаг 1:

Создайте сценарий с одним аргументом, который будет преобразовывать в стандартный вывод. c: \ путь \ к \ some \ script.sh:

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

Шаг 2:

Настройте git, чтобы иметь возможность использовать файл сценария. Внутри вашей конфигурации 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" entropy.ch/blog/Developer/2010/04/15/…
Алексей Шумкин

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

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

5

git недавно начал понимать кодировки, такие как utf16. См. Документацию gitattributes , найдитеworking-tree-encoding

[Убедитесь, что ваша справочная страница совпадает, так как она совсем новая!]

Если (скажем) файл UTF-16 без спецификации на машине 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
  • Подробно - в большом проекте легко могут быть десятки различных типов текстовых файлов.

Проблема

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

Решение

Git позволяет определять новые атрибуты макроса.

Я бы предложил эту верхнюю часть .gitattributesфайла, который у вас есть

 [attr]textfile text diff

Затем для всех путей, которые должны быть text и diff, выполните

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

Обратите внимание, что в большинстве случаев нам нужна кодировка по умолчанию (utf-8) и eol по умолчанию (native), поэтому их можно отбросить.

Большинство строк должно выглядеть так

textfile *.c
textfile *.py
Etc

Почему бы просто не использовать diff?

Практично: в большинстве случаев нам нужен собственный eol. Что значит нет eol=.... Это textне подразумевается, и его нужно указывать явно.

Концептуальный: текст против двоичного - фундаментальное различие. eol, encoding, diff и т. д. - это лишь некоторые его аспекты.

Отказ от ответственности

Из-за странных времен, в которых мы живем, у меня нет машины с текущим работающим git. Поэтому в настоящий момент я не могу проверить последнее добавление. Если кто что-то не так, поправлю / удалю.


Чтобы мой файл UTF-16LE-BOM работал, мне пришлось использовать*.vmc diff working-tree-encoding=UTF-16LE-BOM eol=CRLF
HackSlash

@HackSlash: Спасибо за предупреждение. Я полагаю, вы говорите, что в textодиночестве у вас не было хороших текстовых различий? Не могли бы вы проверить это с обоими, text и diffвсе работает нормально? В таком случае я дам другую рекомендацию
Руси

Одно textтолько правильное приводит к двоичному сравнению. Я могу это сделать, diffили text diffэто работает. Мне нужно было добавить -BOMпросто потому, что у моего файла была спецификация YMMV.
HackSlash

@HackSlash Я учел ваш вывод. Было бы здорово, если бы вы могли это проверить!
Rusi

Спасибо @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.