Update: Added optional code to show how you would put feature in a branch first rather than just committing directly to the trunk.
#!/bin/bash
#
# Merging a separate feature repository into a folder in an SVN repository by
# way of two hg repositories.
#
# Inspired by: http://hgtip.com/tips/advanced/2009-11-17-combining-repositories/
#
# Requires:
# subversion installed
# convert extension
# mq extension (for strip)
# rebase extension
# hgsubversion extension
#
# We have the following four repositories:
# SVN repo hg-svn hg-svn-work
# feature
#
# SVN repo: company subversion repo on remote server, https://ip/svn
# hg-svn: local developer copy of SVN repo using hgsubversion
# hg-svn-work: a local working copy of hg-svn. (Why? In my case,
# it's inside a Linux virtual machine running on a Mac.
# hg-svn is on the Mac.)
# feature: a completely separate hg repository containing some new
# program developed in isolation. (Perhaps a contract job?)
#
# Our goal is to put feature and all of its history into SVN, but we must
# place it into a sub-folder /new/feature.
#
# Steps:
# 1. Use hg convert to re-map feature/* to feature/new/feature/*.
# 2. Hg pull the converted feature repo into hg-svn-work.
# 3. Hg rebase the pulled feature onto the previous tip.
# 4. Hg push the changes to hg-svn
# 5. Hg push from hg-svn into the SVN repo.
# 6. Hg pull changes from hg-svn into hg-svn-work
# 7. Hg strip the pulled feature changesets from step 2.
#
# Using a feature branch:
# It would be nice to put feature into its own subversion branch
# first and then merge it back into the trunk. If you'd like to do
# this, enable USE_A_BRANCH below.
USE_A_BRANCH=1 # enable = 1
# Example:
# Turn on debugging so we can see the commands as they're issued.
set -x
# Clean up after any previous run.
rm -rf feature_test
mkdir feature_test
cd feature_test
# Create a "company" SVN repository.
svnadmin create SVN
svn co file://`pwd`/SVN SVN_temp
# Put something in the SVN repository or we won't be able
# to see why some of the steps are necessary.
cd SVN_temp/
svn mkdir trunk tags branches
svn ci -m "Initial folders"
echo "Company file" > trunk/company.txt
svn add trunk/company.txt
svn ci -m "Added company.txt"
cd ..
if [ "$USE_A_BRANCH" = "1" ]; then
# Create a feature branch in subversion
svn copy file://`pwd`/SVN/trunk file://`pwd`/SVN/branches/feature -m "Added feature branch"
fi
# Create our first and second level clones of SVN.
if [ "$USE_A_BRANCH" = "1" ]; then
# Make sure to clone the new branch!
hg clone file://`pwd`/SVN/branches/feature hg-svn
else
hg clone file://`pwd`/SVN/trunk hg-svn
fi
hg clone hg-svn hg-svn-work
# Create a new feature in its own repository. It needs more than one
# changeset to show how hgsubversion will rebase after pushing each
# changeset.
hg init feature
cd feature
echo "Some text" >> readme.txt
hg add readme.txt
hg com -m "Added readme.txt"
echo "Some more text" >> readme.txt
hg com -m "Added more text"
cd ..
# Create a clone/copy of feature where we move everything into the
# subfolder that it needs to be in for the company SVN layout.
echo "rename . new/feature" > map.txt
hg convert --filemap map.txt feature feature-conv
rm map.txt
# Pull the converted feature repository into our working
# copy of the SVN repository. Save the current tip since we will
# need it to rebase.
cd hg-svn-work/
OLD_TIP=`hg log --template "{rev}\n" -r tip`
hg pull -f ../feature-conv
# All of the new changesets start from OLD_TIP + 1. Rebase them on
# OLD_TIP.
hg rebase --source $(($OLD_TIP + 1)) --dest $OLD_TIP
# Push the changes up one level to hg-svn
hg push
cd ..
# Clean up the feature copy.
rm -rf feature-conv
cd hg-svn/
# Update hg-svn since hgsubversion will not detect any outgoing
# changesets otherwise.
hg up
# Push the changes to SVN. Each changeset pushed will cause a rebase.
# If you are pushing a lot of changesets (e.g. I did 85), this will take a
# while since the algorithm is O(n^2). The first push of N changesets rebases
# N-1 changesets, then the next rebases N-2, etc. It will appear pleasantly
# faster as it goes.
hg push
cd ..
# Pull the newly rebased changesets back to our working repository.
# Unfortunately, we've now done half of an svn push/rebase here. We need
# to manually strip away all of the revisions we pulled from feature-conv
# earlier as they've all been duplicated now.
cd hg-svn-work/
hg pull
hg strip -f -n $(($OLD_TIP + 1))
cd ..
cd SVN_temp
svn up
if [ "$USE_A_BRANCH" = "1" ]; then
# Optionally, merge the svn feature branch back to the trunk
# Note: I don't know (yet) of a simpler way to do this.
DIR=$(dirname $(pwd))
svn merge file://$DIR/SVN/branches/feature trunk
svn ci -m "Merging feature branch back to trunk"
svn delete branches/feature
svn ci -m "Closing feature branch"
fi
set +x
echo "=========================="
echo "Results:"
find . | egrep -v '\.svn'
cd ..
# Use the following command to see the log of changes:
# svn log -v SVN_temp
Leave a Reply