Подтвердить что ты не робот

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

У меня есть репозиторий git с двумя каталогами и несколькими ветвями, я хочу разбить их и создать все ветки

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

Branches : branch1, branch2, branch3 ...

Что я хочу

Я хочу разделить dir1 и dirt как два отдельных repos и сохранить ветки 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.

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

Любые идеи???

4b9b3361

Ответ 1

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

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

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

Walkthrough

Ниже приведен пример безопасного выполнения этого. Вам нужно выполнить это для каждого подкаталога, который будет изолирован от своего собственного репо, в этом случае 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

Наконец, запустите команду filter-branch. Это создаст новые коммиты со всеми коммитами, которые касаются подкаталога 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-журналы. Если вы хотите отбросить данные, прочитанные как собирать мусор, комментирует.

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

Ответ 2

Этот script выполняет эту работу для меня:

#!/bin/bash

set -e

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

repoDir=$1
folder=$2
newOrigin=$3

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