Завтра переписывал историю. Понравилось.
Напишу тут немного про git filter-branch потому, что ничего внятного ни на русском, ни на аглицком нагуглить не удалось. Повторять мои ошибки вам будет дороговато, так как более менее сложное отфильтровывание истории — штука скучная и затяжная.
Не забудьте забекапить папочку .git из вашего репозитория.
Раздвоение
Если у вас больше одного бранча (а как же иначе?), то, судя по названию команды, отфильтровать получится историю только текущего бранча. И вы получите раздвоение репозитория. А это значит, что лучше всего сначала смерджить все в мастер, и только потом начинать творить все эти противоестественные вещи. Даже больше. Если вы работате в команде (а как же иначе?), то важно всем все смерджить в свои мастеры, а потом смерджить все мастеры у кого-то одного, и только потом запускать git filter-branch на его компе. Иначе, получив новый репозиторий с абсолютно иными именами коммитов, вы замучаетесь мерджиться друг с другом. Еще хуже то, что новая история будет только у того, кто ее себе смастерил. Остальные перцы (включая боевые сервера, если вы храните на них репу целиком) получат из новой истории только последний комит, а впридачу всю его новую историю в качестве багажа.
Повторим. Сначала слейте все в один репозиторий, потом максимально упростите его структуру, а потом уже издевайтесь над ним. В случае, если не удается смердить все в мастер, запустите фильтр сначала в мастере, а потом в каждом из оставшихся бранчей. Чтобы не тратить время на переписывание тех коммитов, которые общие у мастера и у текущей ветки, воспользуйтесь опциями для выделения отрезка истории, описанными в руководстве. Мужайтесь.
После того, как вы перелопатили историю на одном из компьютеров, знайте, что это практически новый репозиторий. А это значит, что его надо всем заново склонировать (не забудьте про боевые и сборочные сервера). Чтобы быстрее заливалось, запустите git gc --aggressive, и гит аккуратненько уложит все объекты в один файл.
Редактируем авторов
Так как мы в Иншейкере на гит набросились, как голодные псы, никто, конечно, не удосужился сконфигурировать свои имя и мыло через git configure --global.
Чтобы исправить эту досадную ошибку и заменить логин в системе на свое имя, а кривой адрес — на прямой, запускайте:
git filter-branch --env-filter \
'
if [ "$GIT_AUTHOR_NAME" = "user123" ];
then
export GIT_AUTHOR_NAME="User Name"
fi
if [ "$GIT_AUTHOR_EMAIL" = "user123@host.local" ];
then
export GIT_AUTHOR_EMAIL="user@name.ru"
fi
'
Выбрасываем мусор
Как-то давно, мы решили хранить псдшники и видео в репозитории. Наверное заболели. Вот лекарство от файлов *.flv, *.mp3 и *.psd (нужное подчеркнуть):
git filter-branch --tree-filter 'find . \( -name "*.flv" -o -name "*.mp3" -o -name "*.psd" \) -exec rm -rf {} \;'
Если не получается
Повторно запускать фильтр гит откажется, предупреждая о том, что придется затереть бекап. Вылетит со словами «Cannot create a new backup. A previous backup already exists in refs/original/». Настоять на своем можно, указав ключ -f или вручную стерев папочку refs/original/. Кстати, да, всего несколько файликов в этой папочке и есть весь «бекап». Дело в том, что гит очень умный, и он не удалит старое пространство объектов, пока вы его явно об этом не попросите (git gc --prune=now). Именно поэтому, пока в папке refs/ есть ссылки на старое дерево, ничего не удалится. В общем, стандартный сборщик мусора, знакомый нам по яваскрипту.
Если вы переписывали историю для того, чтобы выбросить из нее мусор, а по окончании мучений репа стала даже чуть больше, не отчаивайтесь. Дело как раз в бекапе. Чтобы стопроцентно очистить репозиторий, надо склонировать этот репозиторий в другое место и запустить там git gc --prune=now. Не очень красиво, но так официально советуют делать.
Знаю по опыту, что гит ошарашивает своей гибкостью и многословием. Поэтому — спрашивайте, если что-то не получается. Было бы мне у кого спросить, замучал бы его совсем :)