如何在将一个巨大的存储库拆分为单独的存储库时将 SVN 转换为 GIT?

Posted

技术标签:

【中文标题】如何在将一个巨大的存储库拆分为单独的存储库时将 SVN 转换为 GIT?【英文标题】:How can I convert SVN to GIT while splitting one huge repository into separate repositories? 【发布时间】:2021-10-04 11:42:24 【问题描述】:

我想将我们的 SVN 存储库迁移到 git

我们当前的存储库是一个巨大的单例堆,包含许多 Visual Studio 解决方案,所有解决方案都位于存储库的单独子目录中。

将其转换为 git 时,我想将 SVN 存储库拆分为每个解决方案的单独 git 存储库,同时维护每个解决方案的历史记录。

我不希望在我们所有未来的git 存储库中保留整个 SVN 存储库的历史记录。在这些未来的git 存储库中,我想要的只是特定子目录的历史记录。

这可能吗?


当前 SVN 存储库文件结构:

svn_base
   |-- Solution1
   |   |-- 1.cs
   |   |-- 1.csproj
   |   |-- 1.sln
   |-- Solution1
   |   |-- 2.cs
   |   |-- 2.csproj
   |   |-- 2.sln
   |-- Solution3
   |   |-- 3.cs
   |   |-- 3.csproj
   |   |-- 3.sln

所需的git 存储库文件结构:

Solution1
   |-- .git
   |-- 1.cs
   |-- 1.csproj
   |-- 1.sln

Solution2
   |-- .git
   |-- 2.cs
   |-- 2.csproj
   |-- 2.sln


Solution3
   |-- .git
   |-- 3.cs
   |-- 3.csproj
   |-- 3.sln

【问题讨论】:

使用 git-svn,您可以告诉它主干在哪里(也是您保存分支/标签的目录),因此将每个项目分成自己的单独 git 存储库应该没有问题。 你也可以先convert SVN to Git,然后split your history in different repositories。 我不确定该工具在将 SVN 转换为 Git 并在那里拆分方面有多好 - 也许它很棒。但我知道新的 git-filter-repo 工具很棒,所以如果是我,我会选择 @sk_pleasant-EliasHolzmann 的建议,先将 SVN 转换为一个大的 Git 存储库,然后使用 git-filter-repo 其余的. 作为旁注,在不了解您的代码库的情况下,我的直觉是每个 repo 的一个解决方案对于 repo 来说可能有点细化。您没有说明为什么要拆分,但是除非每个都太大,或者您的分类限制某些人查看某些代码,否则我可能会将其留在一个仓库中,直到我有充分的理由拆分出来。 (也许你会。) @sk_pleasant-EliasHolzmann:很好的提示!我尝试了一个示例存储库,git subtree 就像一个魅力。 (不幸的是,这个命令的手册页似乎不见了。) - 如果你想发表你的评论作为答案,我很乐意投票。 【参考方案1】:

虽然@acran 给出的答案确实解决了这个问题,但首先将 SVN 存储库转换为 Git,然后将大型 monorepo 拆分为多个较小的存储库也是可能的,有时也是有利的。

1. SVN转Git

如果您的 SVN 存储库具有标准布局(子目录 branchestagstrunk)并且您不需要任何其他花里胡哨,这很容易:

$ git svn clone <url_to_subversion_repo>

这个命令有两个陷阱:

    git svn 使用 SVN 登录作为 Git 作者姓名。它还使用一些默认邮件地址(@localhost,我认为,虽然我不确定)。如果这不是您想要的,您可以使用作者文件。添加文件user_mapping.txt 映射SVN用户到git用户:
    svn_user_1 = Git User 1 <user1@example.com>
    svn_user_2 = Git User 2 <user2@example.com>
    
    然后用这个文件调用git svn clone
    $ git svn clone --authors-file=user_mapping.txt <url_to_subversion_repo>
    
    由于 SVN 标签可以更改,git svn 将它们作为 Git 分支导入。 If you want, you can convert them。

git svn clone 按顺序从 SVN 服务器检查您的 SVN 存储库的每个修订版 - 如果您有一个大存储库,这将需要一段时间(我的经验是大约 50,000 次修订需要几个小时,虽然我是不确定,这是几年前的事了)。如果可能,您可能希望在 SVN 服务器上运行此命令,尤其是在连接速度较慢的情况下。不管怎样,去喝杯咖啡(或五杯)。

2.拆分 Git 存储库

有多种工具可以将 Git 存储库拆分为子存储库。参见例如this question。几年前我这样做的时候,我使用了git filter-branch,但是这个工具现在已经被弃用了——你可以继续使用它,或者你可以使用git filer-repo,尽管我没有使用这个工具的任何经验。

对我链接的问题的最赞成的答案使用git subtree filter - 我建议不要使用这个答案,因为git subtree filter 只转换一个分支,实际上从您的子存储库中删除所有其他分支.

优势

与通过git svn clone 转换每个子存储库相比,此答案有什么优势?

您只需克隆一次 SVN 存储库。这可能比为每个项目克隆子文件夹更快(虽然我没有测试过,这只是一个有根据的猜测)。 克隆具有标准布局的 SVN 存储库比克隆具有非标准布局的 SVN 存储库的测试效果更好。根据我的经验,git svn 并不总是按照您的意愿行事,因此更标准的用法可能更有可能产生您想要的结果。 如果您想重写新 Git 存储库的历史记录(例如,删除大的二进制文件),您可以在第一步和第二步之间重写 monorepo 的历史记录。为每个新的子存储库执行此操作会付出更大的努力。

【讨论】:

【参考方案2】:

如果您的项目被整齐地分隔到它们自己的子目录中,那么使用--trunk parameter 到git svn init/git svn clone 应该非常简单:

git svn clone --trunk=Solution1 $SVN_URI ./Solution1

这会将子文件夹Solution1 的唯一历史克隆到目录./Solution1 中的新git 存储库中。它只会包含涉及该子文件夹中文件的提交,并且会调整相对路径,使子文件夹成为新 git 存储库的根目录。

【讨论】:

很好的答案!我目前正在执行您的建议。在我投票之前等待结果。我应该注意 - 在 Windows 上 - 主干名称应该用正斜杠而不是反斜杠给出,即--trunk MySubDir/Solution1

以上是关于如何在将一个巨大的存储库拆分为单独的存储库时将 SVN 转换为 GIT?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Tortoisesvn 创建新的 SVN 存储库时如何设置存储库路径

如何在将照片上传到 Firebase 存储时将日期或时间等用户图像详细信息添加到文件名?

Jquery在解析时将巨大的数组拆分为许多新的回调

单独的 git 存储库中的服务结构项目

Gitlab Wiki - 导入存储库时如何导入 wiki

git 按子文件夹拆分存储库并保留所有旧分支