Следуйте переименованию при выполнении git разделов поддерева

У меня есть несколько подкаталогов, которые я хочу вытащить в отдельное репо. Чтобы извлечь их с помощью одной команды, я перемещаю (переименовываю) их в один подкаталог внутри корня.

Затем я запускаю: git subtree split -P my_new_subdir -b newbranch

Если я затем проверил эту новую ветку и запустил git log --follow someoldfile, она только покажет мне записи журнала, относящиеся к переходу во временный подкаталог. Я хочу перенести всю историю этих файлов.

Есть ли способ сохранить полную историю, в том числе переименовывать при выполнении разделения поддерева? Есть ли еще один способ достижения желаемого результата?

Я рассмотрел использование ветки фильтра на клоне репо, но я знаю, что будет очень медленно.

Ответ 1

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

Если вы хотите просто оставить файлы с my_new_subdir, вам действительно нужно удалить все остальные файлы самостоятельно. Концепция заключается в использовании:

git filter-branch --tag-name-filter cat --index-filter \
  'git rm -r --cached --ignore-unmatch 
    unneeded-subdir-1 unneeded-pattern-* unneeded-etc' \
--prune-empty -f -- --all

затем, чтобы помочь найти, что еще нужно удалить, вы можете использовать sth как:

git log --name-status --all  | grep -P '^\w\s+[\S]+$'

или даже, например:

git log --name-status --all  | grep -P '^\w\s+[\S]+$' | \
  sed s/^.// | cut -f 1-2 -d '/' | sort -u

Таким образом вы можете найти все файлы/каталоги (или только первые два сегмента пути во втором случае), которые присутствовали в репо в любое время. После этого вы можете использовать следующую команду для очистки репо:

git gc --aggressive

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

Чтобы ускорить работу, вы можете определить самые большие части репо для удаления на первой итерации, затем выполните git gc --aggressive. Имея диск i5 и диск SSD, мне потребовалось около минуты, чтобы выполнить одну итерацию git filter-branch, и обработано около 1000 записей истории.