I'm investigating a discrepancy that shows up, when 'symmetric merge' is enabled [1], in the notifications printed by some merges. Merge_tests 78 fails because the expected notification for the last merge is:
--- Merging r6 through r9 into 'H_COPY':
U H_COPY/psi
D H_COPY/nu
--- Recording mergeinfo for merge of r6 through r9 into 'H_COPY':
U H_COPY
but the first line of that changes to:
--- Merging r7 through r9 into 'H_COPY':
while the rest stays the same. In this instance the difference is probably
harmless since r6 is a no-op in the merge source, but we need to check whether
this is a symptom of a wider problem.
NEW TEST FOR THIS ISSUE
I have simplified the recipe into a new test, merge_tests-130 in
the attached patch [2]. I removed the '--force' option, and this changes
things such that the merge prints a separate notification for the subtree.
Also
in that patch are some debug prints in the merge code which help to
trace the source of the problem. A diagram of the test scenario:
# merge -c4 A/D/H/nu@4 H_COPY/nu
# | merge A/D/H H_COPY
# | |
# A/D/H A---------------
# +-psi +---------M-----
# +-nu A---M-D
# H_COPY C----------G
# +-psi +----------+
# +-nu +-------G--+
# 1 2 3 4 5 6 wc wc
#
# Key: Add Mod Del Copy merGe
The difference in outputs ('-': existing 1.7 merge, '+': symmetric merge):
I: CMD: svn merge ^/A/D/H H_COPY
I: DBG: merge.c:8568: 1: ...130/H_COPY: 3-6
I: DBG: merge.c:8568: 1: .../H_COPY/nu: 3,5-6
I: DBG: merge.c:8568: 2: ...130/H_COPY: 3-6
I: DBG: merge.c:8568: 2: .../H_COPY/nu: 3,5-6
I: DBG: merge.c:8568: 3: ...130/H_COPY: 3-6
-I: DBG: merge.c:8568: 3: .../H_COPY/nu: 3-6
+I: DBG: merge.c:8568: 3: .../H_COPY/nu: 3,5-6
-I: --- Merging r3 through r6 into 'H_COPY':
+I: --- Merging r4 through r6 into 'H_COPY':
I: U H_COPY/psi
-I: --- Merging r3 through r6 into 'H_COPY/nu':
+I: --- Merging r5 through r6 into 'H_COPY/nu':
I: C H_COPY/nu
I: --- Recording mergeinfo for merge of r3 through r6 into 'H_COPY':
I: U H_COPY
I: --- Recording mergeinfo for merge of r3 through r6 into 'H_COPY/nu':
I: G H_COPY/nu
I: --- Eliding mergeinfo from 'H_COPY/nu':
I: U H_COPY/nu
I: Summary of conflicts:
I: Tree conflicts: 1
The immediate cause of the discrepancy is that the symmetric merge code
passes the YCA revision as the beginning of the range to be merged,
whereas the existing merge code passes revision '1' as the beginning of
the range to be merged. At the beginning of the main loop in do_merge():
- source = {loc1 = "/A/D/H@1", loc2 = "/A/D/H@6", ancestral = TRUE}
+ source = {loc1 = "/A/D/H@2", loc2 = "/A/D/H@6", ancestral = TRUE}
The underlying problem -- the reason why the merge code doesn't resolve these
two requests to the same result -- is deeper, involving the function
fix_deleted_subtree_ranges(). That function yields
(child 'H_COPY/nu')->remaining_ranges = 3-6
for the 1.7 merge and
(child 'H_COPY/nu')->remaining_ranges = 3,5-6
for the symmetric merge.
Revision 4 has already been merged to 'H_COPY/nu', so it should not be merged
again; but that doesn't mean 'remaining_ranges = 3-6' is wrong.
fix_deleted_subtree_ranges() is designed to set a subtree's remaining range to
match its parent's remaining range if the subtree doesn't need a separate
editor drive. The function appears to be concluding in the first case that the
subtree doesn't need a separate editor drive (since, over the range 3-6, the
net result is simply to delete the subtree), but in the second case that it
does and should be split into two sub-ranges.
I'm not sure whether one of those conclusions is right and the other wrong;
maybe both are OK. I'm not sure why there are two different conclusions.
TREE CONFLICT
Another issue I have identified here is that, in either case, a tree conflict
is flagged unnecessarily on 'nu'. (That doesn't happen in merge_tests-78
because that test passes the '--force' flag.)
In the 1.7 case, the merge reports that it is merging 'r3 through r6', and the
conflict details are reported as:
$ svn info H_COPY/nu
Tree conflict: local edit, incoming delete upon merge
Source left: (file) ^/A/D/H/nu@1
Source right: (file) ^/A/D/H/nu@6
First, we notice that the reported 'left' and 'right' details don't match up
with the description as an incoming 'delete'. I recall that's a long-standing
error in the conflict reporting.
The working file to be deleted ('H_COPY/nu' with r4 merged in to it) has
content that doesn't match the expected pre-delete content (A/D/H/nu@2, because
the revs to be merged are 3-6). I haven't checked the detection code yet, but
if that's why the conflict is flagged, then clearly the tree-conflict logic
that says 'the content should match that at the beginning of the range being
merged' is incompatible with the logic of fix_deleted_subtree_ranges() which
says 'there is no need to calculate the exact ranges to be merged if the end
result is just a delete'.
In the symmetric merge case, the merge reports that it is merging 'r5 through
r6', and the conflict details are:
Tree conflict: local edit, incoming delete upon merge
Source left: (file) ^/A/D/H/nu@2
Source right: (file) ^/A/D/H/nu@6
I don't know why that's flagging a conflict there -- do we flag a conflict just
because it has local mod, regardless that it may have the expected content?
CONCLUSIONS SO FAR
* There's a deficiency in fix_deleted_subtree_ranges() -- it should at least
give consistent results with these two different input ranges.
* As a temporary or diagnostic measure we might be able to make 'symmetric
merge' give the same result by making it pass the oldest possible revision (1)
instead of the YCA revision (2) as the beginning of the range to consider.
* There's a deficiency in conflict detection.
I will continue to investigate all of this, but any assistance is very welcome.
- Julian
[1] Patch to enable symmetric merge: attachment 'use-symmetric-merge-1.patch'.
[2] New test and debug prints: attachment 'deleted-subtree-ranges-1.patch'.
--
Certified & Supported Apache Subversion Downloads:
http://www.wandisco.com/subversion/download
deleted-subtree-ranges-1.patch
Description: Binary data
use-symmetric-merge-1.patch
Description: Binary data

