Как стать автором
Обновить

Комментарии 23

Если вам нужно перенести все 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 даёт затянуть всё сразу:


  1. В new-repo делаете git checkout -b xxx-temporary-branch-xxx — вам нужна ветка, которой нет нигде, чтобы git не вопил, что он не может затянуть что‐то в текущую ветку.
  2. git fetch path/to/movement-example '*:*': затягиваете всё, но ничего не переименовывается.
  3. git checkout master: чтобы удалить ветку нужно перейти куда‐то ещё, не важно куда
  4. git branch -D xxx-temporary-branch-xxx
  5. 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 из имеющегося.

С таким же успехом можно просто через github UI сделать то же самое – полная копия. Мне нужна одна конкретная папка

Какая ещё полная копия?! После filter-branch там уже только нужные коммиты. Или вы думаете, что изменения в ветке master магическим образом изменятся во время pull, из‐за чего мой вариант не эквивалентен использованию промежуточного репозитория?

Хотя одну вещь в моих советах нужно изменить: везде, где одна команда с '*:*' нужно использовать две: 'refs/heads/*:refs/heads/*' и 'refs/tags/*:refs/tags/*'. Иначе получите дополнительно всю оригинальную историю, т.к. filter-branch сохраняет её в refs/original.

Да, спасибо – это оптимальнее будет. Я попробую это все и обновлю пост

Серьёзно думаю над обратным процессом. Как-то не стрельнула идея в SOA-приложении выделить каждый сервис в отдельный репозиторий, объединив их через submodule.

Попробуйте такой подход: https://habrahabr.ru/post/326132/#comment_10165486

Зависимые сервисы смогут пользоваться маленькими пакетами с кусочками вашего кода, а вы сможете коммитить в монолит.

Если нужно слить проекты в один монолитный репозиторий, может помочь моя давнишняя статья. Если предварительно потренироваться на кошках фейковых репозиториях или клонах, то всё достаточно просто получается.

Спасибо, нужная вещь. Ну и раз уж пошла тема спрошу свое, может подскажет кто.
Не так давно хотелось сделать в репе submodule, но что бы в него затягивался не весь целевой репозиторий, а одна папка, к примеру include из большого С/С++ проекта, пусть только в read-only, но с сохранением возможности обновления как обычный submodule. Возможно ли такое?
Гит в такое не играет, смотрите ниже как можно выкрутиться.
Git Subsplit

# 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 как пакет, автоматически вырезаемый из основного (наряду с другими)
Не раскрыта тема куда девается передвигаемая папка из первоначального репозитория. — Удаляется?
Нет, с ней ничего не происходит – остается на месте :)

А что с ней станет? С клоном же работаете, push в origin не просто не делается — origin вообще удалён на третьем шаге.

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.