我想将Subversion存储库子目录(此处由module
表示)转换为具有完整历史记录的git存储库。我的Subversion存储库的历史记录中有许多svn copy
个操作(Subversion人称之为分支)。发布策略是在每次发布或其他分支创建之后,旧URL保持未使用状态,新URL将替换旧URL以包含工作。
最理想的是,通过我的阅读,似乎应该可以解决这个问题:
$ git svn clone --username=mysvnusername --authors-file=authors.txt \
--follow-parent \
http://svnserver/svn/src/branches/x/y/apps/module module
(其中branches/x/y/
描绘了最新的分支)。但是我收到了一个错误,看起来像这样:
W: Ignoring error from SVN, path probably does not exist: (160013): Filesystem has no item: '/svn/src/!svn/bc/100/branches/x/y/apps/module' path not found
W: Do not be alarmed at the above message git-svn is just searching aggressively for old history.
(更新:在上面添加选项--no-minimize-url
不会删除错误消息。)
创建并填充目录module
,但不会导入超过最新svn copy
提交的Subversion历史记录(当我预期数百个时,创建的git存储库最终只有两次提交)。
问题是,如何在出现这种情况时导出完整的Subversion历史记录?
正在搜索错误消息,我发现了这一点:git-svn anonymous checkout fails with -s 与此Subversion问题相关联:http://subversion.tigris.org/issues/show_bug.cgi?id=3242
我通过阅读理解,Subversion 1.5中的内容改变了客户端如何访问存储库。对于较新的Subversion,如果对URL路径的某些超级目录没有读访问权(对我而言svn ls http://svnserver/svn
对403 Forbidden
失败),那么我们会失败并进行一些Subversion操作。
Jeff Fairley在他的回答中指出Subversion URL中的空格也可能导致此错误消息(由用户Owen确认)。看看他的解决方案,看看如果你的git svn clone
失败了,那么他是如何解决这个问题的。
Dejay Clayton在他的回答中表明,如果branch和tag svn urls中最深的子目录组件具有相同的名称(例如.../tags/release/1.0.0
和.../branches/release-candidates/1.0.0
),则可能会发生此错误。
答案 0 :(得分:7)
当我在分支或标记中有相同名称的子目录时,我遇到了这个问题。
例如,我有标记candidates/1.0.0
和releases/1.0.0
,这导致了记录错误,因为子目录1.0.0
出现在candidates
和releases
内。< / p>
当使用多个--branches或--tags时,git svn不会自动处理名称冲突(例如,如果来自不同路径的两个分支具有相同的名称,或者分支和标记具有相同的名称)。在这些情况下,使用init设置Git存储库,然后在第一次获取之前编辑$ GIT_DIR / config文件,以便分支和标记与不同的名称空间相关联。
因此,由于同名的candidates
和releases
标记导致以下命令失败:
git svn clone --authors-file=../authors.txt --no-metadata \
--trunk=/trunk --branches=/branches --tags=/candidates \
--tags=/releases --tags=/tags -r 100:HEAD \
--prefix=origin/ \
svn://example.com:3692/my-repos/path/to/project/
以下命令序列确实有效:
git svn init --no-metadata \
--trunk=/trunk --branches=/branches --tags=/tags \
--prefix=origin/ \
'svn://example.com:3692/my-repos/path/to/project/'
git config --add svn-remote.svn.tags \
'path/to/project/candidates/*:refs/remotes/origin/tags/Candidates/*'
git config --add svn-remote.svn.tags \
'path/to/project/releases/*:refs/remotes/origin/tags/Releases/*'
git svn fetch --authors-file=../authors.txt -r100:HEAD
请注意,这只有效,因为branches
和tags
内没有其他冲突。如果有,我将不得不同样解决它们。
成功克隆SVN存储库后,我执行了以下步骤,以便:将SVN标记转换为GIT标记;将trunk
转为master
;将其他引用转换为分支;并重新定位远程路径:
# Make tags into true tags
cp -Rf .git/refs/remotes/origin/tags/* .git/refs/tags/
rm -Rf .git/refs/remotes/origin/tags
# Make other references into branches
cp -Rf .git/refs/remotes/origin/* .git/refs/heads/
rm -Rf .git/refs/remotes/origin
cp -Rf .git/refs/remotes/* .git/refs/heads/ # May be missing; that's okay
rm -Rf .git/refs/remotes
# Change 'trunk' to 'master'
git checkout trunk
git branch -d master
git branch -m trunk master
答案 1 :(得分:6)
不是一个完整的答案,但也许你遗失的片段(我也有兴趣迁移,所以我找到了这个难题的一部分)。
当您查看documentation of git-svn时,您会找到以下选项:
--no-minimize-url
当跟踪多个目录(使用--stdlayout, - blank或--tags选项)时,git svn将尝试连接到Subversion存储库的根目录(或允许的最高级别)。如果整个项目在存储库中移动,则此默认设置允许更好地跟踪历史记录,但可能会导致读取访问限制到位的存储库出现问题。传递--no-minimize-url将允许git svn按原样接受URL,而不尝试连接到更高级别的目录。默认情况下,当只跟踪一个URL /分支时,此选项处于关闭状态(这样做不太好)。
这适合您的情况,因此git svn
不会尝试读取更高级别的目录树(将被阻止)。
至少你可以尝试一下......
答案 2 :(得分:2)
我最近将一长串SVN存储库迁移到Git中,并最终遇到了这个问题。我们的SVN结构非常草率,所以我不得不使用--no-minimize-url
。通常,我会运行如下命令:
$ git svn clone http://[url]/svn/[repo]/[path-to-code] \
-s --no-minimize-url \
-A authors.txt
我运行的最后几次迁移在URL中有一个空格。我不知道这是空间还是别的什么,但我得到了你所看到的同样的错误。如果我不需要,我不想进入修改配置文件,幸运的是我最终找到了解决方案。我最终跳过-s --no-minimize-url
选项,转而采用不同的方式明确声明路径。
$ git svn clone http://[url]/svn/[repo]/ \
--trunk="/[path-to-code]/trunk" \
--branches="/[path-to-code]/branches" \
--tags="/[path-to-code]/tags" \
-A authors.txt \
--follow-parent
--follow-parent
,但我也不确定它是否有任何区别。答案 3 :(得分:1)
[我意识到这应该是关于杰夫·费尔利回答的评论,但我没有这样做的声誉。由于原始海报确实要求确认方法有效,我将其作为答案提供。]
我可以确认他的解决方案适用于他(和我)因路径中的空格而导致的问题。我有相同的要求(克隆具有历史记录的SVN仓库中的单个模块),除了我没有任何分支或标签担心。
我尝试了几种在URL中提供模块完整路径的排列(例如,使用--no-minimise-url
,指定--trunk
或--stdlayout
)但没有成功。对我来说,结果通常是带有完整历史记录的git repo,但没有任何文件。这可能是FooF遇到的问题,也可能不是(SVN中没有读访问权限),但肯定是因为我的模块路径中有空格。
再次尝试仅使用SVN repo base作为URL,--trunk
中我的模块的路径完美无缺。之后我的.git / config看起来像这样:
[core]
repositoryformatversion = 0
filemode = false
bare = false
loggallrefupdates = true
symlinks = false
ignorecase = true
hideDotFiles = dotGitOnly
[svn-remote "svn"]
url = https://[url]/svn/[repo]
fetch = trunk/[path-to-code]:refs/remotes/trunk
[svn]
authorsfile = ~/working/authors-transform.txt
以及后续git
和git svn
命令完全没有错误。谢谢杰夫!
答案 4 :(得分:1)
[这是原创海报讲话写作。以下曾经是对问题的更新,但是因为它解决了这个问题 - 尽管我的口味令人不满意 - 我会把它作为一个缺乏更好解决方案的答案发布。]
我不喜欢这样,但我最终将clone
分为init
和fetch
,并在(.git/config
,{repopath=apps/module
之间对gitreponame=module
进行了一些修改{1}}):
$ git svn init--username=mysvnusername \
--branches=/src/branches/ \
--trunk=/src/trunk/${repopath} \
--tags=/src/tags/ \
http://svnserver/svn/src ${gitreponame}
$ cd ${gitreponame}
$ sed -i.bak "s|*:|*/${repopath}:|" .git/config
$ git svn fetch --authors-file=../authors.txt --follow-parent
我找不到如何使用git svn
指定子目录迁移的分支 - 因此编辑了.git/config
文件。以下统一差异说明了使用sed
进行编辑的效果:
[svn-remote "svn"]
url = http://svnserver/svn/src
fetch = trunk/apps/module:refs/remotes/trunk
- branches = branches/*:refs/remotes/*
- tags = tags/*:refs/remotes/tags/*
+ branches = branches/*/apps/module:refs/remotes/*
+ tags = tags/*/apps/module:refs/remotes/tags/*
由于实际需要的HEAD
位于另一个网址中,我只是将另一个[svn-remote]
部分添加到.git/config
:
+ [svn-remote "svn-newest"]
+ url = http://svnserver/svn/src
+ fetch = branches/x/y/apps/module:refs/remotes/trunk
+ branches = branches/*/apps/module:refs/remotes/*
+ tags = tags/*/apps/module:refs/remotes/tags/*
(在现实生活中,我还在这里添加了一些第一次获取没有拾取的分支),并再次获取:
$ git svn fetch --authors-file=../authors.txt --follow-parent svn-newest
这样我结束了将完整的Subversion历史记录迁移到新生成的git存储库。
注意事项1 :我可能刚刚告诉我的“主干”是branches/x/y/apps/module
,因为git-svn
的“主干”的含义似乎基本上具有含义git HEAD
(颠覆概念的主干,分支,标签没有深入的技术基础,它们是社会商定的惯例)。
注意事项2 :--follow-parent
可能不需要git svn fetch
,但我现在无法知道或尝试。
Note-3 :虽然早先阅读的svn2git似乎是git-svn
的封套,但我没有看到动机,但看到标签的混乱呈现我现在得到它。如果我不得不再次尝试这样做,我会在下次尝试svn2git
。
P.S。这是一种相当尴尬的做法。这里的次要问题(为什么需要外部编辑.git/config
)似乎是
git svn
实现严格假定社交Subversion约定在一定程度上遵循(如果您只想迁移子目录而不是整个Subversion存储库,这是不可能的。) TODO:将此.git/config
文件的格式与git svn
相关联,这样做会有所帮助 - 例如我现在已经(在一半之后)撰写原始答案的那一年)不知道上面[svn-remote "svn-newest"]
意味着什么。此外,该方法可以通过编写脚本来实现自动化,但这超出了我目前对该问题的兴趣,并且我无法访问原始Subversion存储库或复制问题。