Paul Hammant's Blog: Subversion Merge Limitations
Regular readers know why I want a branching model for a non-development purpose and with merge directions like so:
This article isn’t about that as such, but is about the merge capabilities of Subversion 1.9.7. Take just the bottom-right of that diagram
/baz/PROD. I want to merge back and forth between the two. Say ‘baz’ is a person, and I’ve launched a UAT and PROD environment for them. There’s only one file within, and for our purposes I’ve called it testfile.txt.
I’ve made a Github repo that has some Mac-flavored bash scripts to show the merge limitation I’m talking about: github.com/paul-hammant/subversion_testing. Make sure you’ve installed subversion 1.9.7.
Test one - merging one way - all good
Here’s were going to test the merging of some individual commits, out of order, from one branch to a second.
In order, run these:
./reset.sh ./server.sh ./test_of_out_order_merges_from_one_branch_to_another.sh
Make sure to read the test script. It’s supposed to merge bunch of changes from ‘one’ to ‘two’, but out of order.
The file one/testfile.txt starts like this:
a b c d e
And changes in five one-line commits to:
a aa b bbb c cccc d ddddd e eeeeee
A second branch ‘two’ is made from the original starting position, and the same five commits are cherry-picked from the ‘one’ branch to that new one, but out of order to try to confuse the Subversion merge tracking.
Note that these lines towards the end of the output of the third bash script:
Mergeinfo, after merge of all the individual commits (out of order) /one:3-7 Mergeinfo, after merge of all the remaining commits (whatever that means) /one:2-12
Subversion is weird - there was nothing more to merge (in terms of commits) at all in the second of those, yet it wants to make extra “mergeinfo” commit, as the changing range show. Specifically, mergeinfo change from “/one:3-7” to “/one:2-12”. Still, whether “/one:3-7” or “/one:2-12” it is vast simplification (and retroactive tidy-up) of the mid-point of the series of merges where it was reported as “/one:3,5,7” (the first three of five cherry-pick merges).
Test two - merging back has a bug
Here we are going to test the merging of some individual commits out of order from the second branch to the back to the first.
In order, run these:
./reset.sh ./server.sh ./test_of_out_order_merges_back_the_original_branch.sh
This runs the first bash script silently - making the ‘one’ and the ‘two’ branch, then makes five more one-line commits leaving the document in ‘two’ like so:
a !! aa b !! bbb c !! cccc d !! ddddd e !! eeeeee
Then, each those commits are merge back to ‘one’, but again out of order. Here’s the last chunk of command output, where it barfs unexpectedly:
Mergeinfo, after merge of all the individual commits (out of order) /two:14-18 Contents of testfile.txt on branch 'one': a !! aa b !! bbb c !! cccc d !! ddddd e !! eeeeee Contents of testfile.txt on branch 'two' (they are the same, as a result of merges): a !! aa b !! bbb c !! cccc d !! ddddd e !! eeeeee Attempt redundant merge of branch two into branch one (individual commits are merged already, and files at HEAD revision are idential): --- Merging r2 through r13 into 'one': C one/testfile.txt --- Recording mergeinfo for merge of r2 through r13 into 'one': U one Summary of conflicts: Text conflicts: 1 Conflict discovered in file 'one/testfile.txt'. Select: (p) postpone, (df) show diff, (e) edit file, (m) merge, (mc) my side of conflict, (tc) their side of conflict, (s) show all options: $ <CTRL-C> svn: E155027: Unable to resolve conflicts on '/path/to/subversion_testing/client_data/wc/one/testfile.txt' svn: E200015: The operation was interrupted svn: E155015: Commit failed (details follow): svn: E155015: Aborting commit: '/path/to/subversion_testing/client_data/wc/one/testfile.txt' remains in conflict
That makes no sense. The files are identical - there’s nothing to merge. All the individual changes were merged back cherry-pick style, so why is there merge conflict?
Reintegration handling changed in Subversion 1.8, but the same bug is shown in Subversion 1.6 and 1.7 (good old homebrew). You can get it to not barf, by adding a judicious
--record-only to the merge that should be a no-op. You can’t tell though and it should not be unreasonable to ask the merge engine whether there’s any pending merges or not.
Here’s what svn-diff says at the merge-conflict point (if instead of the attempt to merge):
Index: . =================================================================== --- . (.../two) (revision 23) +++ . (.../one) (revision 23) Property changes on: . ___________________________________________________________________ Modified: svn:mergeinfo ## -0,1 +0,1 ## Reverse-merged /one:r2-12 Merged /two:r14-18
Thus, I’m left thinking that Subversion cannot be the backing-store for my config centric usage of source-control. I’m also thinking that there’s breakages that regular developers will encounter with Subversion if they try more esoteric branching models. Of course, for software development in a team, you should be doing trunk based development as Google, Facebook and others do.
One more thing: There is a
--reintegrate option for Subversion’s merge engine. That mode of operation is not available in the cherry-pick merge back scenarios, sadly:
svn: E205000: -r and -c can't be used with --reintegrate
June 2017, Subversion 1.9.5 (r1770682)
Sept 2017, Subversion 1.9.7 (r1800392) - this page updated accordingly.
Still an issue.