60
votes

After considering the answers to my previous question (One SVN Repository or many?), I've decided to take the 4 or so repositories I have and consolidate them into one. This of course leads to the question, what's the best way to do this?

Is there a way to combine two or more repositories maintaining the version history for both?

Edit: I should also point out that I'm using Assembla.com, which does not provide access to the svnadmin command, AFAIK

Another edit: Does this even matter? If svnadmin works on URLs, then it's no problem then.

6
svnadmin doc: "Since svnadmin works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL."Nicolas C

6 Answers

74
votes

Edit: Oh well, the question edit was made while I was typing. This is an answer to

Is there a way to combine two or more repositories maintaining the version history for both?


Assuming that

The existing repositories have a structure like:

  • repository root
    • branches
    • tags
    • trunk

and you want a structure something like:

  • repository root
    • projectA
      • branches
      • tags
      • trunk
    • projectB
      • branches
      • tags
      • trunk

Then for each of your project repositories:

svnadmin dump > project<n>.dmp

Then for each of the dump files:

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

More complex manipulations are possible, but this is the simplest, most straightforward. Changing the source repository structure during a dump/load is hazardous, but doable through a combination of svnadmin dump, svndumpfilter, hand-editing or additional text filters and svnadmin load


Dealing with a third party provider

  • Request svnadmin dump files for each of your repositories. The provider should be willing/able to provide this - it is your code!
  • Create an SVN repository locally.
  • Perform the actions listed above for the dump files.
  • Verify the repository structure is correct with your favorite client.
  • Create a dump file for the combined repositories.
  • Request that the provider populate a new repository from this dump file.

YMMV: This seems to be a reasonable approach, but I've never worked with a third party provider like this.

11
votes

With Subversion 1.7, you are now able to do dumps remotely. That is, without having access to the local file system and the svnadmin dump command.

You can use svnrdump to get a complete dump of a remote repository. See the documentation for syntax details.

Note that the server does not have to be running 1.7, only the client.

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

10
votes

Yes, using svnadmin dump and svnadmin load.

Let's assume that you have to repositories, one with HEAD revision 100 and the other with HEAD revision 150.

You dump the first repository and load it in the new one: you end up with the full story of the first repository, from revision 0 to revision 150.

Then you dump the second repository and load it in the new one: it gets loaded with its full history, the only things that change are the actual revision numbers. The history of the second repository will be represented in the new repository from revision 151 to revision 250.

The full history of both repositories is preserver, only the revision numbers change for the repository that is imported for second.

The same of course applies for more than two repositories.

EDIT: I posted while you were editing, so I didn't see your note...

5
votes

You can load many dump files in one repository with the following steps.

Repository root:

 projectA
    branches 
    tags
    trunk
 projectB
    branches
    tags
    trunk

First you must create the directory (project A, project B) in your repository root like this:

$ 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.

And after that you can load your dump files:

Use the parameter --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

This way you'll have a repository which contains many dumped repositories.

3
votes

If you don't have access to svnadmin, it would be hard but doable. Let's say you have repositories A and B, and want to merge them into repository C. Here's the steps you would have to use to accomplish this.

  1. Check out revision 1 of repository A to your hard disk.

  2. Create a directory, called Repository_A on the root of your C repository, and check this out to your local hard disk.

  3. Copy the files from your check out of A (minus) the .svn files, to your checkout of C, in the Repository_A folder.

  4. Perform a Commit on C.

Update your working copy of repository A to revision 2 , and perform steps 3 and 4, and repeat with each successive revision until you reach the head.

Now do the same with B.

This would basically do the same as @Davide Gualano was suggesting, without requiring svnadmin. You could probably write a simple script to do this for your, of if there aren't a lot of revisions, you could just do it manually.

1
votes

The other answers for this question enabled me to make the script below. Adapt the REPOS map for your case. Also, you may want to move the tags and branches into a "preaggregate" directory in stead of directly into the new branches and trunk.

#!/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