Update: Added optional code to show how you would put feature in a branch first rather than just committing directly to the trunk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
#!/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 |