Archive

Archive for May, 2010

With hgsubversion, you can pick and choose.

May 8th, 2010

Something that was not obvious (to me) in the hgsubversion documentation is that you can clone any part of a subversion repository.

#!/bin/bash
# 
# With hgsubversion, you can clone *ANY* folder in a subversion repository. 
# (Well, really any non-empty folder)
# Let me repeat, you do not have to clone the entire repository! It could be
# a branch or even a folder within a branch. If you clone a branch folder,
# your pushed changesets will go into the branch.
# 
# Requires:
#   subversion installed
#   rebase extension
#   hgsubversion extension
#
# We have the following repositories:
#     SVN repo <-> hg-svn
# 
# SVN repo:       company subversion repo on remote server, https://ip/svn
# hg-svn:         local developer copy of SVN repo using hgsubversion 
# 
# Our goal is to clone/checkout only a sub-folder, make changes, and see
# what happens.
# 
# Example:

# Turn on debugging so we can see the commands as they're issued.
set -x
# Clean up after any previous run.
rm -rf folder_test

mkdir folder_test
cd folder_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 mkdir trunk/subfolder
echo "text" >> trunk/subfolder/anotherfile.txt
svn add trunk/subfolder/anotherfile.txt
svn ci -m "Added some files"
cd ..

# Create our clone of SVN. Just grab the folder you want. It could be
# a branch or even a folder in a branch.
hg clone file://`pwd`/SVN/trunk/subfolder hg-svn

# Make some changes
cd hg-svn
echo "more text" >> anotherfile.txt
echo "text" >> newfile.txt
hg add newfile.txt
hg com -m "Made some change in hg."
hg push
cd ..

# Look at the complete subversion repository to see what happened.
cd SVN_temp
svn up

# See that out line was added.
cat trunk/subfolder/anotherfile.txt

# See the new file.
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

Uncategorized

Pushing a new feature from a mercurial repo into an SVN repo

May 7th, 2010

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

Uncategorized