将多个 SVN 存储库合并为一个

Posted

技术标签:

【中文标题】将多个 SVN 存储库合并为一个【英文标题】:Combining multiple SVN repositories into one 【发布时间】:2010-09-21 00:03:33 【问题描述】:

在考虑了我上一个问题 (One SVN Repository or many?) 的答案后,我决定采用我拥有的 4 个左右的存储库并将它们合并为一个。这当然会引出一个问题,最好的方法是什么?

有没有办法结合两个或多个存储库来维护两者的版本历史?

编辑:我还应该指出我正在使用 Assembla.com,它不提供对 svnadmin 命令 AFAIK 的访问权限

另一个编辑:这还重要吗?如果 svnadmin 在 URL 上工作,那么就没有问题了。

【问题讨论】:

svnadmin doc: “由于 svnadmin 通过直接存储库访问工作(因此只能在拥有存储库的机器上使用),它通过路径而不是 URL 引用存储库。” 【参考方案1】:

编辑:哦,好吧,问题编辑是在我打字的时候进行的。这是一个答案

有没有办法结合两个或多个 维护版本的存储库 两者的历史?


假设

现有存储库的结构如下:

存储库根 分支机构 标签 主干

你想要一个类似的结构:

存储库根 项目A 分支机构 标签 主干 项目B 分支机构 标签 主干

然后对于您的每个项目存储库:

svnadmin dump > project<n>.dmp

然后对于每个转储文件:

svn mkdir "<repo url>/project<n>"
svnadmin load --parent-dir "project<n>" <filesystem path to repos>

更复杂的操作是可能的,但这是最简单、最直接的。在转储/加载期间更改源存储库结构是危险的,但可以通过结合使用 svnadmin dumpsvndumpfilter、手动编辑或其他文本过滤器和 svnadmin load


与第三方提供商打交道

为您的每个存储库请求 svnadmin dump 文件。提供者应该愿意/能够提供这个 - 它 你的代码! 在本地创建一个 SVN 存储库。 对转储文件执行上面列出的操作。 使用您最喜欢的客户端验证存储库结构是否正确。 为组合存储库创建转储文件。 请求提供程序从此转储文件填充新的存储库。

YMMV:这似乎是一种合理的方法,但我从未与这样的第三方提供商合作过。

【讨论】:

最后一点正是我所追求的!当我读到这篇文章时,我正要放弃我的机会。谢谢。 如果您的 subversion 主机使用 subversion 1.4 或更高版本,您始终可以将存储库 svnsync 同步到本地存储库并(在同步后)转储该数据库。 还有一些颠覆供应商(例如 Google Code)允许 svnsyncing /to/ 一个存储库。因此,您可以在其他地方执行合并后使用 svnsync 上传结果。 确保在运行 "svnadmin load --parent-dir "project[n]" filesystem path to repos 之前在目标存储库中创建一个空的 "project" 目录dmp 的文件系统路径"。 正如 Aaron 提到的,在运行 svnadmin load --parentdir 之前,您需要在目标仓库中创建一个空的项目目录。这可以通过“svn mkdir repo url/project[n]”来完成。【参考方案2】:

使用 Subversion 1.7,您现在可以远程进行转储。也就是说,无需访问本地文件系统和svnadmin dump 命令。

您可以使用svnrdump 获取远程存储库的完整转储。有关语法详细信息,请参阅文档。

请注意,服务器不必运行 1.7,只需运行客户端即可。

http://svnbook.red-bean.com/en/1.7/svn.ref.svnrdump.c.dump.html

【讨论】:

从 svn 1.4 开始,您还可以使用 svnsync 创建远程存储库的本地副本。 svn.apache.org/repos/asf/subversion/trunk/notes/svnsync.txt【参考方案3】:

是的,使用svnadmin dump 和svnadmin load。

假设您必须使用存储库,一个具有 HEAD 修订版 100,另一个具有 HEAD 修订版 150。

您转储第一个存储库并将其加载到新存储库中:您最终会获得第一个存储库的完整故事,从修订 0 到修订 150。

然后您转储第二个存储库并将其加载到新的存储库中:它会加载完整的历史记录,唯一改变的是实际的修订号。第二个存储库的历史将在新的存储库中表示,从修订版 151 到修订版 250。

两个存储库的完整历史记录是保留者,只有第二个导入的存储库的修订号发生变化。

当然,这同样适用于两个以上的存储库。

编辑:我在你编辑的时候发布了,所以我没有看到你的笔记...

【讨论】:

只是一个简短的说明 - 在您撰写评论时,它看起来像是漏掉了一点意大利语。那应该是“and”,而不是“e” :-) 嗯,你说得对,有时我的意大利手指打字速度比我想成为英语的大脑所能处理的还快:D【参考方案4】:

您可以通过以下步骤在一个存储库中加载多个转储文件。

存储库根目录:

 projectA
    branches 
    tags
    trunk
 projectB
    branches
    tags
    trunk

首先,您必须在存储库根目录中创建目录(项目 A,项目 B),如下所示:

$ svn mkdir -m "Initial project root" \
file:///var/svn/repository_root/Project_A\
file:///var/svn/repository_root/Project_B\
file:///var/svn/repository_root/Project_C\

Revision 1 committed.

然后你可以加载你的转储文件:

使用参数--parent-dir DIRECTORY

$ svnadmin load /var/svn/repository_root --parent-dir Project_A < file-dump-PRJA.dump
…
$ svnadmin load /var/svn/repository_root --parent-dir Project_B < file-dump-PRJB.dump

这样您将拥有一个包含许多转储存储库的存储库。

【讨论】:

【参考方案5】:

如果您无权访问 svnadmin,这将很难但可行。假设您有存储库 A 和 B,并希望将它们合并到存储库 C。这是您完成此操作必须使用的步骤。

    将存储库 A 的修订版 1 签出到您的硬盘。

    在 C 存储库的根目录上创建一个名为 Repository_A 的目录,并将其检出到本地硬盘。

    将文件从签出 A(减去).svn 文件复制到签出 C 的 Repository_A 文件夹中。

    在 C 上执行提交。

将存储库 A 的工作副本更新为修订版 2,并执行步骤 3 和 4,并在每个后续修订版中重复,直到到达头部。

现在对 B 做同样的事情。

这基本上和@Davide Gualano 建议的一样,不需要 svnadmin。您可能可以编写一个简单的脚本来为您执行此操作,如果没有很多修订,您可以手动执行。

【讨论】:

是的,最终结果将与使用 svnadmin dump and load 的解决方案相同,但它可能需要很多时间。 最终结果的元数据会略有不同。一位开发人员将在短时间内签入所有更改。您还需要聪明地让您的脚本将签入 cmets 复制过来。【参考方案6】:

这个问题的其他答案使我能够制作下面的脚本。为您的案例调整 REPOS 地图。此外,您可能希望将标签和分支移动到“预聚合”目录中,而不是直接移动到新的分支和主干中。

#!/bin/bash

NEWREPO=$(pwd)/newrepo
NEWREPOCO="$NEWREPO_co"
DUMPS=repodumps
REV="0:HEAD"
REPOROOT=/data/svn/2.2.1/repositories/
TOOLDIR=/opt/svn/2.2.1/bin/
PATH=$PATH:$TOOLDIR

# Old Repository mapping 
declare -A REPOS=( 
    [BlaEntityBeans]='(
        [newname]="EntityBeans"
    )'
    [OldServletRepoServlet]='(
        [newname]="SpreadsheetImportServlet"
    )'
    [ExperimentalMappingXML]='(
        [newname]="SpreadsheetMappingXML"
    )'
    [NewImportProcess]='(
        [newname]="SpreadsheetImportProcess"
    )'    
)

dump() 
    rm -fr $DUMPS
    mkdir $DUMPS
    for repo in "$!REPOS[@]"
    do
        local dumpfile=$DUMPS/$repo.dmp
    echo "Dumpimg Repo $repo to $dumpfile"
        svnadmin dump -r $REV $REPOROOT/$repo > $dumpfile
    done


loadRepos() 
    # new big repo
    rm -fr $NEWREPO
    svnadmin create $NEWREPO
    svn mkdir file:///$NEWREPO/trunk -m ""
    svn mkdir file:///$NEWREPO/branches -m ""
    svn mkdir file:///$NEWREPO/tags -m ""

    # add the old projects as modules
    for currentname in "$!REPOS[@]"
    do  
        declare -A repo=$REPOS[$currentname]
        local newname=$repo[newname]
        echo "Loading repo $currentname soon to be $newname"
        dumpfile=$DUMPS/$currentname.dmp

        # import the current repo into a trmporary root position
        svn mkdir file:///$NEWREPO/$currentname -m "Made module $currentname"
        svnadmin load --parent-dir $currentname $NEWREPO < $dumpfile

        # now move stuff arround
        # first rename to new repo
        svn move file:///$NEWREPO/$currentname file:///$NEWREPO/$newname -m "Moved $currentname to $newname"
        # now move trunk, branches and tags
        for vc in trunk,branches,tags
        do
            echo "Moving the current content of $vc into $NEWREPO/$vc/$newname"
            svn move file:///$NEWREPO/$newname/$vc file:///$NEWREPO/$vc/$newname -m "Done by $0"
        done
    svn rm  file:///$NEWREPO/$newname -m "Removed old $newname"
    done


dump
loadRepos

【讨论】:

以上是关于将多个 SVN 存储库合并为一个的主要内容,如果未能解决你的问题,请参考以下文章

将 SVN 存储库的一部分合并到另一个具有历史记录的存储库

如何为Mercurial最佳地配置中央存储库/多个中央存储库?

如何将多个 Git 存储库合并为一个并交错历史

git-svn 多个 git 存储库到同一个 svn 存储库

git合并不同的存储库?

将 SVN 主干中的每个目录转换为不同的 GIT 存储库