2

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

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

初始布局:

  • 主干:/ProjectOldName
  • 分支:/ProjectOldName/Releases
  • 标签: 不适用

中间布局:

  • 主干:/主干/ProjectNewName
  • 分支:/releases/ProjectNewName
  • 标签: 不适用

最终布局:

  • 主干:/ProjectNewName/主干
  • 分支:/ProjectNewName/branches/releases
  • 标签:/ProjectNewName/标签

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

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 上同一文件的历史记录在创建重组的最后一步时停止,并且 git 存储库中不存在预期的“old-master-interim”和“old-master”分支。

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

  • 从 /ProjectOldName 开始
  • 添加目录 /trunk/ProjectNewName
  • 从 /ProjectOldName/ 向 /trunk/ProjectNewName/ 添加多个目录(大部分,但不是全部),但未添加这些目录的删除(我不确定这是如何发生的,因为该分支中尚不存在目录)
  • 从 /ProjectOldName/ 替换 /trunk/ProejctNewName/ 中的多个目录(与上面添加的相同)(修订版略有不同,也许是尝试重做以前的添加?)
  • 删除目录 /trunk/ProjectNewName(带有关于未保存历史记录的注释)
  • 添加目录/trunk/ProjectNewName(第二次)
  • 从 /ProjectOldName/ 向 /trunk/ProjectNewName/ 添加多个目录,再次使用同一组目录,但这次删除不存在
  • 添加目录/ProjectNewName/trunk
  • 从 /trunk/ProjectNewName/ 向 /ProjectNewName/trunk/ 添加多个目录
  • 删除目录 /trunk/ProjectNewName

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

  • 从 /ProjectOldName/Releases 开始
  • 添加目录 /releases
  • 从 /ProjectOldName/Releases/ 向 /releases/ 添加多个目录(每个分支一个)
  • 删除目录 /releases
  • 添加目录 /releases/ProjectNewName
  • 从 /ProjectOldName/Releases/ 向 /releases/ProjectNewName/ 添加多个目录(每个分支一个)
  • 添加目录 /ProjectNewName/branches/releases
  • 从 /releases/ProjectNewName/ 向 /ProjectNewName/branches/releases/ 添加多个目录(每个分支一个)
  • 删除目录 /releases/ProjectNewName

唯一真正的区别似乎是主干而不是分支发生的“替换多个目录”步骤。

所以毕竟:

  • 有没有办法让 SubGit 转换上述内容,同时保持主干重组的历史记录?
  • SubGit 能否像在原始存储库布局中那样处理主干下的分支(即 /OldProjectName 的主干,/OldProjectName/Releases 的分支)?
  • “主干”映射有什么特别之处吗?或者它实际上与“分支”映射没有什么不同?svn 和 git 的 AFAIK 分别对 'trunk' 目录和 'master' 分支没有什么特别之处。
  • 尽管分支上的历史似乎跨越了重组 OK,但它们在分支创建处停止,而不是继续到分支所在的位置。什么会导致这种情况以及如何解决(如果可以的话)?
4

1 回答 1

1

有没有办法让 SubGit 转换上述内容,同时保持主干重组的历史记录?

当整个分支目录从一个位置复制到另一个位置时,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/ProjectNewName/trunk目录执行重组的方式。结果 SubGit 无法为它们保留历史记录。

在您的情况下,一种可能的解决方法是将这些目录导入单独的分支,然后使用git-replace将导入的部分移植到一个历史记录中。

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

SubGit 能否像在原始存储库布局中一样处理主干下的分支(即 /OldProjectName 的主干,/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的历史记录。

尽管分支上的历史似乎跨越了重组 OK,但它们在分支创建时停止,而不是继续到分支的位置。什么会导致这种情况以及如何解决(如果可以的话)?

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

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

不幸的是,这意味着您可以选择导入ProjectOldNameProjectOldName/Releases/*,但不能同时选择两者。git replace通过嫁接分支的历史,再次使用可能会有所帮助。

“主干”映射有什么特别之处吗?或者它实际上与“分支”映射没有什么不同?svn 和 git 的 AFAIK 分别对 'trunk' 目录和 'master' 分支没有什么特别之处。

主干分支配置选项之间的区别仅在 Git 到 SVN 导入期间有效。在将 Git 历史导入 SVN 时,SubGit 确保指定为主干的分支是从第一个修订版中创建的,并且永远不会被删除或替换。指定为分支的分支在导入的 SVN 历史记录中的生命周期往往较短。

如果您将 SVN 历史记录导入 Git ,则主干分支之间没有区别。

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

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

于 2015-02-18T07:37:02.650 回答