解决失败的“git svn clone”(需要完整的历史记录)

时间:2012-08-28 14:29:25

标签: git svn git-svn

我想将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历史记录?

可能的原因

  1. 正在搜索错误消息,我发现了这一点: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/svn403 Forbidden失败),那么我们会失败并进行一些Subversion操作。

    < / LI>
  2. Jeff Fairley在他的回答中指出Subversion URL中的空格也可能导致此错误消息(由用户Owen确认)。看看他的解决方案,看看如果你的git svn clone失败了,那么他是如何解决这个问题的。

  3. Dejay Clayton在他的回答中表明,如果branch和tag svn urls中最深的子目录组件具有相同的名称(例如.../tags/release/1.0.0.../branches/release-candidates/1.0.0),则可能会发生此错误。

5 个答案:

答案 0 :(得分:7)

当我在分支或标记中有相同名称的子目录时,我遇到了这个问题。

例如,我有标记candidates/1.0.0releases/1.0.0,这导致了记录错误,因为子目录1.0.0出现在candidatesreleases内。< / p>

git-svn docs

  

当使用多个--branches或--tags时,git svn不会自动处理名称冲突(例如,如果来自不同路径的两个分支具有相同的名称,或者分支和标记具有相同的名称)。在这些情况下,使用init设置Git存储库,然后在第一次获取之前编辑$ GIT_DIR / config文件,以便分支和标记与不同的名称空间相关联。

因此,由于同名的candidatesreleases标记导致以下命令失败:

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

请注意,这只有效,因为branchestags内没有其他冲突。如果有,我将不得不同样解决它们。

成功克隆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,但我也不确定它是否有任何区别。
  • 请记住,这些repos中包含空格,因此{/ 1}}位于主干/分支/标记路径周围。

答案 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

以及后续gitgit svn命令完全没有错误。谢谢杰夫!

答案 4 :(得分:1)

[这是原创海报讲话写作。以下曾经是对问题的更新,但是因为它解决了这个问题 - 尽管我的口味令人不满意 - 我会把它作为一个缺乏更好解决方案的答案发布。]

我不喜欢这样,但我最终将clone分为initfetch,并在(.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)似乎是

  1. Subversion分支没有任何必要的技术含义(Subversion中的分支标记只是版本化文件系统的社会商定标签复制与“标准”或其他社会商定的约定一起复制 - trunk 也没有技术含义),
  2. git svn实现严格假定社交Subversion约定在一定程度上遵循(如果您只想迁移子目录而不是整个Subversion存储库,这是不可能的。)
  3. TODO:将此.git/config文件的格式与git svn相关联,这样做会有所帮助 - 例如我现在已经(在一半之后)撰写原始答案的那一年)不知道上面[svn-remote "svn-newest"]意味着什么。此外,该方法可以通过编写脚本来实现自动化,但这超出了我目前对该问题的兴趣,并且我无法访问原始Subversion存储库或复制问题。

相关问题