如何克隆 SVN 存储库的一部分?

Posted

技术标签:

【中文标题】如何克隆 SVN 存储库的一部分?【英文标题】:how to clone a part of SVN repository? 【发布时间】:2010-07-03 07:25:47 【问题描述】:

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

【问题讨论】:

+1,知道如何拆分 Subversion 存储库是程序员的一项重要技能(如果您使用的是 Subversion)。 【参考方案1】:

您需要创建存储库的转储,并过滤掉您想要的目录和修订。 svndumpfilter 是用于此目的的通用工具。示例见this chapter of the subversion book。

【讨论】:

【参考方案2】:

另一种可能性是 git svn clone,它只拉取感兴趣的目录。然后可以将其推送到新的 svn 存储库。这简单吗?不,但如果您无权访问服务器,这很方便。我确信有更好的方法 - 但这种方法可以确保您不会意外推送到原始 svn 存储库。

# 原始svn路径 git svn clone http://server/path/to/clone orig # SVN 只放你的分支 svnadmin 创建新的 # 添加一个条目,否则 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 repo 的 svn 路径 git svn 初始化文件:///path/to/new # 拉入数据(我们的一次提交) git svn 获取 # 显示分支 git 分支 -a # 为推送准备 git repot git rebase --onto remotes/git-svn --root master # 最后推送到新的 svn repo。 git svn dcommit

我在哪里可以找到如何做到这一点,所以我想出了这个。您可能需要像这样弄乱 svn donf 文件:

svn_repo="$(密码)/新" 用户=“我的用户名” 回声'[/]' >> $svn_repo/conf/authz echo "$user = rw" >> $svn_repo/conf/authz 回声'[用户]' >> $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。

【讨论】:

【参考方案3】:

传统的做法是将存储库转储到转储文件,根据需要使用 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.txt 已从 AnotherLocation 复制到 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 的工具,专门用于从颠覆存储库中提取文件和文件夹。它还可以从 subversion 存储库中删除(或删除)文件,以及将存储库分成两部分,同时保证不会从两个存储库之一中丢失任何文件。 Subdivision 的亮点在于它拥有整个存储库的内存视图,并运行解决我们在上面示例中遇到的所有问题所需的算法。这意味着您只需在提取正确文件时获得必要的粒度,同时节省用户时间,因为操作一次完成。

【讨论】:

以上是关于如何克隆 SVN 存储库的一部分?的主要内容,如果未能解决你的问题,请参考以下文章

git - 如何克隆本地 svn 存储库?

如何 git-svn 从 Subversion 存储库克隆最后 n 个修订?

如何导出具有依赖项的 SVN 存储库的一部分?

如何在 Mercurial 中克隆存储库的子文件夹?

如何将一些文件从一个 git repo 移动到另一个(不是克隆),保留历史记录

如何保留我贡献的远程存储库的更新克隆(VSCode)? [复制]