我的目标是以单向、一次性迁移的方式将我的 SVN 存储项目迁移到 Git,即一旦完成,我们将使用 Git 并完全转储 SVN。为此,我正在尝试将提交日志从 v35.0 迁移到应用程序的最新版本(当前为 v49.0)。应用解决方案由大约20-30个项目、库、exe等组成...
我的项目在SVN中的结构(和案例)如下:
还有与 Branches/Tags/Trunk 处于同一级别的其他文件夹,例如FeatureBranches,但它们都可以忽略。
我在我的 SVN 主干文件夹中运行以下命令来为 Git 正确格式化作者:
svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt
我在为迁移创建的新空文件夹中的 Git Bash 提示符下运行以下命令:
git svn init --prefix "" --no-metadata --trunk=Trunk --branches=Branches --tags=Tags https://my/svn/project/
[UPDATED 08/02] 然后我编辑 /.git/config 文件并删除分支行并将标签行替换为:
tags = Tags/35/*:refs/remotes/tags/*
tags = Tags/36/*:refs/remotes/tags/*
tags = Tags/37/*:refs/remotes/tags/*
tags = Tags/38/*:refs/remotes/tags/*
tags = Tags/39/*:refs/remotes/tags/*
tags = Tags/40/*:refs/remotes/tags/*
tags = Tags/41/*:refs/remotes/tags/*
tags = Tags/42/*:refs/remotes/tags/*
tags = Tags/43/*:refs/remotes/tags/*
tags = Tags/44/*:refs/remotes/tags/*
tags = Tags/45/*:refs/remotes/tags/*
tags = Tags/45/*:refs/remotes/tags/*
tags = Tags/46/*:refs/remotes/tags/*
tags = Tags/47/*:refs/remotes/tags/*
tags = Tags/48/*:refs/remotes/tags/*
tags = Tags/49/*:refs/remotes/tags/*
然后我运行命令:
git lfs install
然后我将一个 .gitattributes 文件复制到文件夹中,其中包含要跟踪的文件列表,即 Git LFS。我对此进行了多次尝试,因此我从以前的尝试中保存了该文件。我以前使用过 git lfs track 命令。同样,我复制了一个 .gitignore 文件和由之前的命令创建的 author-transform.txt 文件。
接下来我运行:
git svn fetch --log-window-size=5000 -A authors-transform.txt
然后我会离开大约 25 个小时,做其他事情,吃饭、睡觉、更多工作等。
然后我运行:
for t in $(git for-each-ref --format='%(refname:short)' refs/remotes/tags); do git tag ${t/tags\//} $t && git branch -D -r $t; done
for b in $(git for-each-ref --format='%(refname:short)' refs/remotes); do git branch $b refs/remotes/$b && git branch -D -r $b; done
for p in $(git for-each-ref --format='%(refname:short)' | grep @); do git branch -D $p; done
git branch -d trunk
上面的最终命令导致:
<块引用>致命:无法查找 HEAD 的提交对象
[更新 08/02] 我启动 SourceTree 并将其指向我的文件夹,然后恐怖就展开了。有 1 个分支称为“trunk”,有 50 个标签。只有 1 个 hte 标签是正确的 - 35.0,其余都以解决方案项目文件夹之一命名;有些几乎相同,只是后面有一个@number,即Fubar@1423、Fubar@1568
如果这一切没有发生严重错误,我会运行以下命令来完成:
$ git remote add origin <AzureDevOps git url>
$ git push origin --all
$ git push origin --tags
我是一个相对的 Git 菜鸟,所以一直在从其他同事和 Git 文档中拼凑出一些东西,但我不得不承认我有一个冒名顶替综合症的大案例,在这一点上我完全迷失了。如果有人对我做错的命令或配置有任何想法,以及我应该怎么做才能实现我的目标,我将不胜感激。
答案 0 :(得分:0)
我不得不承认,你的迁移方法总体上还不错。
但是这个 git-config 部分对我来说立即可疑:
branches = Branches/35/*:refs/remotes/*
branches = Branches/36/*:refs/remotes/*
branches = Branches/37/*:refs/remotes/*
# ...
tags = Tags/35/*:refs/remotes/tags/*
tags = Tags/36/*:refs/remotes/tags/*
tags = Tags/37/*:refs/remotes/tags/*
# ...
假设您有一个类似于此的 svn 树:
https://my/svn/project/
├── Branches
│ ├── 35
│ │ ├── Buzqx
│ │ └── Fubar
│ ├── 36
│ │ ├── Buzqx
│ │ └── Fubar
│ └── 37
│ ├── Buzqx
│ └── Fubar
...
...上面的 git-config 要求映射:
Branches/35/Fubar
到 refs/remotes/Fubar
,Branches/35/Buzqx
到 refs/remotes/Buzqx
,Branches/36/Fubar
到 refs/remotes/Fubar
,Branches/36/Buzqx
到 refs/remotes/Buzqx
,Branches/37/Fubar
到 refs/remotes/Fubar
,Branches/37/Buzqx
到 refs/remotes/Buzqx
,我希望你能看到的结局不会很好。您得到的结果正是您所要求的 :)
尝试重做分支/标签映射,以便没有命名空间冲突。
另请参阅 man git-svn
中 CAVEATS 的最后一段:
当使用多个 --branches 或 --tags 时,git svn 不会自动处理名称冲突(例如,如果来自不同路径的两个分支具有相同的名称,或者如果一个分支和一个标签具有相同的名称)。在这些情况下,使用 init 设置您的 Git 存储库,然后在您第一次获取之前,编辑 $GIT_DIR/config 文件,以便分支和标签与不同的名称空间相关联。例如:
branches = stable/*:refs/remotes/svn/stable/*
branches = debug/*:refs/remotes/svn/debug/*
每个标签文件夹都有一个用于发布的子文件夹,例如47/47.0、47/47.1
这将在您初始 git-config 中的 tags
行中正确描述,但让我稍微调整一下,以便您可以更好地了解发生了什么。假设您改用它:
tags = Tags/35/*:refs/remotes/svn-tag-*
tags = Tags/36/*:refs/remotes/svn-tag-*
tags = Tags/37/*:refs/remotes/svn-tag-*
# ...
tags = Tags/49/*:refs/remotes/svn-tag-*
然后,这会将 SVN Tags/47/47.1
映射到名为 svn-tag-47.1
的 Git branch¹。
当然,这也会将 SVN Tags/35/35.0
映射到名为 svn-tag-35.0
的 Git 分支,等等。
现在,请注意:您的 /Branches
结构与 /Tags
不同(没有每个版本的子目录!...)但是您的 git-config 映射是相同的。 这就是您遇到问题的原因。
试试这样的:
branches = Branches/49:refs/remotes/latest
branches = Branches/48:refs/remotes/stable
branches = Branches/47:refs/remotes/lastyear-stable
# ...
branches = Branches/35:refs/remotes/pre-eol
#-- or at the very very least (NOT RECOMMENDED):
#branches = Branches/*:refs/remotes/svn-branch-*
¹ svn 标签必须是 git 中的分支,因为它们不像 git 标签那样是不可变的。
答案 1 :(得分:0)
所以我的敌人是打字错误+跳枪。
在我的标签列表中,我重复了以下行两次:
tags = Tags/45/*:refs/remotes/tags/*
在那之后,在 SVN 中创建标签之前,我有以下行:
tags = Tags/45/*:refs/remotes/tags/*
为了使标签例如 47.0 和 47.1 出现在我的 Git UI (SourceTree) 中可折叠的 47 标签下,我更新了配置中使用的上述行:
tags = Tags/47/*:refs/remotes/tags/47/*
以上结合删除主要问题编辑中提到的分支线使我达到了 90%。我最终得到了一个主标签和一个从 35 到 49 的标签(我再次尝试时用 SVN 制作的分支/标签)。我仍然有一堆奇怪的标签,比如 47.1@343,实际上大约有 150 个。然而,由于它是如此接近,我只是删除了那些标签,让 Git 为文件生成标签列表,并将其用作包含一堆“git tag -d”命令的批处理文件的基础。