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

Mik*_*keM 84 git split repository git-filter-branch

一个SVN仓库成功转换到Git的,我现在有一个我想分解成多个更小的存储库,并保持历史上的一个非常大的Git仓库.

那么,有人可以帮助拆分可能看起来像这样的回购:

MyHugeRepo/
   .git/
   DIR_A/
   DIR_B/
   DIR_1/
   DIR_2/
Run Code Online (Sandbox Code Playgroud)

进入两个看起来像这样的存储库:

MyABRepo/
   .git
   DIR_A/
   DIR_B/

My12Repo/
   .git
   DIR_1/
   DIR_2/
Run Code Online (Sandbox Code Playgroud)

我试过以下几个方向在此之前的问题,但它试图把多个目录到一个单独的回购协议(时并不真正适合拆离(移动)子目录成独立的Git仓库).

unu*_*tbu 78

这将设置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 
Run Code Online (Sandbox Code Playgroud)

对.git/refs/original/refs/heads/master的引用仍然存在.你可以删除它:

cd ..
git clone MyABRepo.tmp MyABRepo
Run Code Online (Sandbox Code Playgroud)

如果一切顺利,您可以删除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
Run Code Online (Sandbox Code Playgroud)

这将创建并使用/tmp/git-rewrite.tmp作为临时目录,而不是.git-rewrite.当然,/tmp/git-rewrite.tmp只要您具有写入权限,并且该目录尚不存在,您可以替换您希望的任何路径.

  • 我没有意识到“filter-branch”的全部后果。对于那些不知道的人,它会重写历史记录,因此如果您计划在完成此操作后推送存储库,那么提交哈希现在将有所不同,并且不会起作用。 (2认同)

Chr*_*sen 10

您可以使用git filter-branch --index-filterwith 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
Run Code Online (Sandbox Code Playgroud)

您需要手动删除每个存储库的不需要的分支或标记(例如,如果您有一个feature-x-for-AB分支,那么您可能希望从"12"存储库中删除它).

  • @Daenyth,`:`是一个传统的内置命令([也在POSIX中指定](http://www.opengroup.org/onlinepubs/009695399/utilities/colon.html)).它包含在*bash*中,但它不是评论.我特意使用它而不是`#`,因为并非所有shell都将`#`作为所有上下文中的注释介绍者(例如,启用了INTERACTIVE_COMMENTS选项时的interactive*zsh*).使用`:`使整个文本适合粘贴到任何交互式shell以及保存在脚本文件中. (4认同)

Unr*_*son 6

尽管在提出问题时 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/
Run Code Online (Sandbox Code Playgroud)

您可以在https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#EXAMPLES看到更多示例


van*_*rra 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.
Run Code Online (Sandbox Code Playgroud)