如何将 SVN 转换为 GIT,同时将一个巨大的存储库拆分为单独的存储库?
How can I convert SVN to GIT while splitting one huge repository into separate repositories?
我想将我们的 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
如果你的项目被整齐地分成它们自己的子目录,这应该是非常简单的使用 --trunk
parameter 到 git svn init
/git svn clone
:
git svn clone --trunk=Solution1 $SVN_URI ./Solution1
这会将子文件夹 Solution1
的唯一历史克隆到目录 ./Solution1
中的新 git 存储库中。它将只包含涉及该子文件夹中文件的提交,并且它会调整相对路径,以便该子文件夹是新 git 存储库的根目录。
虽然@acran 给出的答案确实解决了问题,但也可以先将 SVN 存储库转换为 Git,然后将大的 monorepo 拆分为多个较小的存储库。
1。将 SVN 转换为 Git
如果您的 SVN 存储库具有标准布局(子目录 branches
、tags
和 trunk
)并且您不需要任何其他附加功能,这很容易:
$ 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. When I did this a few years ago, I used git filter-branch
, but this tool is now deprecated – you may still use it, or you may use git filer-repo
,尽管我没有使用此工具的任何经验。
我链接的问题的最受支持的答案使用 git subtree filter
– 我建议 不要 使用这个答案,因为 git subtree filter
只转换一个分支,实际上从您的子存储库中删除所有其他分支。
优势
与通过 git svn clone
转换每个子存储库相比,此答案的优势是什么?
- 您只需克隆 SVN 存储库一次。这可能比为每个项目克隆子文件夹更快(虽然我没有测试过,这只是一个有根据的猜测)。
- 克隆具有标准布局的 SVN 存储库比克隆具有非标准布局的 SVN 存储库经过更好的测试。根据我的经验,
git svn
并不总是按照您的意愿行事,因此更标准的用法可能更有可能产生您想要的结果。
- 如果您想重写新 Git 存储库的历史记录(例如,删除大型二进制文件),您可以在第一步和第二步之间重写 monorepo 的历史记录。为每个新的子存储库执行此操作将需要更大的努力。
我想将我们的 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
如果你的项目被整齐地分成它们自己的子目录,这应该是非常简单的使用 --trunk
parameter 到 git svn init
/git svn clone
:
git svn clone --trunk=Solution1 $SVN_URI ./Solution1
这会将子文件夹 Solution1
的唯一历史克隆到目录 ./Solution1
中的新 git 存储库中。它将只包含涉及该子文件夹中文件的提交,并且它会调整相对路径,以便该子文件夹是新 git 存储库的根目录。
虽然@acran 给出的答案确实解决了问题,但也可以先将 SVN 存储库转换为 Git,然后将大的 monorepo 拆分为多个较小的存储库。
1。将 SVN 转换为 Git
如果您的 SVN 存储库具有标准布局(子目录 branches
、tags
和 trunk
)并且您不需要任何其他附加功能,这很容易:
$ 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. When I did this a few years ago, I used git filter-branch
, but this tool is now deprecated – you may still use it, or you may use git filer-repo
,尽管我没有使用此工具的任何经验。
我链接的问题的最受支持的答案使用 git subtree filter
– 我建议 不要 使用这个答案,因为 git subtree filter
只转换一个分支,实际上从您的子存储库中删除所有其他分支。
优势
与通过 git svn clone
转换每个子存储库相比,此答案的优势是什么?
- 您只需克隆 SVN 存储库一次。这可能比为每个项目克隆子文件夹更快(虽然我没有测试过,这只是一个有根据的猜测)。
- 克隆具有标准布局的 SVN 存储库比克隆具有非标准布局的 SVN 存储库经过更好的测试。根据我的经验,
git svn
并不总是按照您的意愿行事,因此更标准的用法可能更有可能产生您想要的结果。 - 如果您想重写新 Git 存储库的历史记录(例如,删除大型二进制文件),您可以在第一步和第二步之间重写 monorepo 的历史记录。为每个新的子存储库执行此操作将需要更大的努力。