如何克隆 SVN 仓库的部分内容?

4
我有一个SVN仓库,里面有很多目录。现在我想克隆这个仓库,只留下其中一个特定的目录。当然,我不需要在这个新仓库中与其他目录相关的任何修订版。我该怎么做?谢谢。

+1,如果你在使用Subversion,那么知道如何拆分一个Subversion仓库是程序员的重要技能。 - Craig Trader
3个回答

5

0
传统的做法是将存储库转储到一个转储文件中,使用svndumpfilter根据需要包含或排除文件,然后将过滤后的转储文件加载到新存储库中。这种方法适用于简单的更改,例如从存储库中删除几个文件。
当存储库包括文件移动和复制时,情况会变得有些困难。
让我们以最简单的例子为例,假设有一个名为MyProject的项目文件夹,在历史记录中的某个时间被重命名为TheProject。随后,另一个名为TheProject/copiedfile.txt的文件从AnotherLocation复制到TheProject下。一个基本的树形结构可能如下所示。
...
+ AnotherLocation
|--- copiedfile.txt
|--- unwantedfile.txt
+ TheProject
|--- copiedfile.txt
|--- otherfile.txt 
...

您想让TheProject拥有自己的新存储库。因此,您将存储库转储到文件中,并使用svndumpfilter仅包括TheProject,因为这是您在HEAD修订版中看到的项目名称。

svndumpfilter include /TheProject < input.dump > output.dump

很不幸,你从svndumpfilter得到了这个错误。

svndumpfilter: E200003: Invalid copy source path '/MyProject'

这是因为TheProject曾被称为MyProject,在过去的某个版本中进行了重命名。由于重命名本质上是删除和复制,因此svndumpfilter无法找到创建TheProject的复制源,并出现错误。因此,我们使用以下命令再次尝试,其中包括MyProject
svndumpfilter include /TheProject /MyProject < input.dump > output.dump

Svndumfilter现在出现了另一个错误。

svndumpfilter: E200003: Invalid copy source path '/AnotherLocation/copiedfile.txt'

是的,这是因为copiedfile.txtAnotherLocation复制到TheProject。因此我们必须包括这个文件,否则我们无法将其复制到`TheProject'。让我们再试一次。

svndumpfilter include /TheProject /MyProject /AnotherLocation/copiedfile.txt < input.dump > output.dump

操作成功!看来第三次就是幸运的!

让我们尝试将过滤后的转储文件加载到存储库中。

svnadmin create newrepo
svnadmin load newrepo < output.dump

运气不太好!在加载过程中出现了以下错误

* editing path : AnotherLocation/copiedfile.txt ...svnadmin: E160013: File not found: transaction '1-1', path '/AnotherLocation/copiedfile.txt'

啊!这是因为我们忘记包含AnotherLocation,它是copiedfile.txt的父文件夹,所以必须要包含。
svndumpfilter include /TheProject /MyProject /AnotherLocation < input.dump > output.dump

好的,这个命令可以工作,加载也可以工作。不幸的是,我们现在也包括了/AnotherLocation/unwantedfile.txt。这意味着使用svndumpfilter include并不能真正起到我们想要的细粒度作用。我们必须使用svndumpfilter exclude来尝试排除我们不需要的所有内容,从而得到一个只包含所需文件的存储库。不用说,这种方法也存在自己的问题。例如,很容易排除实际上在存储库中需要的文件。如果有人想要一个例子,我可以扩展这个答案。

一定有更好的方法。事实证明确实有,但这是一个商业产品。我们开发了一个名为Subdivision的工具,专门用于从子版本库中提取文件和文件夹。它还可以从子版本库中删除(或抹掉)文件,以及将版本库分成两个部分,同时保证不会错过任何文件。Subdivision的亮点在于它拥有整个版本库的内存视图,并运行所需的算法来解决我们在上面示例中遇到的所有问题。这意味着您只提取正确的文件时获得必要的细粒度,同时节省用户时间,因为操作只需一次完成。


0
另一种可能性是使用git svn clone,它仅拉取感兴趣的目录。然后可以将其推送到新的svn repo。这容易吗?不,但如果您无法访问服务器,则很方便。我相信有更好的方法 - 但这种方法确保您不会意外地推送到原始svn repo。
    # 原始svn路径
    git svn clone http://server/path/to/clone orig
    # 要放置您的分支的SVN
    svnadmin create new
    # 添加一个条目,否则git svn会出错...
    svn co file:///path/to/new new.wd
    mkdir new.wd/null
    svn add new.wd/null
    svn ci -m"add null" new.wd/null
    # 克隆我们的克隆
    git clone file:///path/to/orig abc
    cd abc
    # 设置svn路径到svn repo
    git svn init file:///path/to/new
    # 拉取数据(我们的一个提交)
    git svn fetch
    # 显示分支
    git branch -a
    # 准备要推送的git存储库
    git rebase --onto remotes/git-svn --root master
    # 最后推送到新的svn repo。
    git svn dcommit

我找不到如何做这个的地方,所以想出了这个方法。您可能需要修改svn donf文件,像这样:

    svn_repo =“$(pwd)/new”
    user =“myusername”
    echo'[ /]' >> $svn_repo/conf/authz
    echo“$user = rw”>> $svn_repo/conf/authz
    echo'[ users]' >> $svn_repo/conf/passwd
    echo“$user = test”>> $svn_repo/conf/passwd
    echo'password-db = passwd'>> $svn_repo/conf/svnserve.conf
    echo“svn repo is file://$svn_repo”
    svn co file://$svn_repo svn.wd

在上面的示例中,myusername的密码是test。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接