使用 SubGit 跨存储库重组将 svn 转换为 git

Convert svn to git across repository restructuring using SubGit

我正在使用 SubGit 2.0.3 将 Subversion 存储库迁移到 Git,同时尝试在重组过程中维护完整的历史记录。我有一个配置似乎可以在分支机构而不是主干的整个重组过程中维护历史记录。

重组本身有点...不寻常...并且涉及中间布局。

初始布局:

中间布局:

最终布局:

所以我用于转换的子git映射是:

trunk = ProjectNewName/trunk:refs/heads/master
branches = trunk/ProjectNewName:refs/heads/old-master-interim
branches = ProjectOldName:refs/heads/old-master
branches = ProjectNewName/branches/releases/*:refs/heads/releases/*
branches = releases/ProjectNewName/*:refs/heads/old-releases-interim/*
branches = ProjectOldName/Releases/*:refs/heads/old-releases/*
tags = ProjectNewName/tags/*:refs/tags/*
shelves = ProjectNewName/shelves/*:refs/shelves/*

这维护了发布分支的历史记录,一个文件的日志将超出重构的范围……尽管它似乎在创建分支时停止(发生在重构之前)。然而,master 上同一文件的历史记录在重组的最后一步创建时停止,并且预期的 'old-master-interim' 和 'old-master' 分支在 git 存储库中不存在。

看起来重组是使用 svn 副本完成的(即,他们没有手动复制文件并重新提交它们)并且最终布局的历史记录被正确保留。虽然创建了两次中间布局,但第一次尝试被删除,并带有一条注释,表明历史未保留。因此,尽我所能告诉重组提交链(对于主干):

类似,但发布分支略有不同:

唯一真正的区别似乎是 'Replace multiple directories' 发生在主干上而不是分支上的步骤。

毕竟:

Is there a way to get SubGit to convert the above while maintaining history across the restructuring for trunk?

当整个分支目录从一个位置复制到另一个位置时,SubGit 能够跟踪分支历史:

$ svn cp ^/trunk ^/branches/foo

但是,当某些分支子目录被复制时,无法跟踪历史:

$ svn add ^/branches/foo
$ svn cp ^/trunk/dir1 ^/branches/foo/dir1
$ svn cp ^/trunk/dir2 ^/branches/foo/dir2
...
$ svn cp ^/trunk/dirN ^/branches/foo/dirN

不幸的是,这是对 ProjectOldName/trunk/ProjectNewName[=94= 执行重构的方式] 个目录。结果 SubGit 无法为他们保留历史记录。

针对您的情况,一种可能的解决方法是将这些目录导入单独的分支,然后使用 git-replace.

将导入的片段移植到一个历史记录中

但是,此解决方法会导致下一个问题:

Can SubGit handle having branches under the trunk as in the original repository layout (ie. trunk at /OldProjectName, branches at /OldProjectName/Releases)?

不,在这种情况下,SubGit 会忽略 OldProjectName 目录。

我们是故意这样做的:如果 SubGit 会尝试导入 OldProjectName 目录,任何向 OldProjectName/Releases 添加分支的修订 会花费很多时间,因为 SubGit 将其视为一个全新的目录。

为了将 OldProjectName 历史移植到其他分支,我建议单独导入该分支:

$ subgit configure --svn-url URL REPO
$ git config -f REPO/subgit/config svn.trunk OldProjectName:refs/heads/master
$ subgit import REPO

之后,您可以获取导入的更改 Git 使用您已经提到的设置导入的存储库,然后使用 git replace 加入 ProjectOldName 的历史记录, /trunk/ProjectNewName/ProjectNewName/trunk.

Even though history on the branches seem to cross the restructuring OK, they stop at the branch creation instead of continuing on to where it was branched from. What would cause this and how can it be fixed (if it can)?

我相信这是由前面的问题引起的:由于 ProjectOldName 目录被忽略,SubGit 无法保留复制的分支历史记录如下:

$ svn cp ^/ProjectOldName ^/ProjectOldName/Releases/BRANCH

不幸的是,这意味着您可以选择导入 ProjectOldNameProjectOldName/Releases/*,但不能同时导入。再次使用 git replace 可能有助于嫁接分支的历史记录。

Is there anything special about the 'trunk' mapping? Or is it actually no different than the 'branches' mapping? AFAIK for both svn and git there's nothing special about the 'trunk' directory and the 'master' branch respectively.

trunkbranches配置选项的区别仅在Git导入SVN时有效。在将 Git 历史导入 SVN 时,SubGit 确保指定为 trunk 的分支从最初的修订版开始创建,并且永远不会被删除或替换。指定为 branches 的分支在导入的 SVN 历史记录中往往具有较短的生命周期。

trunkbranches如果导入SVN history到Git没有区别。

警告:
你永远不应该使用 use git replace 命令,以防你要保持 Git 和 SVN 存储库同步,而不是执行一次性导入。

感谢您在问题中提供所有必要的详细信息。希望我的回答对您有所帮助。