git разделение репозитория по подпапкам и сохранение всех старых ветвей

у меня есть git repo с 2 каталогами и несколькими ветвями, я хочу разделить их и создать все ветви

`-- Big-repo
    |-- dir1
    `-- dir2

Branches : branch1, branch2, branch3 ...

что я хочу!--8-->

Я хочу разделить dir1 и dir2 как два отдельных репозитория и сохранить ветви branch1, branch2 ... в обоих репозиториях.

dir1
Branches : branch1, branch2, branch3 ...

dir2
Branches : branch1, branch2, branch3 ...

что я пробовал:

Я могу разделить их на 2 РЕПО, используя

git subtree split -P dir1 -b dir1-only 
git subtree split -P dir2 -b dir2-only 

но, он не создает никаких ветвей после разделение.

всех подразделений:

git checkout branch1 (in Big-repo)
git subtree split -p dir1 -b dir1-branch1

git checkout branch2 (in Big-repo)
git subtree split -p dir1 -b dir1-branch2

And push these branches to newly created repo.

это требует больше ручного усилия, и я уверен, что может быть быстрый способ достичь этого?

какие идеи???

2 ответов


короткий ответ:

git filter-branch предоставляет именно ту функциональность, которую вы хотите. С вы можете создать новый набор коммитов, где содержание subDirectory находятся в корне каталога.

git filter-branch --prune-empty --subdirectory-filter subDirectory -- --branches

прохождение

ниже приведен пример, чтобы выполнить это безопасным способом. Вы должны выполнить это для каждого подкаталога, который будет изолирован в свое собственное РЕПО, в этом случае dir1.

первый клонируйте свой репозиторий, чтобы изолировать изменения:

git clone yourRemote dir1Clone
cd dir1Clone

чтобы подготовить клонированный репозиторий, мы воссоздадим все удаленные ветви как локальные. Мы пропускаем тот, который начинается с * так как это текущая ветвь, которая в этом случае будет читать (no branch) так как мы находимся в безголовом состоянии:

# move to a headless state
# in order to delete all branches without issues
git checkout --detach

# delete all branches
git branch | grep --invert-match "*" | xargs git branch -D

чтобы воссоздать все удаленные ветви локально, мы проходим через результаты git branch --remotes. Мы пропускаем те, которые содержат -> так как это не ветви:

# get all local branches for remote
git branch --remotes --no-color | grep --invert-match "\->" | while read remote; do
    git checkout --track "$remote"
done

# remove remote and remote branches
git remote remove origin

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

# Isolate dir1 and recreate branches
# --prune-empty removes all commits that do not modify dir1
# -- --all updates all existing references, which is all existing branches
git filter-branch --prune-empty --subdirectory-filter dir1 -- --all

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

в качестве дополнительного последнего шага, если вы заботитесь о размере репозитория:

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

дополнительные ресурсы:


этот скрипт делает всю работу за меня:

#!/bin/bash

set -e

if [ -z "" ]; then
        echo "usage:  /full/path/to/repository path/to/splitfolder/from/repository/root new_origin"
        exit
fi

repoDir=
folder=
newOrigin=

cd $repoDir

git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D

for remote in `git branch --remotes | grep --invert-match "\->"`
do
        git checkout --track $remote
        git add -vA *
        git commit -vam "Changes from $remote" || true
done

git remote remove origin
git filter-branch --prune-empty --subdirectory-filter $folder -- --all

#prune old objects
rm -rf .git/refs/original/*
git reflog expire --all --expire-unreachable=0
git repack -A -d
git prune

#upload to new remote
git remote add origin $newOrigin
git push origin master

for branch in `git branch | grep -v '\*'`
do
        git push origin $branch
done