Комментарии 25
Если вам нужно перенести все 50 (60? 100?) бранчей, то данное решение...
автоматизируется скриптом :)
git subtree push --prefix folder-to-move remote-name branch-name
не сделает то же самое?Могу порекомендовать тулзу BFG, она может удалять файлы из истории типа случайно закоммиченных паролей или просто огромных файлов, которые стали не нужны, но занимают место в истории. Она, к сожалению, не умеет выпиливать по правилу "все, кроме", но можно написать простенький скрипт, чтобы из git'а вытащить список всех файлов во всех бранчах, отсортировать, выбрав уникальные, вычеркнуть sed'ом те, которые планируется оставить, а потом скормить результат bfg.
А зачем в новом репозитории делать git remote add
+git remote rm
? Git спокойно принимает вместо названия remote значение, на которое это название ссылается.
К тому же, кажется, вы чего‐то накосячили при клонировании или pull’е: в документации filter-branch
ясно сказано, что -- --all
переписывает все тёги и ветки, вам нужно просто их все склонировать а потом так же все затянуть в новом репозитории, а не заниматься скриптописательством или рутинной работой.
И clone в первом шаге лучше делать локального репозитория — это быстрее, а git не будет что‐то в оригинале менять, хотя и воспользуется по возможности жёсткими ссылками. Ещё при желании можно cp -r
локальные клоны делать, хотя лучше не надо — притянет мусорные изменения. Но все ветки и тёги, с которыми вы работали будут на месте точно.
Хотя я вижу: вы точно накосячили при pull и push: тянете только master, явно. Git даёт затянуть всё сразу:
- В new-repo делаете
git checkout -b xxx-temporary-branch-xxx
— вам нужна ветка, которой нет нигде, чтобы git не вопил, что он не может затянуть что‐то в текущую ветку. git fetch path/to/movement-example '*:*'
: затягиваете всё, но ничего не переименовывается.git checkout master
: чтобы удалить ветку нужно перейти куда‐то ещё, не важно кудаgit branch -D xxx-temporary-branch-xxx
git push origin '*:*'
: отправляете всё, что затянули при fetch.
Если не ошибаюсь, то с голыми репозиториями (git clone --bare
) 1, 3 и 4 не нужны.
И вообще вы занимаетесь фигнёй: делайте git push 'git@github.com:<user_or_organization>/new-repo.git' '*:*'
прямо из movement-example. Новый клон не нужен, создавать remote не нужно, временная ветка не нужна, push’ити всё сразу; потом сделаете себе клон для работы уже с нужными изменениями или сделаете pull с github из имеющегося.
Какая ещё полная копия?! После filter-branch там уже только нужные коммиты. Или вы думаете, что изменения в ветке master магическим образом изменятся во время pull, из‐за чего мой вариант не эквивалентен использованию промежуточного репозитория?
Серьёзно думаю над обратным процессом. Как-то не стрельнула идея в SOA-приложении выделить каждый сервис в отдельный репозиторий, объединив их через submodule.
Не так давно хотелось сделать в репе submodule, но что бы в него затягивался не весь целевой репозиторий, а одна папка, к примеру include из большого С/С++ проекта, пусть только в read-only, но с сохранением возможности обновления как обычный submodule. Возможно ли такое?
# This utility uses `git-subsplit`. If you don't have one, run this:
# pusd /tmp/ && git clone git@github.com:dflydev/git-subsplit.git && cd git-subsplit && ./instal.sh && popd
#
# This utility also uses linux "parallel"
# To install a fresh version, run:
# Ubuntu:
# apt-get -y install bzip2 make && (wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
#
# MacOS:
# brew install parallel
git subsplit init git@github.com:your/big-project.git
modules_array=(
'your/subfolder/to/split:git@github.com:your/new_microservice.git',
'your/another/subfolder/to/split:git@github.com:your/other_microservice.git',
)
printf '%s\n' "${modules_array[@]}" | parallel "git subsplit publish --heads='master staging development' --no-tags"
rm -rf .subsplit/
Делаете other_microservice.git проектом с READ-ONLY доступом и можете спокойно коммитить в основной проект, запуская утилиту в CI-процессе автоматически. В --heads можно подставлять текущую ветку с помощью чего-то вроде
```$(git symbolic-ref --short HEAD)```
Пример аналогичного подхода: https://github.com/laravel/framework как основной код и https://github.com/illuminate/queue как пакет, автоматически вырезаемый из основного (наряду с другими)
Всю статью можно сократить до трех шагов:
Создать клон в соседнем каталоге
git clone --no-local . "../movement-example"
Перейти туда
cd "../movement-example"
Оставить только внутренности каталога folder-to-move
git filter-repo --subdirectory-filter "folder-to-move/"
А пакет filter-branch объявлен устаревшим и не рекомендуется к использованию.
Выделение подпроекта в отдельный репозиторий на github