You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2011/08/22 22:57:22 UTC
svn commit: r1160432 - in /subversion/branches/issue-3975/subversion:
libsvn_client/merge.c tests/cmdline/merge_authz_tests.py
tests/cmdline/merge_reintegrate_tests.py tests/cmdline/merge_tests.py
Author: pburba
Date: Mon Aug 22 20:57:21 2011
New Revision: 1160432
URL: http://svn.apache.org/viewvc?rev=1160432&view=rev
Log:
On the issue-3975 branch: Don't add subtree mergeinfo to describe a merge
if such mergeinfo describes non-existent sources or other lines of history.
* subversion/libsvn_client/merge.c
(calculate_merge_inheritance): Add an output argument to communicate back
to the caller what inheritance was set.
(record_mergeinfo_for_dir_merge): When describing a merge, don't set
mergeinfo on subtrees which contains non-existent merge sources or
different lines of history which happen to share the same path.
* subversion/tests/cmdline/merge_authz_tests.py
(mergeinfo_and_skipped_paths): Don't expect mergeinfo describing
non-existent paths on a subtree added by a merge.
* subversion/tests/cmdline/merge_reintegrate_tests.py
(reintegrate_with_rename,
reintegrate_with_subtree_mergeinfo): Don't expect mergeinfo describing
non-existent paths on a subtree added by a merge.
(added_subtrees_with_mergeinfo_break_reintegrate): Adjust expected
mergeinfo such that added subtrees get mergeinfo describing the merge.
* subversion/tests/cmdline/merge_tests.py
(dont_explicitly_record_implicit_mergeinfo): Don't expect subtree elision
because we are no longer setting non-existent mergeinfo on the subtree.
(no_self_referential_filtering_on_added_path): Don't expect mergeinfo
describing non-existent paths on a subtree added by a merge.
Modified:
subversion/branches/issue-3975/subversion/libsvn_client/merge.c
subversion/branches/issue-3975/subversion/tests/cmdline/merge_authz_tests.py
subversion/branches/issue-3975/subversion/tests/cmdline/merge_reintegrate_tests.py
subversion/branches/issue-3975/subversion/tests/cmdline/merge_tests.py
Modified: subversion/branches/issue-3975/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/libsvn_client/merge.c?rev=1160432&r1=1160431&r2=1160432&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/issue-3975/subversion/libsvn_client/merge.c Mon Aug 22 20:57:21 2011
@@ -4480,7 +4480,8 @@ populate_remaining_ranges(apr_array_head
/* Helper for record_mergeinfo_for_dir_merge().
Adjust, in place, the inheritability of the ranges in RANGELIST to
- describe a merge of RANGELIST into WC_WCPATH at depth DEPTH.
+ describe a merge of RANGELIST into WC_WCPATH at depth DEPTH. Set
+ *RANGELIST_INHERITANCE to the inheritability set.
WC_PATH_IS_MERGE_TARGET is true if WC_PATH is the target of the merge,
otherwise WC_PATH is a subtree.
@@ -4492,6 +4493,7 @@ populate_remaining_ranges(apr_array_head
Perform any temporary allocations in SCRATCH_POOL. */
static svn_error_t *
calculate_merge_inheritance(apr_array_header_t *rangelist,
+ svn_boolean_t *rangelist_inheritance,
const char *local_abspath,
svn_boolean_t wc_path_is_merge_target,
svn_boolean_t wc_path_has_missing_child,
@@ -4503,6 +4505,10 @@ calculate_merge_inheritance(apr_array_he
SVN_ERR(svn_wc_read_kind(&path_kind, wc_ctx, local_abspath, FALSE,
scratch_pool));
+
+ /* Starting assumption. */
+ *rangelist_inheritance = TRUE;
+
if (path_kind == svn_node_file)
{
/* Files *never* have non-inheritable mergeinfo. */
@@ -4515,17 +4521,27 @@ calculate_merge_inheritance(apr_array_he
if (wc_path_has_missing_child
|| depth == svn_depth_files
|| depth == svn_depth_empty)
- svn_rangelist__set_inheritance(rangelist, FALSE);
+ {
+ svn_rangelist__set_inheritance(rangelist, FALSE);
+ *rangelist_inheritance = FALSE;
+ }
else /* depth == svn_depth_files || depth == svn_depth_empty */
- svn_rangelist__set_inheritance(rangelist, TRUE);
+ {
+ svn_rangelist__set_inheritance(rangelist, TRUE);
+ }
}
else /* WC_PATH is a directory subtree of the target. */
{
if (wc_path_has_missing_child
|| depth == svn_depth_immediates)
- svn_rangelist__set_inheritance(rangelist, FALSE);
+ {
+ svn_rangelist__set_inheritance(rangelist, FALSE);
+ *rangelist_inheritance = FALSE;
+ }
else /* depth == infinity */
- svn_rangelist__set_inheritance(rangelist, TRUE);
+ {
+ svn_rangelist__set_inheritance(rangelist, TRUE);
+ }
}
}
return SVN_NO_ERROR;
@@ -7599,6 +7615,7 @@ record_mergeinfo_for_dir_merge(svn_merge
else /* Record mergeinfo on CHILD. */
{
svn_boolean_t child_is_deleted;
+ svn_boolean_t rangelist_inheritance;
/* If CHILD is deleted we don't need to set mergeinfo on it. */
SVN_ERR(svn_wc__node_is_status_deleted(&child_is_deleted,
@@ -7661,6 +7678,7 @@ record_mergeinfo_for_dir_merge(svn_merge
continue;
SVN_ERR(calculate_merge_inheritance(child_merge_rangelist,
+ &rangelist_inheritance,
child->abspath,
i == 0,
child->missing_child,
@@ -7694,6 +7712,66 @@ record_mergeinfo_for_dir_merge(svn_merge
}
child_merges = apr_hash_make(iterpool);
+
+ /* If CHILD is the merge target we then know that the mergeinfo
+ described by MERGE_SOURCE_PATH:MERGED_RANGE->START-
+ MERGED_RANGE->END describes existent path-revs in the repository,
+ see normalize_merge_sources() and the global comment
+ 'MERGEINFO MERGE SOURCE NORMALIZATION'.
+
+ If CHILD is a subtree of the merge target however, then no such
+ guarantee holds. The mergeinfo described by
+ (MERGE_SOURCE_PATH + CHILD_REPOS_PATH):MERGED_RANGE->START-
+ MERGED_RANGE->END might contain merge sources which don't
+ exist or refer to unrelated lines of history. */
+ if (i > 0
+ && (!merge_b->record_only || merge_b->reintegrate_merge)
+ && (!is_rollback))
+ {
+ svn_opt_revision_t peg_revision;
+ svn_mergeinfo_t subtree_history_as_mergeinfo;
+ apr_array_header_t *child_merge_src_rangelist;
+ const char *old_session_url;
+ const char *subtree_mergeinfo_url =
+ svn_path_url_add_component2(merge_b->repos_root_url,
+ child_merge_src_canon_path + 1,
+ iterpool);
+
+ /* Confirm that the naive mergeinfo we want to set on
+ CHILD->ABSPATH both exists and is part of
+ (MERGE_SOURCE_PATH+CHILD_REPOS_PATH)@MERGED_RANGE->END's
+ history. */
+ peg_revision.kind = svn_opt_revision_number;
+
+ /* We know MERGED_RANGE->END is younger than MERGE_RANGE->START
+ because we only do this for forward merges. */
+ peg_revision.value.number = merged_range->end;
+ SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+ merge_b->ra_session2,
+ subtree_mergeinfo_url,
+ iterpool));
+ SVN_ERR(svn_client__get_history_as_mergeinfo(
+ &subtree_history_as_mergeinfo, NULL,
+ subtree_mergeinfo_url, &peg_revision,
+ MAX(merged_range->start, merged_range->end),
+ MIN(merged_range->start, merged_range->end),
+ merge_b->ra_session2, merge_b->ctx, iterpool));
+
+ if (old_session_url)
+ SVN_ERR(svn_ra_reparent(merge_b->ra_session2,
+ old_session_url, iterpool));
+ child_merge_src_rangelist = apr_hash_get(
+ subtree_history_as_mergeinfo,
+ child_merge_src_canon_path,
+ APR_HASH_KEY_STRING);
+ SVN_ERR(svn_rangelist_intersect(&child_merge_rangelist,
+ child_merge_rangelist,
+ child_merge_src_rangelist,
+ FALSE, iterpool));
+ if (!rangelist_inheritance)
+ svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
+ }
+
apr_hash_set(child_merges, child->abspath, APR_HASH_KEY_STRING,
child_merge_rangelist);
SVN_ERR(update_wc_mergeinfo(result_catalog,
Modified: subversion/branches/issue-3975/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/tests/cmdline/merge_authz_tests.py?rev=1160432&r1=1160431&r2=1160432&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/branches/issue-3975/subversion/tests/cmdline/merge_authz_tests.py Mon Aug 22 20:57:21 2011
@@ -420,7 +420,7 @@ def mergeinfo_and_skipped_paths(sbox):
props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8-9'}),
'chi' : Item("This is the file 'chi'.\n"),
'zeta' : Item("This is the file 'zeta'.\n",
- props={SVN_PROP_MERGEINFO : '/A/D/H/zeta:8-9'}),
+ props={SVN_PROP_MERGEINFO : '/A/D/H/zeta:9'}),
})
expected_skip = wc.State(A_COPY_2_H_path, {})
svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
Modified: subversion/branches/issue-3975/subversion/tests/cmdline/merge_reintegrate_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/tests/cmdline/merge_reintegrate_tests.py?rev=1160432&r1=1160431&r2=1160432&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/tests/cmdline/merge_reintegrate_tests.py (original)
+++ subversion/branches/issue-3975/subversion/tests/cmdline/merge_reintegrate_tests.py Mon Aug 22 20:57:21 2011
@@ -486,22 +486,9 @@ def reintegrate_with_rename(sbox):
"" : Item(status=' M', wc_rev=9),
})
k_expected_disk.tweak('', props={SVN_PROP_MERGEINFO : '/A_COPY:2-9'})
-
- # Why do we expect mergeinfo of '/A_COPY/D/G/tauprime:2-9' on
- # A/D/G/tauprime? Because this --reintegrate merge is effectively a
- # two URL merge of %URL%/A@9 %URL%/A_COPY@9 to 'A'. Since %URL%/A@9 and
- # %URL%/A_COPY@9 have a common ancestor in %URL%/A@1 we expect this 2-URL
- # merge to record mergeinfo and a component of that mergeinfo describes
- # the merge of %URL%/A_COPY@2 to %URL%/A_COPY@9. We see that above on
- # A. But we also get it on A's subtrees with explicit mergeinfo, namely
- # A/D/G/tauprime. Now I know what you are thinking, "'A_COPY/D/G/tauprime'
- # doesn't even exist until r9!", and you are quite right. But this
- # inheritance of bogus mergeinfo is a known problem, see
- # http://subversion.tigris.org/issues/show_bug.cgi?id=3157#desc8,
- # and is not what this test is about, so we won't fail because of it.
k_expected_disk.add({
'D/G/tauprime' : Item(props={SVN_PROP_MERGEINFO :
- '/A/D/G/tau:2-7\n/A_COPY/D/G/tauprime:2-9'},
+ '/A/D/G/tau:2-7\n/A_COPY/D/G/tauprime:9'},
contents="This is the file 'tau'.\n")
})
expected_skip = wc.State(A_path, {})
@@ -1340,7 +1327,7 @@ def reintegrate_with_subtree_mergeinfo(s
'' : Item(status=' U'),
'mu' : Item(status=' G'),
'D' : Item(status=' U'),
- 'D/gamma_moved' : Item(status=' G'),
+ 'D/gamma_moved' : Item(status=' U'),
})
expected_elision_output = wc.State(A_path, {
})
@@ -1384,22 +1371,9 @@ def reintegrate_with_subtree_mergeinfo(s
'D/G/pi' : Item("This is the file 'pi'.\n"),
'D/G/rho' : Item("New content"),
'D/G/tau' : Item("This is the file 'tau'.\n"),
- # Why do we expect mergeinfo of '/A_COPY/D/G/tauprime:2-9' on
- # A/D/G/tauprime? Because this --reintegrate merge is effectively a
- # two URL merge of %URL%/A@9 %URL%/A_COPY@9 to 'A'. Since %URL%/A@9 and
- # %URL%/A_COPY@9 have a common ancestor in %URL%/A@1 we expect this 2-URL
- # merge to record mergeinfo and a component of that mergeinfo describes
- # the merge of %URL%/A_COPY@2 to %URL%/A_COPY@9. We see that above on
- # A. But we also get it on A's subtrees with explicit mergeinfo, namely
- # A/D/G/tauprime. Now I know what you are thinking, "'A_COPY/D/G/tauprime'
- # doesn't even exist until r9!", and you are quite right. But this
- # inheritance of bogus mergeinfo is a known problem, see
- # http://subversion.tigris.org/issues/show_bug.cgi?id=3157#desc8,
- # and is not what this test is about, so we won't fail because of it.
'D/gamma_moved' : Item(
"Even newer content", props={SVN_PROP_MERGEINFO :
- '/A/D/gamma_moved:2-15\n'
- '/A_COPY/D/gamma_moved:2-19\n'
+ '/A_COPY/D/gamma_moved:17-19\n'
'/A_COPY_3/D/gamma:9'}),
'D/H' : Item(),
'D/H/chi' : Item("This is the file 'chi'.\n"),
@@ -2037,7 +2011,7 @@ def added_subtrees_with_mergeinfo_break_
'C' : Item(),
'C/nu' : Item("Trunk work on nu.\n",
props={SVN_PROP_MERGEINFO :
- '/A_COPY/C/nu:16-18\n'
+ '/A_COPY/C/nu:13,16-18\n'
'/A_COPY_2/C/nu:10'}), # <-- From cyclic
# merge in r11
'D' : Item(),
Modified: subversion/branches/issue-3975/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/issue-3975/subversion/tests/cmdline/merge_tests.py?rev=1160432&r1=1160431&r2=1160432&view=diff
==============================================================================
--- subversion/branches/issue-3975/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/issue-3975/subversion/tests/cmdline/merge_tests.py Mon Aug 22 20:57:21 2011
@@ -11582,24 +11582,7 @@ def dont_explicitly_record_implicit_merg
svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
wc_status.tweak(wc_rev=10)
- # Now do a cherry harvest merge to 'A_copy'. We should pick up the
- # change to 'A_copy/D/H/nu' from r10, the mergeinfo on 'A_copy' should
- # reflect the entire eligible revision range from 'A', r2-10.
- # 'A_copy/D/H/nu' should have get the equivalent mergeinfo to 'A_copy'
- # which should elide to the latter, leaving no explicit mergeinfo...
- #
- # ...or should it? For the mergeinfo on ' A_copy/D/H/nu' to elide, it
- # needs mergeinfo '/A/D/H/nu:2-10', but 'A/D/H/nu' doesn't exist prior to
- # r6...Anyhow, regardless of what the mergeinfo on ' A_copy/D/H/nu' should
- # be prior to elision, if we have the following conditions:
- #
- # 1) A uniform working revision merge target.
- #
- # 2) Explicit mergeinfo on the target/subtrees from the same
- # source ('A' in this case).
- #
- # Then a cherry harvest from the same source should leave explicit
- # mergeinfo *only* on the merge target no?
+ # Now do a cherry harvest merge to 'A_copy'.
expected_output = wc.State(A_copy_path, {
'D/H/nu' : Item(status='U '),
})
@@ -11608,7 +11591,6 @@ def dont_explicitly_record_implicit_merg
'D/H/nu' : Item(status=' U'),
})
expected_elision_output = wc.State(A_copy_path, {
- 'D/H/nu' : Item(status=' U'),
})
expected_A_copy_status = wc.State(A_copy_path, {
'' : Item(status=' M', wc_rev=10),
@@ -11652,7 +11634,8 @@ def dont_explicitly_record_implicit_merg
'D/H/chi' : Item("This is the file 'chi'.\n"),
'D/H/psi' : Item("This is the file 'psi'.\n"),
'D/H/omega' : Item("This is the file 'omega'.\n"),
- 'D/H/nu' : Item("Even nuer content"),
+ 'D/H/nu' : Item("Even nuer content",
+ props={SVN_PROP_MERGEINFO : '/A/D/H/nu:6-10'}),
})
expected_A_copy_skip = wc.State(A_copy_path, {})
svntest.actions.run_and_verify_merge(A_copy_path, None, None,
@@ -13957,7 +13940,7 @@ def no_self_referential_filtering_on_add
'B/E/beta' : Item("New content"),
'B/lambda' : Item("This is the file 'lambda'.\n"),
'B/F' : Item(),
- 'C_MOVED' : Item(props={SVN_PROP_MERGEINFO : '/A/C_MOVED:3-10\n' +
+ 'C_MOVED' : Item(props={SVN_PROP_MERGEINFO : '/A/C_MOVED:10\n' +
'/A_COPY/C:8\n' +
'/A_COPY/C_MOVED:8',
'propname' : 'propval'}),