Разделить большой хранилище Git на многие более мелкие

После успешной конвертации SVN-репозитория в Git у меня теперь есть очень большой репозиторий Git, который я хочу разбить на несколько меньших репозиториев и сохранить историю.

Итак, может кто-то помочь с разбивкой репо, которое может выглядеть так:

MyHugeRepo/
   .git/
   DIR_A/
   DIR_B/
   DIR_1/
   DIR_2/

В два репозитория, которые выглядят следующим образом:

MyABRepo/
   .git
   DIR_A/
   DIR_B/

My12Repo/
   .git
   DIR_1/
   DIR_2/

Я пробовал следующие указания в этом предыдущем вопросе, но это не очень подходит при попытке поместить несколько каталогов в отдельный репозиторий (подкаталог Detach (move) в отдельный Git репозиторий).

Ответы

Ответ 1

Это установит MyABRepo; вы тоже можете сделать My12Repo, конечно.

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch --prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 

Относится ссылка на .git/refs/original/refs/heads/master. Вы можете удалить это с помощью:

cd ..
git clone MyABRepo.tmp MyABRepo

Если все пойдет хорошо, вы можете удалить MyABRepo.tmp.


Если по какой-то причине вы получите сообщение об ошибке .git-rewrite, вы можете попробовать следующее:

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-branch -d /tmp/git-rewrite.tmp --prune-empty --index-filter 'git rm --cached --ignore-unmatch DIR_1/* DIR_2/*' HEAD 
cd ..
git clone MyABRepo.tmp MyABRepo

Это создаст и использует /tmp/ git-rewrite.tmp в качестве временного каталога вместо .git-rewrite. Естественно, вы можете заменить любой путь, а не /tmp/git-rewrite.tmp, если у вас есть разрешение на запись, а каталог еще не существует.

Ответ 2

Вы можете использовать git filter-branch --index-filter с git rm --cached для удаления нежелательных каталогов из клонов/копий исходного хранилища.

Например:

trim_repo() { : trim_repo src dst dir-to-trim-out...
  : uses printf %q: needs bash, zsh, or maybe ksh
  git clone "$1" "$2" &&
  (
    cd "$2" &&
    shift 2 &&

    : mirror original branches &&
    git checkout HEAD~0 2>/dev/null &&
    d=$(printf ' %q' "[email protected]") &&
    git for-each-ref --shell --format='
      o=%(refname:short) b=${o#origin/} &&
      if test -n "$b" && test "$b" != HEAD; then 
        git branch --force --no-track "$b" "$o"
      fi
    ' refs/remotes/origin/ | sh -e &&
    git checkout - &&
    git remote rm origin &&

    : do the filtering &&
    git filter-branch \
      --index-filter 'git rm --ignore-unmatch --cached -r -- '"$d" \
      --tag-name-filter cat \
      --prune-empty \
      -- --all
  )
}
trim_repo MyHugeRepo MyABRepo DIR_1 DIR_2
trim_repo MyHugeRepo My12Repo DIR_A DIR_B

Вам нужно будет вручную удалить все репозитории ненужных ветвей или тегов (например, если у вас есть ветка feature-x-for-AB, то вы, вероятно, захотите удалить ее из репозитория "12" ).

Ответ 4

Проект git_split - это простой script, который делает именно то, что вы ищете. https://github.com/vangorra/git_split

Поверните каталоги git в свои собственные репозитории в своем собственном расположении. Нет поддерева смешного дела. Этот script будет использовать существующий каталог в вашем репозитории git и превратить этот каталог в самостоятельный собственный репозиторий. По пути он скопирует всю историю изменений для предоставленного вами каталога.

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
        src_repo  - The source repo to pull from.
        src_branch - The branch of the source repo to pull from. (usually master)
        relative_dir_path   - Relative path of the directory in the source repo to split.
        dest_repo - The repo to push to.

Ответ 5

Спасибо за ваши ответы, но в итоге я просто копировал репозиторий дважды, а затем удалял файлы, которые я не хотел от них. Я собираюсь использовать ветвь фильтра позже, чтобы вычеркнуть все коммиты для удаленных файлов, так как они уже контролируются версией в другом месте.

cp -R MyHugeRepo MyABRepo
cp -R MyHugeRepo My12Repo

cd MyABRepo/
rm -Rf DIR_1/ DIR_2/
git add -A
git commit -a

Это работало на то, что мне нужно.

EDIT: Конечно, то же самое было сделано в My12Repo против каталога A и B. Это дало мне два репозитория с одинаковой историей вплоть до того, что я удалил нежелательные каталоги.