- PVSM.RU - https://www.pvsm.ru -
Привет. В силу специфики, на работе используется Linux с KOI8-R, все коммиты в git репозиторий осуществлялись в локальной кодировке. Через некоторое время было принято решение перекодировать репозиторий в UTF-8. В этой статье я хочу обсудить технологию изменения кодировки существующего 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
можно прочитать здесь [1]
Итак, мы подошли к основной теме данной статьи. Для того, что бы «переписать историю» имеющегося репозитория используется команда 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'
Команда 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 репозитория. Обо всех ее возможностях можно прочитать здесь [2]:
Автор: Distress
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/git/33114
Ссылки в тексте:
[1] здесь: https://www.kernel.org/pub/software/scm/git/docs/git-log.html
[2] здесь: https://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html
[3] Источник: http://habrahabr.ru/post/178069/
Нажмите здесь для печати.