svnsvn-externalssubtreesvn-export

svn subtree, update from one repo, commit to other


A have a big project in a SVN repository. I would like to use some modules of the project in other applications, so I thought about checkout them from my main SVN repository so I can keep my code updated.

How can I "export" one folder / module of my repository so I can checkout only that module to other project? My other projects where I want to include that module are also in their own SVN repository.

In resume, I would like to be able to do SVN update to the main repo but do the commits to the project repo.

I hope its clear what I want to do.

In response to DavidW anwser:


Solution

  • A few questions:

    The answer you'll give depends heavily upon your answers to these questions.

    Let's assume that the code is actually shared. What you do in one is what you want done in the other. You make a change in your project, the code in the other project also changes.

    In that case, use svn:externals. This is a property that you place upon a directory. What it does is relate a Subversion URL to a sub-dirctory name. For example:

    $ svn propset svn:externals "http://svn.vegibanc.com/svn/trunk/project/stuff utils" .
    

    WIll place the property on the current directory. When you do an update or checkout, a directory called utils will be created in your project, and Subversion will automatically checkout http://svn.vegibanc.com/svn/trunk/project/stuff into that directory. It's magic, but like all magic it has both a light and a dark side.

    First of all the light side:

    This is sharing code between two projects. You make a change in your utils directory and commit the change, and the stuff sub-directory in project will be updated. I use it to build tools into my projects. If I upgrade the tool, all projects get the upgraded tools.

    Now, the dark side:

    If you define the svn:externals just like I showed you, you will deeply regret it. Imagine if you decide to branch your work for a release. Well, your utils directory is still pointing to the trunk of project/stuff. If you branch for release 2.1, and trunk is now working on 2.2, you're going to get stuff in utils that you don't want.

    Even worse, if you create a tag, that tag will continue to change because that utils directory in trunk is still being changed.

    Therefore, it is highly recommended that you specify an exact version of a URL:

    $ svn propset svn:externals "-r23283 ^/trunk/project/stuff@23283 utils" .
    $ svn propset svn:externals "^/tags/2.3.3/project/stuff utils" .
    

    In the first, I am referring to a specific revision of the URL. It is completely unchanging. If I need to point it to another revision, I need to change the svn:externals property itself.

    The second is pointing to a specific tag. It's not as safe since tags could be changed, but I can treat my external dependency as a release this way. I am using release 2.3.3 of the stuff utilities.

    Both are using the ^ shortcut which simply means the Subversion Repository Root. This way, if you move your Subversion repository to another system, or change from http to svn, your externals will still work. Of course, if you do it this way, you'll never be able to change the code under svn:externals. And, this isn't what you want.

    You can use relative URLs too, but they care a bit more dangerous.

    Imagine your two projects like this, and you want to make the stuff directory an svn:external link to the utils directory:

    http://svn.vegibanc.com/svn/trunk/project/foo/stuff
    http://svn.vegibanc.com/svn/trunk/project/bar/utils
    

    The project is branched together and tagged together. You could do this:

    $ co http://svn.vegibanc.com/svn/trunk/project/bar bar-trunk
    $ cd project-bar
    $ svn propset svn:externals "../foo/stuff utils" .
    

    This will link the stuff directory externally to your utils directory. However, it's done in a relative manner. If you do this:

    $ cp http://svn.vegibanc.com/svn/trunk http://svn.vegibank.com/svn/branches/2.3
    

    Your utils directory will still be externally linked to the stuff directory under the foo project, but they will both be on the 2.3 branch.

    Changing code in bar/utils will change the code in foo/stuff and visa versa. You're still sharing code, but in a way that both projects are still in the same branch.

    Later on, if you tag like this:

    $ cp http://svn.vegibank.com/svn/branches/2.3 http://svn.vegibank.com/svn/tags/2.3.0
    

    Your tag 2.3.0 is unlikely to change because the external links and what they link to are all encased by that tag.

    The above is assuming you're sharing the code, and changes in either project should affect the other.

    A better way to do this is for foo to create a compiled object of some sort (like a JAR file or a *.so) that could be stored on a release server. You treat this compiled object as its own project with its own versioning, and your project will depend upon a particular release of this object. Unfortunately, that doesn't always work.

    If you are simply forking the code, do a svn cp from one spot in the repository to the other. You can make your changes without affecting the other project and visa versa. Even better, you could merge changes back and forth between the two locations to keep them somewhat in sync.

    Hope this answers your question. If you can expand your question and give us more details on what you want, I'll be able to update my answer.