Выделение подпроекта в отдельный репозиторий на github
Недавно я столкнулся с задачей переноса папки с проектом из одного репозитория в другой на github. Звучит примитивно, но если рассмотреть то, что дано и то, что необходимо получить, могут возникнуть некоторые нюансы.
Итак, что дано:
- Есть большой репозиторий, содержащий множество папок. Каждая папка — это отдельный проект.
Что необходимо сделать:
- Одну из папок перенести в отдельный репозиторий с сохранением ее истории коммитов.
В теории можно было бы просто скопировать весь репозиторий со всем содержимым в новое место, а потом просто удалить те папки, которые не нужны. Но такой способ довольно неоптимален и не особо мне понравился, так что я решил поступить иначе.
Я использовал стандартный гитовый filter-branch. За основу я взял следующие статьи:
- http://gbayer.com/development/moving-files-from-one-git-repository-to-another-preserving-history/
- https://help.github.com/articles/splitting-a-subfolder-out-into-a-new-repository/
В этом посте я хочу немного адаптировать процесс для лучшего восприятия.
Предположим для примера, что наш репозиторий называется movement-example, а та единственная папка, которую мы хотим перенести в отдельный репозиторий — folder-to-move. Тогда шаги, которые необходимо выполнить для подготовки переноса, выглядят следующим образом:
git clone git@github.com:/movement-example.git
Лучше сделать новый клон репозитория, даже если он у вас уже скачан.cd movement-examplegit remote rm origin
Это именно тот момент, ради которого мы делали новый клон — теперь мы не боимся поломать оригинальный репозиторий.git filter-branch --subdirectory-filter folder-to-move -- --all
После выполнения этого шага в вашем локальном репозитории останется только контент папкиfolder-to-move, причем самой папки больше нет — все содержащиеся в ней файлы теперь лежат в текущей директории (вmovement_example).mkdir folder-to-movemv * folder-to-move
Это опциональный шаг — если вы хотите иметь все файлы внутри той же папки, что и раньше, а не в корне нового репозитория.git add .git commit -m "Preparing to extract folder”
Первая часть готова, а вторая заключается в том, чтобы совершить фактический перенос. Предположим, что новый репозиторий называется просто new-repo, тогда необходимые шаги выглядят следующим образом:
git clone git@github.com:/new-repo.git
Клонируем себе новый репозиторий, если, конечно, все еще не сделали этого.cd new-repogit remote add old-repo-branch
Добавляем новый remote. Если ваши папки new-repo и movement-example лежат на одном уровне в файловой системе, тоpath-to-movement-example-folderвыглядел бы как../movement-examplegit pull old-repo-branch master
После выполнения этого шага цель будет практически достигнута — у вас уже будет весь контентfolder-to-moveв локальном репозиторииnew-repo, останется только сделать push. Но сначала нужно сделать кое-что еще.git remote rm old-repo-branch
Вам же больше не нужен второй remote, верно?git push origin master
Готово! Теперь в вашем новом репозитории есть только интересующая вас папка вместе со всей историей коммитов. Например, сразу после вышеописанных шагов я увидел следующее в своем новом репозитории: 
810 коммитов!
Кстати, вы увидите только 1 бранч — master. Процедура переносит только один бранч за раз. Если вы хотите перенести dev, то вам нужно просто сделать git checkout dev и git pull origin dev после второго шага на обоих этапах.
Если вам нужно перенести все 50 (60? 100?) бранчей, то данное решение не будет удачным из-за слишком большого количества рутинной работы. Но я считаю, что для переноса достаточно лишь сохранить master и dev бранчи, потому что все feature branches уже должны быть в dev, а новые бранчи вы будете ветвить уже в новом репозитории.
