将一个Subversion代码库项目拆分成两个Git代码库

4

我有一个Subversion服务器,其中有几个不同的项目,采用标准布局,如下所示:

ProjectA/
    trunk/
    branches/
    tags/
ProjectB/
    trunk/
        FolderOfBinaries/
        SourceFolderA/
        SourceFolderB/
        SourceFolderC/
    branches/
    tags/
        v1.0/
        v1.1/
        v2.0/
ProjectC/
    trunk/
    branches/
    tags/

ProjectB将要迁移到Git,但不是使用标准的克隆方式。我想把项目分成两个Git仓库 - 一个用于存放变化相对频繁的大型二进制文件夹,另一个用于存放其他所有内容。我已经完整地克隆了该仓库,它有几GB大小,但二进制文件夹可能占据了其中90%,并且运行git gc需要很长时间。如果开发人员需要,我宁愿拥有一个小而快速的仓库,然后将二进制文件夹作为子模块添加到其中。

到目前为止,我找到了两个潜在的选项。首先,我可以像Git Book中所示使用git branch-filter尝试从历史记录中删除二进制文件夹。其次,我可以使用svndumpfilter将当前的Subversion仓库分成两个部分,然后分别使用git svn clone

我的问题是,所有的历史记录,特别是分支和标签,会发生什么?即使在两个标签之间二进制文件夹可能没有发生变化,我仍然想知道该文件夹在每个标签中是什么样子的。这是否可能?

编辑:二进制文件夹不是构建工件(*.class,*.o,*.dll等),因此我不能仅剥离它并将其作为外部文件。它充满了需要进行版本控制的第三方程序输出的二进制文件(例如OpenOffice文档,Photoshop文件等)。

3个回答

1
我建议首先使用svndumpfilter将ProjectB拆分成两个仓库。然后,您可以使用git svn clone将新的SVN仓库转换为GIT仓库。
svndumpfilter--include模式考虑到主干、分支和标签文件夹时,拆分仓库的完整历史记录将被保留。因此,您可以在新的二进制仓库中查看FolderOfBinaries的所有历史记录。
使用git svn clone创建GIT仓库时,branches文件夹的内容将被转换为GIT分支,tags文件夹的内容将被转换为GIT标签。

1

看一下svndumpfilter吧。它非常简单易用。你需要先导出Subversion版本库的Dump文件,然后使用该工具对数据进行筛选,可以选择需要的内容或者排除不需要的内容。

通过导出当前版本库的Dump文件,运行两次 svndumpfilter——每个Git版本库运行一次。你可以链式地执行它们,只需为每个Git版本库两次运行即可。

$ svndumpfilter include ProjectB < svn_repo_dump | svndumpfilter exclude ProjectB/trunk/folderofbinaries > svn_repos_no_binaries

我想提醒一件事:不要在代码库中存储已构建的二进制对象。在Subversion中,它们无法被删除,除非进行转储和过滤,即使在具有消除版本能力的版本控制系统中,这样做也需要大量的时间和精力。这是一个巨大的维护难题。
而且为什么要这样做呢?在版本控制系统中存储二进制文件并没有真正帮助到你。你不能对二进制文件进行比较,历史记录也没有用处,而且非开发人员很难访问。
相反,使用发布存储库,并将您的二进制文件存储在那里。即使您不使用Maven或甚至不使用Java,您也可以使用像Artifactory或Nexus这样的Maven存储库。

如果将二进制文件夹剥离出仓库,标记和分支会发生什么?我需要在两个仓库中保留所有标记。我也需要更新标记,以便如果标记A和B之间的二进制部分没有变化(但源文件有变化),则两个标记现在应该指向相同的修订版本。 - Adam Rodger
@AdamRodger 在 --include--exclude 参数中也要包括 branches 和 tags 目录。我没有包括它们,因为我不想让语法变得过于复杂。您可以使用 svn2git 的参数来指定标签和分支目录的位置。 - David W.

1

好的,我已经成功完成了这个任务,但并不是那么简单明了。也许有更好的方法,但我自己没能找到。我按照以下步骤进行:

  1. 创建当前仓库的转储文件:svnadmin dump /opt/repo > full_dump

  2. 过滤掉转储文件中的二进制文件夹:svndumpfilter exclude *folderofbinaries* --pattern --renumber-revs --drop-empty-revs < full_dump > filtered_dump。我需要将folderofbinaries设置为一个模式,因为在过去的某个时候,有人直接将二进制文件检入了标签中,所以下一步由于缺少文件夹而失败。

  3. 使用过滤后的转储文件创建本地 SVN 仓库: mkdir repo-filtered; svnadmin create repo-filtered; svnadmin load repo-filtered < filtered_dump

  4. 将完整仓库和过滤后的仓库克隆到不同的文件夹中(我使用了svn2git)。过滤后的仓库将不包含任何二进制文件。如果在完整仓库中,只有二进制文件夹在标签 A 和 B 之间发生了变化,在新的过滤 Git 仓库中,这两个标签将指向相同的提交,这正是我想要的。

  5. 在完整 Git 仓库中,使用 Git 命令除了二进制文件夹以外的所有内容。

我不得不使用Git来隔离二进制文件夹的原因是,我无法弄清楚如何仅使用svndumpfilter维护标签(特别是考虑到我直接将二进制文件提交到标签中)。转换后,我获得了与过滤后的存储库相同的行为 - 如果两个标签之间没有二进制文件发生变化,则它们都指向相同的提交。
最后一步的命令如下:
git checkout master
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter folderofbinaries -- --all
git reset --hard
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --prune=now

我从这个问题中得到了这个答案。

现在我有一个80MB的源代码仓库和一个1.5GB的二进制文件仓库,它们都来自于我的原始4.4GB SVN转储文件!我可以通过将二进制文件夹作为Git子模块添加到源代码仓库中,并在每个仓库上检出相同的标签(这就是为什么我需要保留所有标签信息)来重新创建原始SVN仓库的确切状态,同时不会拥有一个庞大的Git仓库,这样工作起来就不会很慢。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接