将大型Git repo强烈重组为多个新的回购

时间:2014-03-06 21:19:51

标签: git git-subtree git-filter-branch

我发现了几个使用filter-branch和subtree的简单例子,但它们总是只移动1个目录。我想采取以下回购:

/
  Project1.sln
  Project2.sln
  Source/
    CommonLib.Data/
    CommonLib.Web/
    Project1.Data/
    Project1.Web/
    Project1.Other/
    Project2.Data/
    Project2.Web/

将事情移到他们自己的回购中,具有以下结构:

# CommonRepo
/
  CommonLib.Data/
  CommonLib.Web/

# Project1Repo
/
  Project1.sln
  Project1.Data/
  Project1.Web/
  Project1.Other/

# Project2Repo
/
  Project2.sln
  Project2.Data/
  Project2.Web/

保持整个历史。更复杂的是,原始仓库中有一个或多个分支对应于每个项目,因此所引用的其他项目的CommonLib版本可能略有不同。

我想使用git子树添加在正确的标签/版本的每个新repos中添加一个引用回CommonLib,但首先我需要一种方法将一些目录一次性拆分到自己的位置

git subtree split -P似乎只想要一个目录,而且我也无法获得filter-branch来获取倍数。我在一个Windows框中,所以没有设置所有脚本细节,以使这更容易。

有什么建议吗?

3 个答案:

答案 0 :(得分:5)

最后,我建议您保留项目中包含的公共库,特别是由于您所说的不同,所以理想的结构应该是:

# CommonRepo
/
  CommonLib.Data/
  CommonLib.Web/

# Project1Repo
/
  Project1.sln
  Project1.Data/
  Project1.Web/
  Project1.Other/
  CommonLib/         # I recommend that you do whatever restructuring needed to support this in a sub-directory
    CommonLib.Data/
    CommonLib.Web/

# Project2Repo
/
  Project2.sln
  Project2.Data/
  Project2.Web/
  CommonLib/         # I recommend that you do whatever restructuring needed to support this in a sub-directory
    CommonLib.Data/
    CommonLib.Web/

现在处理拆分:

当你拆分时,只要你不使用不同的注释或什么东西,提交ID就会兼容,并且应该很好地与合并一起使用。因此,您可以先自己解压缩CommonLib。

  1. 我建议您在开始前克隆整个depo,以确保不会丢失任何东西。

    git clone <big-repo> <big-repo-clone>
    
  2. 准备旧的仓库

    pushd <big-repo-clone>
    # split for the common lib
    git checkout master  # assuming you want your common lib at master
    git subtree split --prefix=Source --branch=temp-commonLib
    
    # split the projects from their respective branches
    git checkout <branch-for-project1>
    git subtree split --prefix=Source --branch=temp-project1
    
    # split the projects from their respective branches
    git checkout <branch-for-project2>
    git subtree split --prefix=Source --branch=temp-project2
    
  3. 现在我们需要清理那些我们不想要的项目部分。由于它们混合在一起你不能真正使用子树,但你可以过滤分支来重写历史而不需要其他部分。

    # strip unrelated parts from the CommonLib
    git checkout temp-commonLib
    git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch Project1* Project2*' HEAD
    
    # strip unrelated parts from the Project1
    git checkout temp-project1
    git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch CommonLib* Project2*' HEAD
    
    # strip unrelated parts from the Project2
    git checkout temp-project2
    git filter-branch --tag-name-filter cat --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch CommonLib* Project1*' HEAD
    

    prune empty将删除变为空的提交,因为它们只包含您删除的文件夹中的更改。

    注意:所有这些更改都位于/ source级别,因此它可以是每个项目的新根。您可以稍后再添加您的解决方案。或者您可以将此修剪技术用于克隆而不是子树,当您完成所有操作后,您可以将所有内容从“/来源”移动到“/”

    现在,您将在refs/original/refs/heads/<branch-name>中拥有额外的分支和备份。如果在此过程中您遇到了filter-branch的致命错误,您可以重新创建分支并重新开始,或者如果您确信它没有执行任何操作,则可以使用以下命令删除此备份:git update-ref -d refs/original/refs/heads/<branch-name>

  4. 现在只需创建新的存储库来存储从这些分支创建的项目

    popd # to get out of <big-repo-clone>
    
    mkdir <new-repo>
    pushd <new-repo>
    
    git init
    git pull <big-repo-clone> <name-of-branch> # like temp-project1
    popd # to get out of the <new-repo>
    
  5. 最后,让我们将CommonRepo拉入项目中。

    pushd <new-project-repo>
    git subtree add --prefix=CommonLib <new-commonlib-repo>
    
  6. 然后你需要引入.sln文件(我会把这最后一步留给你)。

答案 1 :(得分:1)

我的程序git_filter可以为你做分组。我写它是因为我们的大型存储库上所有其他解决方案都很慢。它在这里:

https://github.com/slobobaby/git_filter

它为原始存储库的每个提取创建多个分支。目前我在这里有一个测试分支:

https://github.com/slobobaby/git_filter/tree/subdir

将创建一个新分支,其中包含原始存储库的子目录,并重命名为新的根目录。

与基于git-core的解决方案的小时或天相比,运行需要几分钟。

包含一个脚本,然后将这些新分支推送到新的干净存储库。

答案 2 :(得分:1)

对我而言,我不是试图弄清楚如何拆分回购的许多部分,而是更喜欢克隆原件,然后通过切掉我不想要的东西来削减它。然后在原版(或另一个克隆版)中,我将我分开的部分削减掉了。我发现它是一种更容易,更迭代的方法,可以更好地了解正在发生的事情。

请在此处查看我最近对此主题的回答:https://stackoverflow.com/a/22210682/955926

相关问题