At work we use svn, with svnmerge for managing branches (most projects tend to use a trunk with a stable branch or two). I’m pretty much a svnmerge newbie, so every now and then I mess up one of my trees. When that happens, I’m lucky enough to have a fair share of total svn experts around to help me figure out what happened.
So here’s a little test scenario that shows what kind of merge conflict you tend to get when you cherry-pick a change to merge to stable, out of chronological order of change to the trunk, and then later you merge an older change that has a conflicting line in it:
$ cd /tmp $ mkdir svnmergetest $ cd svnmergetest $ mkdir repo $ svnadmin create /tmp/svnmergetest/repo $ svn co file:///tmp/svnmergetest/repo co Checked out revision 0. $ cd co $ svn mkdir trunk A $ cd trunk $ cat > A <<END > line ASTART > line A1 > line A2 > line AEND > END $ svn add A A A $ svn commit -m "Init trunk" Adding Adding trunk/A Transmitting file data . Committed revision 1. $ cat > A <<END > line ASTART > line A1 > line A3 > line AEND > END $ svn diff A Index: A =================================================================== --- A (revision 1) +++ A (working copy) @@ -1,4 +1,4 @@ line ASTART line A1 - line A2 + line A3 line AEND $ svn commit -m "commit 1" Sending trunk/A Transmitting file data . Committed revision 2. $ cat > A <<END > line ASTART > line A1 > line A4 > line AEND > END $ svn diff A Index: A =================================================================== --- A (revision 2) +++ A (working copy) @@ -1,4 +1,4 @@ line ASTART line A1 - line A3 + line A4 line AEND $ svn commit -m "commit 2" Sending trunk/A Transmitting file data . Committed revision 3. $ cd .. # FWIW, I messed up commit in 4, and 5, commit 6 is to un-do the mess-up $ svn cp -m "Init stable" -r 1 file:///tmp/svnmergetest/repo/trunk \ > file:///tmp/svnmergetest/repo/stable Committed revision 7. $ svn up A stable A stable/A Updated to revision 7. $ cd stable $ cat A line ASTART line A1 line A2 line AEND $ svnmerge.py init property 'svnmerge-integrated' set on '.' $ svn commit -F svnmerge-commit-message.txt Sending Committed revision 8. $ rm svnmerge-commit-message.txt $ svnmerge.py avail 2-3 $ svnmerge.py merge 3 svnmerge: "3" is not a subversion working directory $ svnmerge.py merge -r 3 C A property 'svnmerge-integrated' set on '.' $ cat A line ASTART line A1 <<<<<<>>>>>> .merge-right.r3 line AEND $ cat > A <<END > line ASTART > line A1 > line A4 > line AEND > END $ svn resolved A Resolved conflicted state of 'A' $ svn diff Property changes on: . ___________________________________________________________________ Name: svnmerge-integrated - /trunk:1 + /trunk:1,3 Index: A =================================================================== --- A (revision 7) +++ A (working copy) @@ -1,4 +1,4 @@ line ASTART line A1 - line A2 + line A4 line AEND $ svn commit -m "Hand-resolve merge conflict" Sending Sending stable/A Transmitting file data . Committed revision 9. $ svnmerge.py avail 2 svnmerge.py merge -r 2 C A property 'svnmerge-integrated' set on '.' $ cat A line ASTART line A1 <<<<<<>>>>>> .merge-right.r2 line AEND $ cat > A <<END > line ASTART > line A1 > line A4 > line AEND > END $ svn resolved A Resolved conflicted state of 'A' $ svn diff Property changes on: . ___________________________________________________________________ Name: svnmerge-integrated - /trunk:1,3 + /trunk:1-3 $ svn commit -m "Hand-resolve merge conflict" Sending Committed revision 10.
Justin tells me there’s very little in terms of handy fancy dandy software tooling that magically does the ‘right thing’ here without a human’s intervention. The main reason for that is that there is, fundamentally, no ‘right thing’.
So it’s possible to resolve this cleanly, and svn + svnmerge make it pretty clear what is going on, but it’s still a bit of work to figure out what to do. To stay out of trouble, it’s a safe bet that you should limit cherry picking as much as possible, and try and do merges between branches in chronological order whenever you can.