将大型Git存储库拆分为许多较小的存储库

时间:2010-10-11 22:32:57

标签: git split repository git-filter-branch

成功将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) subdirectory into separate Git repository)时,它并不适合。

6 个答案:

答案 0 :(得分:77)

这将设置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,只要您具有写入权限,并且该目录尚不存在。

答案 1 :(得分:10)

您可以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' "$@") &&
    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”存储库中删除它)。

答案 2 :(得分:5)

git_split项目是一个简单的脚本,可以完全满足您的需求。 https://github.com/vangorra/git_split

将git目录转换为自己位置的自己的存储库。没有子树有趣的业务。此脚本将获取您的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.

答案 3 :(得分:4)

这是一个可以执行此操作的ruby脚本。 https://gist.github.com/4341033

答案 4 :(得分:1)

感谢您的回答,但我最后只是复制了两次存储库,然后删除了我不想要的文件。我将在以后使用filter-branch来删除已删除文件的所有提交,因为它们已经在其他地方进行了版本控制。

cp -R MyHugeRepo MyABRepo
cp -R MyHugeRepo My12Repo

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

这适用于我需要的东西。

编辑:当然,在My12Repo中针对A和B目录完成了同样的事情。这给了我两个历史相同的回购,直到我删除了不需要的目录。

答案 5 :(得分:0)

虽然在问题出现时 utunbu 的回答是最好的,但现在连 git 本身都推荐 https://github.com/newren/git-filter-repo

它的速度要快几个数量级,而且相对来说非常容易使用

例如在这里你会做

git clone MyHugeRepo/ MyABRepo.tmp/
cd MyABRepo.tmp
git filter-repo --path DIR_A/ --path DIR_B/

您可以在 https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#EXAMPLES

查看更多示例