Привет. В силу специфики, на работе используется Linux с KOI8-R, все коммиты в git репозиторий осуществлялись в локальной кодировке. Через некоторое время было принято решение перекодировать репозиторий в UTF-8. В этой статье я хочу обсудить технологию изменения кодировки существующего git репозитория, а заодно и исправления некоторых ошибок допущенных в определенных коммитах.
Фактически, будет создан новый репозиторий, соответственно перед проведением процедуры необходимо приостановить текущую разработку, слить все изменения в условно центральный репозиторий, в котором мы и будем производить перекодировку. После проверки полученного репозитория, необходимо будет повторно склонировать его на все машины.
Git оперирует бинарными данными, поэтому с кодировкой файлов он никак не взаимодействует, что касается комментариев коммитов, то он также сохраняет их в том виде, котором мы ему их передали, но при этом для каждого коммита заполняется заголовок
Для настройки существуют два параметра находящиеся в секции [i18n]:
Первый из них как раз задает содержание заголовка encoding для команд
Из-за этого могут возникать различные ошибки – например, если в коммитах заголовок
Для того, чтобы посмотреть значение заголовка
Подробнее о возможностях команды
Итак, мы подошли к основной теме данной статьи. Для того, что бы «переписать историю» имеющегося репозитория используется команда
В данной статье используются три фильтра:
После каждого фильтра задается команда, которую
Для того, что бы пройти по всему репозиторию, необходимо указать параметр
Прежде чем менять кодировку комментариев, не забываем задать правильное значение директивы
Для конвертации кодировки комментария используем следующую команду:
Команда
Поскольку операция по «переписыванию истории” достаточно грубо вмешивается в рабочий процесс, имеет смысл (если вы все-таки решились ее произвести) попытаться исправить максимальное количество ошибок. Это могут быть неправильно заданные параметры окружения, сохраненные в репозитории файлы, которых там быть не должно, кодировка или часть данных отдельных файлов и т.д.
В частности, я обнаружил что у пары коммитов был неверно задан e-mail автора. Поскольку на тот момент все коммиты были созданы мной, проблема решилась просто перезаписью этого параметра во всех коммитах:
Но естественно никто не мешает использовать более сложные конструкции с различными условиями и т.д.
В целом, команда
Предупреждение
Фактически, будет создан новый репозиторий, соответственно перед проведением процедуры необходимо приостановить текущую разработку, слить все изменения в условно центральный репозиторий, в котором мы и будем производить перекодировку. После проверки полученного репозитория, необходимо будет повторно склонировать его на все машины.
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 репозитория. Обо всех ее возможностях можно прочитать здесь.