Pull to refresh

Изменение кодировки git репозитория

Reading time 3 min
Views 11K
Привет. В силу специфики, на работе используется Linux с KOI8-R, все коммиты в git репозиторий осуществлялись в локальной кодировке. Через некоторое время было принято решение перекодировать репозиторий в UTF-8. В этой статье я хочу обсудить технологию изменения кодировки существующего git репозитория, а заодно и исправления некоторых ошибок допущенных в определенных коммитах.

Предупреждение


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

Git и кодировка


Git оперирует бинарными данными, поэтому с кодировкой файлов он никак не взаимодействует, что касается комментариев коммитов, то он также сохраняет их в том виде, котором мы ему их передали, но при этом для каждого коммита заполняется заголовок encoding, который в дальнейшем может быть использован при запросе комментариев. Если заголовок encoding пустой, git считает его равным UTF-8.

Для настройки существуют два параметра находящиеся в секции [i18n]:

[i18n]
        commitencoding = UTF-8
        logoutputencoding = KOI8-R

Первый из них как раз задает содержание заголовка encoding для команд git commit и git commit-tree, второй сообщает командам git log, git show, git blame в какую кодировку следует перекодировать текст комментария перед выводом пользователю. Если ни один из параметров не задан, git считает, что logoutputencoding равен UTF-8, однако, если установлен только первый параметр, git использует его значение и для второго.

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

Для того, чтобы посмотреть значение заголовка encoding комментариев, можно воспользоваться следующей командой:

git log –pretty=”%h - ‘%e’: %s”

Подробнее о возможностях команды git log можно прочитать здесь.

Git filter-branch


Итак, мы подошли к основной теме данной статьи. Для того, что бы «переписать историю» имеющегося репозитория используется команда git filter-branch. Она позволяет последовательно повторить все произведенные коммиты предварительно обработав файлы или мета-данные различными фильтрами.

В данной статье используются три фильтра:
  • --msg-filter – применяется для перезаписи текста комментария коммитов;
  • --env-filter – применяется, если необходимо изменить окружение, в котором был произведен коммит (имя автора, адрес электронной почты и т.д.);
  • --tag-name-filter – применяется для перезаписи текстов меток.

После каждого фильтра задается команда, которую git filter-branch выполнит перед записью коммита.

Для того, что бы пройти по всему репозиторию, необходимо указать параметр --all, отделив его дополнительным -- от фильтров, указать HEAD как цель и перезаписать метки (tags) согласно новым коммитам. Для этого, необходимо добавить фильтр tag-name с командой cat:

git filter-branch <фильтры> --tag-name-filter 'cat' -- --all HEAD

Прежде чем менять кодировку комментариев, не забываем задать правильное значение директивы i18n.commitencoding – именно оно будет записано во всех заголовках полученного после выполнения операции репозитория.

Для конвертации кодировки комментария используем следующую команду:

'iconv -c -s -f KOI8-R -t UTF-8'

  • s – silent mode;
  • с – пропускать символы, которые не удается преобразовать.

Команда git filter-branch принимает следующий вид:

git filter-branch --msg-filter 'iconv -c -s -f KOI8-R -t UTF-8' \
--tag-name-filter 'cat' -- --all HEAD

Поскольку операция по «переписыванию истории” достаточно грубо вмешивается в рабочий процесс, имеет смысл (если вы все-таки решились ее произвести) попытаться исправить максимальное количество ошибок. Это могут быть неправильно заданные параметры окружения, сохраненные в репозитории файлы, которых там быть не должно, кодировка или часть данных отдельных файлов и т.д.

В частности, я обнаружил что у пары коммитов был неверно задан e-mail автора. Поскольку на тот момент все коммиты были созданы мной, проблема решилась просто перезаписью этого параметра во всех коммитах:

git filter-branch --msg-filter 'iconv -c -s -f KOI8-R -t UTF-8' \
--env-filter 'export GIT_AUTHOR_EMAIL="xxx@gmail.com" export GIT_COMMITTER_EMAIL="xxx@gmail.com"' \
--tag-name-filter 'cat' -- --all HEAD

Но естественно никто не мешает использовать более сложные конструкции с различными условиями и т.д.

В целом, команда git filter-branch предоставляет очень богатый функционал для модификации/исправления git репозитория. Обо всех ее возможностях можно прочитать здесь.
Tags:
Hubs:
+11
Comments 3
Comments Comments 3

Articles