Question

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:

  • I have one repository with multiple projects, but i might change this if necessary.
  • I want to shere the source code. its a php project. I am forking the module. (I have a global generic project and if my
    client needs some specific functions,
  • I want to create a separate project for that client (separate in svn also). But i would like to
    have a way to merge some changes made in the main project to the
    client project. (ex: global bug fixes or funcionality).
Was it helpful?

Solution

A few questions:

  • Are you talking about multiple repositories, or multiple projects in the same repository?
  • If you borrow this other module's code, are you keeping it in sync with that other module, or are you forking that module?
  • What do you really want to share? Do you have to share the source, or the compiled output (*.so or *.a in Unix C/C+, *.jar in Java, etc.).

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.

OTHER TIPS

  • If you want to use shared code inside Subversion repository - it's svn:externals
  • If you want port changes from mainline on shared code into customer-specific version of shared code - it's "Vendor branches" in svn lingo

Combined a) and b) will give you needed result

  1. Select some node (outside trunk of customer's repository), which you'll link to shared node in dev-repo
  2. Create external definition (with PEG-revision preferred, if you'll have to have easy time-back for the cost of manual updates of definition after commits to dev-repo)
  3. Copy node to the location, where in must be in live project (svn cp ...)
  4. Code...
  5. When you have changes in dev-repo, which you want to transfer into customer repo - update externals to needed revision, merge "Vendor" node to "Live"

Sample:

If you'll have in customer's repo

  • /vendor/lib (where lib is directory from foreign repo) */trunk/common/lib (customer's version of the lib above)

incorporating changes from lib-mainline is merge from /vendor/lib to /trunk/common/lib (in the corresponding node of Working Copy for your trunk)

David's notes about externals are still valid, correct and useful

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top