Reputation: 23
I have a trunk on server A and would like to copy the whole SVN repository to server B, i.e. create the same trunk there. I then would like to be able to merge changes done on server A in trunk to server B trunk. Is that possible?
I tried with svn export and then import, but then I cannot do any merging. Any ideas?
Upvotes: 0
Views: 277
Reputation: 4982
SVN isn't like git. Having seperate repositories doesn't allow you to easily merge one to the other.
Let's say A and B are perfect copies with HEAD pointing to revision 10000. A commit by Fred to repo A, will get a revision number of 10001. Then Sally commits something else to repo B which is also 10001. Getting these repos back in sync with identical revision numbers isn't possible.
What is possible is applying patch files. Let's say Fred's company has made 100 commits in repository A. Fred can 'export' those commits with something like this bash script:
for rev in {1000..10100} do
svn log -c $rev --diff > $rev.patch
done
Now Fred has 100 patch files which he can zip up and send it to Sally. '
Sally now needs to "merge" those in with:
for patchfile in $(ls *.patch) do
svn patch $patchfile
svn ci
done
There will be a lot of manual work in checking all changes.
Maintaining this on a busy project will take lots of work, and is probably not the ideal situation. There is lots of potential for human-error and you will have a hard time tracking which revisions have been merged, which need to be sent, etc. Consider rethinking how/why you are doing this and think about if one of these approaches would suit your needs:
My guess is that you are delivering (or receiving) source code from another company. In this case, it might be a good idea to question whether you really need all details of all commits in the duplicated repository. If you consider the source repository as the "vendor", then consider each update of the duplicated repository as "integrating a vendor release". If there are 1000 commits between deliveries, then you can deliver one giant commit representing the new release and do an actual svn merge
of that. In fact, to make things easier, just do a periodic svn export
to make a simple archive with no revision history.
I do this currently. Here are some instructions I wrote for one of my customers (names changed) to help them setup a repository and prepare for our vendor releases:
First set up the repository:
# Start from an empty repository
# Initialize the repository with tags+branches directories
svn mkdir http://example.com/svn/awesomecode/tags
svn mkdir http://example.com/svn/awesomecode/branches
# Extract the contents of the source file.
tar -xf awesomecode_1.27.tar.xz
# Import the contents of that archive into your repository
svn import \
awesomecode_1.27 \
http://example.com/svn/awesomecode/upstream \
-m "Importing upstream version 1.27"
# Tag the upstream version (optional)
svn copy \
http://example.com/svn/awesomecode/upstream \
http://example.com/svn/awesomecode/tags/upstream_1.27 \
-m "Tagging upstream 1.27"
# Make a trunk to do your work in
svn copy \
http://example.com/svn/awesomecode/upstream \
http://example.com/svn/awesomecode/trunk
When we send a source code update, you can update your upstream/vendor branch:
# Checkout the upstream branch of the repository
svn checkout \
http://example.com/svn/awesomecode/upstream \
awesomecode
# Replace the old version
rm -rf awesomecode/*
tar -xf awesomecode_1.28.tar.xz \
--strip-components=1 \
--directory=awesomecode
# Commit the new version (also delete missing and add unversioned files)
cd awesomecode
svn delete $(svn status | sed -ne '/^!/p' | awk '{print $2}')
svn add $(svn status | sed -ne '/^?/p' | awk '{print $2}')
svn commit -m "Importing upstream version 1.28"
# Tag the new delivery:
svn copy \
http://example.com/svn/awesomecode/upstream \
http://example.com/svn/awesomecode/tags/upstream_1.28 \
-m "Tagging upstream 1.28"
# Merge the delivery into your trunk
svn swtich ^/trunk
svn merge ^/upstream
As our trunks diverge over time, this merge will get much more difficult. To make this easier, consider sending some of your changes to us. We will review patches and add things we agree with to our code base. Minimizing differences is the easiest way to keep upstream merges manageable. Please send one patch file per commit. We need to check every change and a 20,000 line patch file cannot be reviewed. To generate patch files from commits 5-10, do this:
for rev in {5..10} do
svn log -c $rev --diff > $rev.patch
done
The most authoritative literature on working with vendor branching is SVN book
Another reason you may want to have the same code in two repositories may be that you simply need the same code in two different projects. This is where svn:externals
comes in handy. You could maintain the common code in an external
repository, and simply have a reference to it in your project. Then, if someone makes a commit to your common code, you can benefit from it on all projects. If your repository is internet-facing, then you can consider having your customer integrate your source-code using svn:externals
too.
First make sure your common code is in a repository, independent of any specific project. Next, in your specific project, you'll need use svn propset
svn propset svn:externals 'http://example.com/svn/common-code/trunk common' .
Now you have a directory called common
in the root of your tree which contains the HEAD revision of the common-code. You can also peg a specific revision (which I recommend so that you can check out old revisions without them breaking). I like to use a script which periodically checks if my external repository has been updated, then bumps the pegged revision.
For more info, see the svn book, or svn help propset
Maybe you want repo B to be a mirror of repo A. If you do that, then repo B should be read-only for normal users, and writable only for the svnsync
process.
I have less experience with svnsync
but it does exist and it is documented here:
http://svnbook.red-bean.com/en/1.7/svn.ref.svnsync.html
Upvotes: 1