You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2013/02/02 22:11:02 UTC
svn commit: r1441810 - in /subversion/trunk/subversion:
libsvn_client/merge.c tests/cmdline/merge_tests.py
Author: julianfoad
Date: Sat Feb 2 21:11:02 2013
New Revision: 1441810
URL: http://svn.apache.org/viewvc?rev=1441810&view=rev
Log:
Fix two errors in how a single-file merge stops if there conflicts. (1) It
didn't abort if there were conflicts on the last sub-range of a non-last
requested range. (2) When aborting with conflicts it recorded mergeinfo
describing only the current sub-range, not the sub-ranges merged before the
conflict.
* subversion/libsvn_client/merge.c
(do_file_merge): Take an 'abort_on-conflicts' flag and use it so that we
abort on conflicts in all but the last sub-range of the last specified
range, just like in do_directory_merge(). Record the right mergeinfo
when aborting.
(do_merge): Pass that flag.
* subversion/tests/cmdline/merge_tests.py
(conflict_aborted_mergeinfo_described_partial_merge): Test more cases.
Modified:
subversion/trunk/subversion/libsvn_client/merge.c
subversion/trunk/subversion/tests/cmdline/merge_tests.py
Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1441810&r1=1441809&r2=1441810&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Sat Feb 2 21:11:02 2013
@@ -7083,6 +7083,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
const svn_diff_tree_processor_t *processor,
svn_boolean_t sources_related,
svn_boolean_t squelch_mergeinfo_notifications,
+ svn_boolean_t abort_on_conflicts,
merge_cmd_baton_t *merge_b,
apr_pool_t *scratch_pool)
{
@@ -7316,10 +7317,13 @@ do_file_merge(svn_mergeinfo_catalog_t re
processor,
iterpool));
}
- if ((i < (ranges_to_merge->nelts - 1))
+ if ((i < (ranges_to_merge->nelts - 1) || abort_on_conflicts)
&& is_path_conflicted_by_merge(merge_b))
{
conflicted_range = svn_merge_range_dup(r, scratch_pool);
+ /* Only record partial mergeinfo if only a partial merge was
+ performed before a conflict was encountered. */
+ range.end = r->end;
break;
}
}
@@ -7345,9 +7349,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
&filtered_rangelist,
mergeinfo_path,
merge_target->implicit_mergeinfo,
- /* Only record partial mergeinfo if only a partial merge was
- performed before a conflict was encountered. */
- conflicted_range ? conflicted_range : &range,
+ &range,
iterpool));
/* Only record mergeinfo if there is something other than
@@ -9463,6 +9465,11 @@ do_merge(apr_hash_t **modified_subtrees,
svn_node_kind_t src1_kind;
merge_source_t *source =
APR_ARRAY_IDX(merge_sources, i, merge_source_t *);
+ /* If conflicts occur while merging any but the very last
+ * revision range we want an error to be raised that aborts
+ * the merge operation. The user will be asked to resolve conflicts
+ * before merging subsequent revision ranges. */
+ svn_boolean_t abort_on_conflicts = (i < merge_sources->nelts - 1);
svn_pool_clear(iterpool);
@@ -9512,16 +9519,11 @@ do_merge(apr_hash_t **modified_subtrees,
processor,
sources_related,
squelch_mergeinfo_notifications,
+ abort_on_conflicts,
&merge_cmd_baton, iterpool));
}
else /* Directory */
{
- /* If conflicts occur while merging any but the very last
- * revision range we want an error to be raised that aborts
- * the merge operation. The user will be asked to resolve conflicts
- * before merging subsequent revision ranges. */
- svn_boolean_t abort_on_conflicts = (i < merge_sources->nelts - 1);
-
SVN_ERR(do_directory_merge(result_catalog,
source, target->abspath,
processor,
Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=1441810&r1=1441809&r2=1441810&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Sat Feb 2 21:11:02 2013
@@ -18191,46 +18191,108 @@ def conflict_aborted_mergeinfo_described
sbox.build()
- iota_copy_path = sbox.ospath('iota-copy')
-
- # r2
- sbox.simple_copy('iota', 'iota-copy')
+ trunk = 'A'
+ branch = 'A2'
+ file = 'mu'
+ trunk_file = 'A/mu'
+
+ # r2: initial state
+ for rev in range(4, 11):
+ sbox.simple_propset('prop-' + str(rev), 'Old pval ' + str(rev),
+ trunk_file)
sbox.simple_commit()
- # r3
- sbox.simple_append('iota', 'new line in r3\n')
+ # r3: branch
+ sbox.simple_copy(trunk, branch)
sbox.simple_commit()
- # r4
- sbox.simple_append('iota', 'new line in r4\n')
- sbox.simple_commit()
+ zero_rev = 3
- # r5
- sbox.simple_append('iota', 'new line in r5\n')
- sbox.simple_commit()
+ def edit_file(path, rev, val):
+ """Make a local edit to the file at PATH."""
+ sbox.simple_propset('prop-' + str(rev), val + ' pval ' + str(rev), path)
+
+ # r4 through r13: simple edits
+ for rev in range(4, 11):
+ edit_file(trunk_file, rev, 'Edited')
+ sbox.simple_commit()
- # r6 Merge r4 from iota to iota-moved
- svntest.actions.run_and_verify_svn(None, None, [], 'merge', '^/iota',
- '-c', '4', iota_copy_path, '--accept',
- 'theirs-conflict')
+ # r14: merge some changes to the branch so that later merges will be split
+ svntest.actions.run_and_verify_svn(None, None, [], 'merge', '-c5,9',
+ '^/' + trunk, sbox.ospath(branch),
+ '--accept', 'theirs-conflict')
sbox.simple_commit()
- # Merge everything (i.e. r2 and r5) from iota to iota-moved.
- # This is split into to merges, first of r2 and then of r5.
- # But since we are postponing conflict resolution, the merge
- # should stop after r2 is merged, allowing us to resolve and
- # repeat the merge at which point r5 can be merged. The mergeinfo
- # on iota-copy then should only reflect that r2 and r3 have been
- # merged from ^/iota; r5 should not be present.
- svntest.actions.run_and_verify_svn(None, None, '.*', 'merge', '^/iota',
- iota_copy_path, '--accept', 'postpone')
-
- # Previously this test failed because the merge failed after merging
- # only r2 (as it should) but mergeinfo for r5-6 was recorded, preventing
- # subsequent repeat merges from applying the operative r5.
- svntest.actions.run_and_verify_svn(
- "Incorrect mergeinfo set during conflict aborted merge",
- ['/iota:2-4\n'], [], 'pg', SVN_PROP_MERGEINFO, iota_copy_path)
+ def try_merge(target, conflict_rev, rev_ranges, mergeinfo, expect_error=True):
+ """Revert TARGET_PATH in the branch; merge TARGET_PATH in the trunk
+ to TARGET_PATH in the branch; expect to find MERGEINFO.
+ """
+ src_url = '^/' + trunk + '/' + target
+ src_path = trunk + '/' + target
+ tgt_path = branch + '/' + target
+ svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R',
+ sbox.ospath(tgt_path))
+ edit_file(tgt_path, conflict_rev, 'Conflict')
+ if expect_error:
+ expected_error = ('^svn: E155015: .* conflicts were produced .* into$'
+ "|^'.*" + sbox.ospath(tgt_path) + "' --$"
+ '|^resolve all conflicts .* remaining$'
+ '|^unmerged revisions$')
+ else:
+ expected_error = []
+ svntest.actions.run_and_verify_svn(None, None, expected_error,
+ 'merge',
+ src_url, sbox.ospath(tgt_path),
+ '--accept', 'postpone',
+ *rev_ranges)
+ expected_out = ['/' + src_path + ':' + mergeinfo + '\n']
+ svntest.actions.run_and_verify_svn(
+ "Incorrect mergeinfo set during conflict aborted merge",
+ expected_out, [], 'pg', SVN_PROP_MERGEINFO, sbox.ospath(tgt_path))
+
+ # In a mergeinfo-aware merge, each specified revision range is split
+ # internally into sub-ranges, to avoid any already-merged revisions.
+ #
+ # From white-box inspection, we see there are code paths that treat
+ # the last specified range and the last sub-range specially. The
+ # first specified range or sub-range is not treated specially in terms
+ # of the code paths, although it might be in terms of data flow.
+ #
+ # We test merges that raise a conflict in the first and last sub-range
+ # of the first and last specified range.
+
+ # First test: Merge "everything" to the branch.
+ #
+ # This merge is split into three sub-ranges: r3-4, r6-8, r10-head.
+ # We have arranged that the merge will raise a conflict in the first
+ # sub-range. Since we are postponing conflict resolution, the merge
+ # should stop after the first sub-range, allowing us to resolve and
+ # repeat the merge at which point the next sub-range(s) can be merged.
+ # The mergeinfo on the target then should only reflect that the first
+ # sub-range (r3-4) has been merged.
+ #
+ # Previously the merge failed after merging only r3-4 (as it should)
+ # but mergeinfo for the whole range was recorded, preventing subsequent
+ # repeat merges from applying the rest of the source changes.
+ try_merge(file, 4, [], '3-5,9')
+
+ # Try a multiple-range merge that raises a conflict in the
+ # first sub-range in the first specified range.
+ try_merge(file, 4, ['-r1:6', '-r7:10'], '3-5,9')
+
+ # Try a multiple-range merge that raises a conflict in the
+ # last sub-range in the first specified range.
+ try_merge(file, 6, ['-r1:6', '-r7:10'], '3-6,9')
+
+ # Try a multiple-range merge that raises a conflict in the
+ # first sub-range in the last specified range.
+ try_merge(file, 8, ['-r1:6', '-r7:10'], '3-6,8-9')
+
+ # Try a multiple-range merge that raises a conflict in the
+ # last sub-range in the last specified range.
+ # (Expect no error, because 'svn merge' does not throw an error if
+ # there is no more merging to do when a conflict occurs.)
+ try_merge(file, 10, ['-r1:6', '-r7:10'], '3-6,8-10', expect_error=False)
@SkipUnless(server_has_mergeinfo)
@Issue(4310)