将 SVN 项目迁移到 Git - 分支和标签完全错误

Migrating SVN project to Git - Branches and Tags coming out completely wrong

我的目标是将我的 SVN 存储项目迁移到 Git 以单向、一次性迁移,即完成后我们使用 Git 并完全转储 SVN。为此,我正在尝试将提交日志从 v35.0 迁移到应用程序的最新版本(当前为 v49.0)。应用程序的解决方案由大约 20-30 个项目、库、exe 等组成...

我的项目在SVN中的结构(及案例)如下:

还有其他文件夹与Branches/Tags/Trunk处于同一级别,例如FeatureBranches,但都可以忽略。

我 运行 在我的 SVN t运行k 文件夹中获取作者的以下格式 Git:

svn log -q | awk -F '|' '/^r/ {sub("^ ", "", ); sub(" $", "", ); print " = "" <"">"}' | sort -u > authors-transform.txt

我 运行 Git Bash 中的以下命令在我为迁移创建的新空文件夹中提示:

git svn init --prefix "" --no-metadata --trunk=Trunk --branches=Branches --tags=Tags https://my/svn/project/

[更新 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 文件和 authors-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

上面的最终命令导致:

fatal: Couldn't look up commit object for HEAD

[更新 08/02] 我启动 SourceTree 并将其指向我的文件夹,然后恐怖事件就此展开。有 1 个名为“t运行k”的分支,有 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 文档中拼凑一些东西,但我不得不承认我有一个很大的冒名顶替综合症病例并且完全迷失了在此刻。如果有人对命令或配置有任何想法,我错了,我应该怎么做才能实现我的目标,我将不胜感激。

不得不承认,你的迁移方法总体来说还是不错的。

但是这个 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/Fubarrefs/remotes/Fubar,
  • Branches/35/Buzqxrefs/remotes/Buzqx,
  • Branches/36/Fubarrefs/remotes/Fubar,
  • Branches/36/Buzqxrefs/remotes/Buzqx,
  • Branches/37/Fubarrefs/remotes/Fubar,
  • Branches/37/Buzqxrefs/remotes/Buzqx,
  • 等(标签类似)。

我希望你能看到它不能很好地结束。您得到的结果正是您所要求的:)

尝试重做 branch/tag 映射,这样没有命名空间冲突

另见 man git-svn 中 CAVEATS 的最后一段:

When using multiple --branches or --tags, git svn does not automatically handle name collisions (for example, if two branches from different paths have the same name, or if a branch and a tag have the same name). In these cases, use init to set up your Git repository then, before your first fetch, edit the $GIT_DIR/config file so that the branches and tags are associated with different name spaces. For example:

branches = stable/*:refs/remotes/svn/stable/*
branches = debug/*:refs/remotes/svn/debug/*

编辑:标签映射示例

Each tag folder has a sub-folder for the releases e.g. 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 标签那样是不可变的。

原来错别字 + 抢跑是我的敌人。

在我的标签列表中,我将以下行重复了两次:

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 的标签(branch/tag 在我再次尝试时在 SVN 中制作)。我还有一堆奇怪的标签,比如 47.1@343,实际上大约有 150 个。但是,由于它是如此接近,我只是删除了那些获取 Git 的标签以生成文件的标签列表,并将其用作包含一堆“git 标签的批处理文件的基础 - d " 命令.