I am working on a team that uses SVN primarily, whereas I prefer to use Mercurial when possible. I set up an hg clone of the SVN repo using hgsubversion, and several basic pulls/commits/pushes seemed to function fine.
Now after 2 weeks of local development (during which time I've merged in changes from an external hg repo, and merged in changes from the SVN repo multiple times), I've attempted to push to the SVN repo, but failed with this message:
abort: Sorry, can't find svn parent of a merge revision.
I've found other users encountering the same problem, with how-tos on how to avoid this issue going forward, but I haven't encountered anything that seems to address condensing multiple parallel commits to clean up an existing hgsubversion repo.
What is the best way that I can rectify matters without losing my own commits? (With step-by-step instructions?)
You can't push hg merges into a subversion repository, since SVN can't understand them. You need to rebase your changes on top of the latest SVN commit.
Edit Steps to flatten the history:
Warning, be prepared to do have lots of merge conflicts
You need the mq and rebase extension activated
The first step is to create a backup repo, since you will need it as a reference for the upcoming merge conflicts (expect many of them).
Say your graph looks like this:
C1--C2--C3------M1--C5--C6--C7---M2--
\ / \ /
\--B1--B2--/ \--B3--B4-B5-/
Then the second step is to rebase B1+B2 on top of C3: hg rebase -b B2 -d C3
-b
use the common base of both branches as the start for the branch to rebase, so mercurial finds that B1 is the first deviation commit und uses this even when you say B2 to rebase.
-d
specifies the destination of the rebased branch.
Wen you encounter merge conflicts then ensure that the result of B2' = M1, else you will get lots of conflicts in the following revisions.
Afterwards Merge M1 is gone and your graph looks like this:
C1--C2--C3--B1'--B2'--C5'--C6'--C7'---M2'--
\ /
\--B3'--B4'-B5'-/
and now you do the same for the second merge: hg rebase -b B3' -d C7'
, which makes your repo look like this:
C1--C2--C3--B1'--B2'--C5'--C6'--C7'--B3''--B4''--B5''
Repeat until you have an all linear version history.
After you have flattened the history you need to reorder your commits on top of the svn commits.
Say your repo now looks like this (S=subversion commit, C=local commit):
S1--S2--S3--C1--C2--S4--S5--C3-C4--C5--C6--C7--S6--S7
Now you import everything from (including) C1 into a mercurial queue (hg qimport -rC1:
). To view all created patches use hg qseries
.
Then you unapply all patches (hg qgoto C1.diff [this is the first one in qseries]
, followed by hg qpop
). Then you remove the subversion ones (hg qdelete S4.diff S5.diff S6.diff S7.diff
).
Now is the time to re-fetch the svn commits (hg pull »svn-remote«
). Then you reapply all local patches, one by one with hg qpush
, and fix all merge conflicts which are now occurring. When you are done with one conflict, you can move the current patch into a mercurial commit with hg qfinish -a
, and send your current state with hg push »svn-remote«
.