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/12/01 19:38:39 UTC
svn commit: r1209176 - in /subversion/trunk/subversion:
libsvn_client/merge.c libsvn_client/mergeinfo.h
tests/cmdline/merge_authz_tests.py tests/cmdline/merge_tests.py
Author: pburba
Date: Thu Dec 1 18:38:38 2011
New Revision: 1209176
URL: http://svn.apache.org/viewvc?rev=1209176&view=rev
Log:
Fix issue #4056 "don't record non-inheritable mergeinfo if missing
subtrees are not touched by the full-depth diff".
* subversion/libsvn_client/mergeinfo.h
(svn_client__merge_path_t): Add a few new members.
* subversion/libsvn_client/merge.c
(calculate_merge_inheritance): Stop adjusting a rangelist in place and
instead simply communicate back to the caller they inheritance type
required to describe the merge.
(insert_parent_and_sibs_of_sw_absent_del_subtree): Set one of the new
svn_client__merge_path_t members.
(flag_subtrees_needing_mergeinfo): New. Takes an initial walk over
(record_mergeinfo_for_dir_merge): Factor out the bulk of the code which
determines if a subtree of interest *needs* new mergeinfo to describe a
merge -- see flag_subtrees_needing_mergeinfo for its new home. Leave
behind the code which actually *calculates* what the actual mergeinfo is
and records it.
(do_directory_merge): Account for new differentiation between missing and
switched children.
* subversion/tests/cmdline/merge_authz_tests.py
(mergeinfo_and_skipped_paths): Expand test for greater coverage of
issue #4056 and adjust existing expectations to account for the more
concise mergeinfo produced by this fix.
* subversion/tests/cmdline/merge_tests.py
(merge_to_path_with_switched_children): Adjust existing expectations to
account for the more concise mergeinfo produced by this fix.
(noninheritable_mergeinfo_test_set_up): Adjust test expectations a bit.
We still expect no spurious subtree mergeinfo, but how this is
accomplished (set it, then elide it) was not what the test
originally expected.
(unnecessary_noninheritable_mergeinfo_missing_subtrees): Remove XFail
decorator and comment.
Modified:
subversion/trunk/subversion/libsvn_client/merge.c
subversion/trunk/subversion/libsvn_client/mergeinfo.h
subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py
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=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Thu Dec 1 18:38:38 2011
@@ -4528,9 +4528,9 @@ 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. Set
- *RANGELIST_INHERITANCE to the inheritability set.
+ Set *NON_INHERITABLE to TRUE if non-inheritable mergeinfo is needed to
+ describe a merge into LOCAL_ABSPATH at DEPTH. Set *NON_INHERTIABLE to
+ FALSE otherwise.
WC_PATH_IS_MERGE_TARGET is true if WC_PATH is the target of the merge,
otherwise WC_PATH is a subtree.
@@ -4541,8 +4541,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,
+calculate_merge_inheritance(svn_boolean_t *non_inheritable,
const char *local_abspath,
svn_boolean_t wc_path_is_merge_target,
svn_boolean_t wc_path_has_missing_child,
@@ -4556,14 +4555,10 @@ calculate_merge_inheritance(apr_array_he
scratch_pool));
/* Starting assumption. */
- *rangelist_inheritance = TRUE;
+ *non_inheritable = FALSE;
- if (path_kind == svn_node_file)
- {
- /* Files *never* have non-inheritable mergeinfo. */
- svn_rangelist__set_inheritance(rangelist, TRUE);
- }
- else if (path_kind == svn_node_dir)
+ /* Only directories can have non-inheritable mergeinfo. */
+ if (path_kind == svn_node_dir)
{
if (wc_path_is_merge_target)
{
@@ -4571,12 +4566,7 @@ calculate_merge_inheritance(apr_array_he
|| depth == svn_depth_files
|| depth == svn_depth_empty)
{
- svn_rangelist__set_inheritance(rangelist, FALSE);
- *rangelist_inheritance = FALSE;
- }
- else /* depth == svn_depth_files || depth == svn_depth_empty */
- {
- svn_rangelist__set_inheritance(rangelist, TRUE);
+ *non_inheritable = TRUE;
}
}
else /* WC_PATH is a directory subtree of the target. */
@@ -4584,12 +4574,7 @@ calculate_merge_inheritance(apr_array_he
if (wc_path_has_missing_child
|| depth == svn_depth_immediates)
{
- svn_rangelist__set_inheritance(rangelist, FALSE);
- *rangelist_inheritance = FALSE;
- }
- else /* depth == infinity */
- {
- svn_rangelist__set_inheritance(rangelist, TRUE);
+ *non_inheritable = TRUE;
}
}
}
@@ -5481,13 +5466,15 @@ insert_parent_and_sibs_of_sw_absent_del_
parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath);
if (parent)
{
- parent->missing_child = TRUE;
+ parent->missing_child = child->absent;
+ parent->switched_child = child->switched;
}
else
{
/* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */
parent = svn_client__merge_path_create(parent_abspath, pool);
- parent->missing_child = TRUE;
+ parent->missing_child = child->absent;
+ parent->switched_child = child->switched;
/* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
insert_child_to_merge(children_with_mergeinfo, parent, pool);
/* Increment for loop index so we don't process the inserted element. */
@@ -7426,6 +7413,202 @@ get_inoperative_immediate_children(apr_h
return SVN_NO_ERROR;
}
+/* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of
+ NOTIFY_B->CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately
+ describe a merge, what inheritance type such new mergeinfo should have,
+ and what subtrees can be ignored altogether.
+
+ For each svn_client__merge_path_t CHILD in
+ NOTIFY_B->CHILDREN_WITH_MERGEINFO, set CHILD->RECORD_MERGEINFO and
+ CHILD->RECORD_NONINHERITABLE to true if the subtree needs mergeinfo
+ to describe the merge and if that mergeinfo should be non-inheritable
+ respectively.
+
+ If OPERATIVE_MERGE is true, then the merge being described is operative
+ as per subtree_touched_by_merge. OPERATIVE_MERGE is false otherwise.
+
+ MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all
+ cascaded from record_mergeinfo_for_dir_merge's arguments of the same
+ names.
+
+ SCRATCH_POOL is used for temporary allocations.
+*/
+static svn_error_t *
+flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
+ const svn_merge_range_t *merged_range,
+ const char *mergeinfo_fspath,
+ svn_depth_t depth,
+ notification_receiver_baton_t *notify_b,
+ merge_cmd_baton_t *merge_b,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ int i;
+ apr_hash_t *inoperative_immediate_children = NULL;
+
+ /* Find all issue #3642 children (i.e immediate child directories of the
+ merge target, with no pre-existing explicit mergeinfo, during a --depth
+ immediates merge). Stash those that are inoperative at any depth in
+ INOPERATIVE_IMMEDIATE_CHILDREN. */
+ if (!merge_b->record_only
+ && merged_range->start <= merged_range->end
+ && depth == svn_depth_immediates)
+ SVN_ERR(get_inoperative_immediate_children(
+ &inoperative_immediate_children,
+ notify_b->children_with_mergeinfo,
+ mergeinfo_fspath, merged_range->start + 1, merged_range->end,
+ merge_b->target_abspath, merge_b->ra_session1,
+ scratch_pool, iterpool));
+
+ /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
+ order. This way each child knows if it has operative missing/switched
+ children which necessitates non-inheritable mergeinfo. */
+ for (i = notify_b->children_with_mergeinfo->nelts - 1; i >= 0; i--)
+ {
+ svn_client__merge_path_t *child =
+ APR_ARRAY_IDX(notify_b->children_with_mergeinfo, i,
+ svn_client__merge_path_t *);
+
+ /* Can't record mergeinfo on something that isn't here. */
+ if (child->absent)
+ continue;
+
+ /* Don't record mergeinfo on skipped paths. */
+ if (notify_b->skipped_abspaths
+ && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
+ APR_HASH_KEY_STRING))
+ continue;
+
+ /* ### ptb: Yes, we could combine the follwing into a single
+ ### conditional, but clarity would suffer (even more than
+ ### it does now). */
+ if (i == 0)
+ {
+ /* Always record mergeinfo on the merge target. */
+ child->record_mergeinfo = TRUE;
+ }
+ else if (merge_b->record_only && !merge_b->reintegrate_merge)
+ {
+ /* Always record mergeinfo for --record-only merges. */
+ child->record_mergeinfo = TRUE;
+ }
+ else if (child->immediate_child_dir
+ && !child->pre_merge_mergeinfo
+ && inoperative_immediate_children
+ && !apr_hash_get(inoperative_immediate_children,
+ child->abspath,
+ APR_HASH_KEY_STRING))
+ {
+ /* We must record mergeinfo on those issue #3642 children
+ that are operative at a greater depth. */
+ child->record_mergeinfo = TRUE;
+ }
+
+ if (operative_merge)
+ {
+ svn_boolean_t child_is_deleted;
+
+ svn_pool_clear(iterpool);
+
+ /* If CHILD is deleted we don't need to set mergeinfo on it. */
+ SVN_ERR(svn_wc__node_is_status_deleted(&child_is_deleted,
+ merge_b->ctx->wc_ctx,
+ child->abspath, iterpool));
+ if (!child_is_deleted
+ && subtree_touched_by_merge(child->abspath, notify_b,
+ iterpool))
+ {
+ /* This subtree was affected by the merge. */
+ child->record_mergeinfo = TRUE;
+
+ /* Were any CHILD's missing children skipped by the merge?
+ If not, then CHILD's missing children don't need to be
+ considered when recording mergeinfo describing the merge. */
+ if (!merge_b->reintegrate_merge
+ && child->missing_child
+ && !path_is_subtree(child->abspath,
+ notify_b->skipped_abspaths,
+ iterpool))
+ {
+ child->missing_child = FALSE;
+ }
+
+ /* If CHILD has an immediate switched child or children and
+ none of these were touched by the merge, then we don't need
+ need to do any special handling of those switched subtrees
+ (e.g. record non-inheritable mergeinfo) when recording
+ mergeinfo desribing the merge. */
+ if (child->switched_child)
+ {
+ int j;
+ svn_boolean_t operative_switched_child = FALSE;
+
+ for (j = i + 1;
+ j < notify_b->children_with_mergeinfo->nelts;
+ j++)
+ {
+ svn_client__merge_path_t *potential_child =
+ APR_ARRAY_IDX(notify_b->children_with_mergeinfo, j,
+ svn_client__merge_path_t *);
+ if (!svn_dirent_is_ancestor(child->abspath,
+ potential_child->abspath))
+ break;
+
+ /* POTENTIAL_CHILD is a subtree of CHILD, but is it
+ an immediate child? */
+ if (strcmp(child->abspath,
+ svn_dirent_dirname(potential_child->abspath,
+ iterpool)))
+ continue;
+
+ if (potential_child->switched
+ && potential_child->record_mergeinfo)
+ {
+ operative_switched_child = TRUE;
+ break;
+ }
+ }
+
+ /* Can we treat CHILD as if it has no switched children? */
+ if (!operative_switched_child)
+ child->switched_child = FALSE;
+ }
+ }
+ }
+
+ if (child->record_mergeinfo)
+ {
+ SVN_ERR(calculate_merge_inheritance(&(child->record_noninheritable),
+ child->abspath,
+ i == 0,
+ (child->missing_child
+ || child->switched_child),
+ depth,
+ merge_b->ctx->wc_ctx,
+ iterpool));
+ }
+ else
+ {
+ /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
+ because it had no explicit mergeinfo of its own at the
+ start of the merge but is the child of of some path with
+ non-inheritable mergeinfo, then the explicit mergeinfo it
+ has *now* was set by get_mergeinfo_paths() -- see criteria
+ 3 in that function's doc string. So since CHILD->ABSPATH
+ was not touched by the merge we can remove the
+ mergeinfo. */
+ if (child->child_of_noninheritable)
+ SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
+ NULL, FALSE,
+ merge_b->ctx,
+ iterpool));
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
/* Helper for do_directory_merge().
If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
@@ -7457,7 +7640,6 @@ record_mergeinfo_for_dir_merge(svn_merge
int i;
svn_boolean_t is_rollback = (merged_range->start > merged_range->end);
svn_boolean_t operative_merge;
- apr_hash_t *inoperative_immediate_children = NULL;
/* Update the WC mergeinfo here to account for our new
merges, minus any unresolved conflicts and skips. */
@@ -7484,23 +7666,12 @@ record_mergeinfo_for_dir_merge(svn_merge
remove_absent_children(merge_b->target_abspath,
notify_b->children_with_mergeinfo);
+ /* Determine which subtrees of interest need mergeinfo recorded... */
+ SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
+ mergeinfo_fspath, depth, notify_b,
+ merge_b, iterpool));
- /* Find all issue #3642 children (i.e immediate child directories of the
- merge target, with no pre-existing explicit mergeinfo, during a --depth
- immediates merge). Stash those that are inoperative at any depth in
- INOPERATIVE_IMMEDIATE_CHILDREN. */
- if (!merge_b->record_only && range.start <= range.end
- && depth == svn_depth_immediates)
- SVN_ERR(get_inoperative_immediate_children(
- &inoperative_immediate_children,
- notify_b->children_with_mergeinfo,
- mergeinfo_fspath, range.start + 1, range.end,
- merge_b->target_abspath, merge_b->ra_session1,
- pool, iterpool));
-
- /* Record mergeinfo on any subtree affected by the merge or for
- every subtree if this is a --record-only merge. Always record
- mergeinfo on the merge target CHILDREN_WITH_MERGEINFO[0]. */
+ /* ...and then record it. */
for (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++)
{
const char *child_repos_path;
@@ -7512,60 +7683,10 @@ record_mergeinfo_for_dir_merge(svn_merge
svn_client__merge_path_t *);
SVN_ERR_ASSERT(child);
- /* Can't record mereginfo on something that isn't here. */
- if (child->absent)
- continue;
-
svn_pool_clear(iterpool);
- /* If CHILD is a subtree, this is not a record only merge, and
- CHILD was not affected by the merge then we don't need to
- record mergeinfo. If this is a record only merge being done
- as part of a reintegrate merge then we need to check if CHILD
- was affected by the merge. */
- if (i > 0 /* Always record mergeinfo on the merge target. */
- && (!merge_b->record_only || merge_b->reintegrate_merge)
- && (!child->immediate_child_dir || child->pre_merge_mergeinfo)
- && (!operative_merge
- || !subtree_touched_by_merge(child->abspath, notify_b,
- iterpool)))
+ if (child->record_mergeinfo)
{
- /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
- because it had no explicit mergeinfo of its own at the
- start of the merge but is the child of of some path with
- non-inheritable mergeinfo, then the explicit mergeinfo it
- has *now* was set by get_mergeinfo_paths() -- see criteria
- 3 in that function's doc string. So since CHILD->ABSPATH
- was not touched by the merge we can remove the
- mergeinfo. */
- if (child->child_of_noninheritable)
- {
- SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
- NULL, FALSE,
- merge_b->ctx,
- iterpool));
- }
- }
- 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,
- merge_b->ctx->wc_ctx,
- child->abspath, iterpool));
- if (child_is_deleted)
- continue;
-
- /* We don't need to record mergeinfo on those issue #3642 children
- that are inoperative at any depth. */
- if (inoperative_immediate_children
- && apr_hash_get(inoperative_immediate_children,
- child->abspath,
- APR_HASH_KEY_STRING))
- continue;
-
child_repos_path = svn_dirent_skip_ancestor(merge_b->target_abspath,
child->abspath);
SVN_ERR_ASSERT(child_repos_path != NULL);
@@ -7582,35 +7703,21 @@ record_mergeinfo_for_dir_merge(svn_merge
continue;
if (!squelch_mergeinfo_notifications)
- {
- notify_mergeinfo_recording(child->abspath, merged_range,
- merge_b->ctx, iterpool);
- }
+ notify_mergeinfo_recording(child->abspath, merged_range,
+ merge_b->ctx, iterpool);
/* If we are here we know we will be recording some mergeinfo, but
- before we do set override mergeinfo on skipped paths so they
- don't incorrectly inherit the mergeinfo we are about to set.
- We only need to do this once. If we are dealing with a subtree
- (i.e. i != 0) that was skipped then don't record mergeinfo on
- it. The earlier call to record_skips will already have taken
- care of this. */
+ before we do, set override mergeinfo on skipped paths so they
+ don't incorrectly inherit the mergeinfo we are about to set. */
if (i == 0)
SVN_ERR(record_skips(mergeinfo_fspath, child_merge_rangelist,
is_rollback, notify_b->skipped_abspaths,
merge_b, iterpool));
- else if (notify_b->skipped_abspaths
- && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
- APR_HASH_KEY_STRING))
- continue;
- SVN_ERR(calculate_merge_inheritance(child_merge_rangelist,
- &rangelist_inheritance,
- child->abspath,
- i == 0,
- child->missing_child,
- depth,
- merge_b->ctx->wc_ctx,
- iterpool));
+ /* We may need to record non-inheritable mergeinfo that applies
+ only to CHILD->ABSPATH. */
+ if (child->record_noninheritable)
+ svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
/* If CHILD has inherited mergeinfo set it before
recording the first merge range. */
@@ -7718,7 +7825,7 @@ record_mergeinfo_for_dir_merge(svn_merge
child_merge_rangelist,
child_merge_src_rangelist,
FALSE, iterpool));
- if (!rangelist_inheritance)
+ if (child->record_noninheritable)
svn_rangelist__set_inheritance(child_merge_rangelist,
FALSE);
}
@@ -8400,7 +8507,8 @@ do_directory_merge(svn_mergeinfo_catalog
the target thanks to depth-first ordering. */
target_merge_path = APR_ARRAY_IDX(notify_b->children_with_mergeinfo, 0,
svn_client__merge_path_t *);
- merge_b->target_missing_child = target_merge_path->missing_child;
+ merge_b->target_missing_child = (target_merge_path->missing_child
+ || target_merge_path->switched_child);
/* If we are honoring mergeinfo, then for each item in
NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
Modified: subversion/trunk/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mergeinfo.h?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/trunk/subversion/libsvn_client/mergeinfo.h Thu Dec 1 18:38:38 2011
@@ -40,7 +40,9 @@ typedef struct svn_client__merge_path_t
{
const char *abspath; /* Absolute working copy path. */
svn_boolean_t missing_child; /* ABSPATH has an immediate child which
- is missing. */
+ is missing, but is not switched. */
+ svn_boolean_t switched_child; /* ABSPATH has an immediate child which
+ is switched. */
svn_boolean_t switched; /* ABSPATH is switched. */
svn_boolean_t has_noninheritable; /* ABSPATH has svn:mergeinfo set on it
which includes non-inheritable
@@ -79,6 +81,13 @@ typedef struct svn_client__merge_path_t
to the merge, and the operational
depth of the merge is
svn_depth_immediates. */
+ svn_boolean_t record_mergeinfo; /* Mergeinfo needs to be recorded
+ on ABSPATH to describe the
+ merge. */
+ svn_boolean_t record_noninheritable; /* Non-inheritable mergeinfo needs to
+ be recorded on ABSPATH to describe
+ the merge. Implies RECORD_MERGEINFO
+ is true. */
} svn_client__merge_path_t;
/* Return a deep copy of the merge-path structure OLD, allocated in POOL. */
Modified: subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py Thu Dec 1 18:38:38 2011
@@ -73,7 +73,10 @@ from svntest.actions import inject_confl
# This is *not* a full test of issue #2829, see also merge_tests.py,
# search for "2829". This tests the problem where a merge adds a path
# with a missing sibling and so needs its own explicit mergeinfo.
-@Issues(2893,2997,2829)
+#
+# #4056 - Don't record non-inheritable mergeinfo if missing subtrees are not
+# touched by the full-depth diff
+@Issues(2893,2997,2829,4056)
@SkipUnless(svntest.main.server_has_mergeinfo)
@Skip(svntest.main.is_ra_type_file)
def mergeinfo_and_skipped_paths(sbox):
@@ -393,10 +396,54 @@ def mergeinfo_and_skipped_paths(sbox):
# Merge -r7:9 to the restricted WC's A_COPY_2/D/H.
#
+ # r9 adds a path, 'A_COPY_2/D/H/zeta', which has a missing sibling 'psi',
+ # but since 'psi' is untouched by the merge it isn't skipped, and since it
+ # isn't skipped, its parent 'A_COPY_2/D/H' won't get non-inheritable
+ # mergeinfo set on it to describe the merge, so none of the parent's
+ # children will get explicit mergeinfo -- see issue #4056.
+ expected_output = wc.State(A_COPY_2_H_path, {
+ 'omega' : Item(status='U '),
+ 'zeta' : Item(status='A '),
+ })
+ expected_mergeinfo_output = wc.State(A_COPY_2_H_path, {
+ '' : Item(status=' U'),
+ 'omega' : Item(status=' U'),
+ })
+ expected_elision_output = wc.State(A_COPY_2_H_path, {
+ 'omega' : Item(status=' U'),
+ })
+ expected_status = wc.State(A_COPY_2_H_path, {
+ '' : Item(status=' M', wc_rev=8),
+ 'chi' : Item(status=' ', wc_rev=8),
+ 'omega' : Item(status='M ', wc_rev=8),
+ 'zeta' : Item(status='A ', copied='+', wc_rev='-'),
+ })
+ expected_disk = wc.State('', {
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9'}),
+ 'omega' : Item("New content"),
+ 'chi' : Item("This is the file 'chi'.\n"),
+ 'zeta' : Item("This is the file 'zeta'.\n"),
+ })
+ expected_skip = wc.State(A_COPY_2_H_path, {})
+ svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
+ sbox.repo_url + '/A/D/H', None,
+ expected_output,
+ expected_mergeinfo_output,
+ expected_elision_output,
+ expected_disk,
+ expected_status,
+ expected_skip,
+ None, None, None, None,
+ None, 1, 0)
+
+ # Merge -r4:9 to the restricted WC's A_COPY_2/D/H.
+ #
# r9 adds a path, 'A_COPY_2/D/H/zeta', which has a parent with
- # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing).
- # 'A_COPY_2/D/H/zeta' must therefore get its own explicit mergeinfo from
- # this merge.
+ # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing
+ # and skipped). 'A_COPY_2/D/H/zeta' must therefore get its own explicit
+ # mergeinfo from this merge.
+ svntest.actions.run_and_verify_svn(None, None, [], 'revert', '--recursive',
+ wc_restricted)
expected_output = wc.State(A_COPY_2_H_path, {
'omega' : Item(status='U '),
'zeta' : Item(status='A '),
@@ -415,15 +462,17 @@ def mergeinfo_and_skipped_paths(sbox):
'zeta' : Item(status='A ', copied='+', wc_rev='-'),
})
expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9*'}),
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-9*'}),
'omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8-9'}),
+ props={SVN_PROP_MERGEINFO : '/A/D/H/omega:5-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:9'}),
})
- expected_skip = wc.State(A_COPY_2_H_path, {})
- svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
+ expected_skip = wc.State(A_COPY_2_H_path, {
+ 'psi' : Item(),
+ })
+ svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '4', '9',
sbox.repo_url + '/A/D/H', None,
expected_output,
expected_mergeinfo_output,
Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Thu Dec 1 18:38:38 2011
@@ -5599,7 +5599,7 @@ def merge_to_switched_path(sbox):
# 3188: Mergeinfo on switched targets/subtrees should
# elide to repos
@SkipUnless(server_has_mergeinfo)
-@Issue(2823,2839,3187,3188)
+@Issue(2823,2839,3187,3188,4056)
def merge_to_path_with_switched_children(sbox):
"merge to path with switched children"
@@ -5694,18 +5694,18 @@ def merge_to_path_with_switched_children
'omega' : Item(status=' U')
})
expected_elision_output = wc.State(A_COPY_H_path, {
+ 'omega' : Item(status=' U')
})
expected_status = wc.State(A_COPY_H_path, {
'' : Item(status=' M', wc_rev=8),
'psi' : Item(status=' ', wc_rev=8, switched='S'),
- 'omega' : Item(status='MM', wc_rev=8),
+ 'omega' : Item(status='M ', wc_rev=8),
'chi' : Item(status=' ', wc_rev=8),
})
expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*'}),
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8'}),
'psi' : Item("This is the file 'psi'.\n"),
- 'omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ 'omega' : Item("New content"),
'chi' : Item("This is the file 'chi'.\n"),
})
expected_skip = wc.State(A_COPY_H_path, { })
@@ -5739,7 +5739,7 @@ def merge_to_path_with_switched_children
'' : Item(status=' M', wc_rev=8),
'H' : Item(status=' M', wc_rev=8),
'H/chi' : Item(status=' ', wc_rev=8),
- 'H/omega' : Item(status='MM', wc_rev=8),
+ 'H/omega' : Item(status='M ', wc_rev=8),
'H/psi' : Item(status=' ', wc_rev=8, switched='S'),
'G' : Item(status=' M', wc_rev=8, switched='S'),
'G/pi' : Item(status=' ', wc_rev=8),
@@ -5749,10 +5749,9 @@ def merge_to_path_with_switched_children
})
expected_disk_D = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A/D:6*'}),
- 'H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*'}),
+ 'H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8'}),
'H/chi' : Item("This is the file 'chi'.\n"),
- 'H/omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ 'H/omega' : Item("New content"),
'H/psi' : Item("This is the file 'psi'.\n",),
'G' : Item(props={SVN_PROP_MERGEINFO : '/A/D/G:6*'}),
'G/pi' : Item("This is the file 'pi'.\n"),
@@ -5786,10 +5785,10 @@ def merge_to_path_with_switched_children
})
expected_elision_output = wc.State(A_COPY_D_path, {
})
- expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5-6*'})
- expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'})
+ expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
+ expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
expected_disk_D.tweak('H/psi', contents="New content",
- props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5'})
+ props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5,8'})
expected_status_D.tweak('H/psi', status='MM')
svntest.actions.run_and_verify_merge(A_COPY_D_path, '4', '5',
sbox.repo_url + '/A/D', None,
@@ -5830,7 +5829,7 @@ def merge_to_path_with_switched_children
'D/H' : Item(status=' M', wc_rev=8),
'D/H/chi' : Item(status=' ', wc_rev=8),
'D/H/psi' : Item(status='MM', wc_rev=8, switched='S'),
- 'D/H/omega' : Item(status='MM', wc_rev=8),
+ 'D/H/omega' : Item(status='M ', wc_rev=8),
})
expected_disk = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A:5-8'}),
@@ -5842,19 +5841,18 @@ def merge_to_path_with_switched_children
'B/lambda' : Item("This is the file 'lambda'.\n"),
'B/F' : Item(),
'C' : Item(),
- 'D' : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-6*'}),
+ 'D' : Item(props={SVN_PROP_MERGEINFO : '/A/D:5,6*'}),
'D/G' : Item(props={SVN_PROP_MERGEINFO : '/A/D/G:6*'}),
'D/G/pi' : Item("This is the file 'pi'.\n"),
'D/G/rho' : Item("New content",
props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'}),
'D/G/tau' : Item("This is the file 'tau'.\n"),
'D/gamma' : Item("This is the file 'gamma'.\n"),
- 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'}),
+ 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'}),
'D/H/chi' : Item("This is the file 'chi'.\n"),
'D/H/psi' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5'}),
- 'D/H/omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5,8'}),
+ 'D/H/omega' : Item("New content"),
})
expected_skip = wc.State(A_COPY_path, { })
svntest.actions.run_and_verify_merge(A_COPY_path, '4', '8',
@@ -5865,7 +5863,6 @@ def merge_to_path_with_switched_children
expected_disk,
expected_status, expected_skip,
None, None, None, None, None, 1)
-
# Commit changes thus far.
expected_output = svntest.wc.State(wc_dir, {
'A_COPY' : Item(verb='Sending'),
@@ -5892,17 +5889,16 @@ def merge_to_path_with_switched_children
wc_disk.tweak("A_COPY/B/E/beta",
contents="New content")
wc_disk.tweak("A_COPY/D",
- props={SVN_PROP_MERGEINFO : '/A/D:5-6*'})
+ props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
wc_disk.tweak("A_COPY/D/G",
props={SVN_PROP_MERGEINFO : '/A/D/G:6*'})
wc_disk.tweak("A_COPY/D/G/rho",
contents="New content",
props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'})
wc_disk.tweak("A_COPY/D/H",
- props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'})
+ props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
wc_disk.tweak("A_COPY/D/H/omega",
- contents="New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'})
+ contents="New content")
wc_disk.tweak("A_COPY_2", props={})
svntest.actions.run_and_verify_switch(sbox.wc_dir, A_COPY_psi_path,
sbox.repo_url + "/A_COPY/D/H/psi",
@@ -5941,8 +5937,7 @@ def merge_to_path_with_switched_children
expected_disk = wc.State('', {
'' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-8'}),
'psi' : Item("New content"),
- 'omega' : Item("New content",
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+ 'omega' : Item("New content"),
'chi' : Item("This is the file 'chi'.\n"),
})
expected_skip = wc.State(A_COPY_H_path, { })
@@ -5992,14 +5987,11 @@ def merge_to_path_with_switched_children
expected_status_D.tweak('H/psi', wc_rev=10, switched=None)
expected_status_D.tweak('H/omega', wc_rev=9)
expected_status_D.tweak('G', 'G/rho', switched='S', wc_rev=9)
- expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5-6*,10*',
+ expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*,10',
"prop:name" : "propval"})
expected_disk_D.tweak('G/rho',
props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'})
expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5-8'})
-
- expected_disk_D.tweak('H/omega',
- props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'})
expected_disk_D.tweak('H/psi', contents="New content", props={})
svntest.actions.run_and_verify_merge(A_COPY_D_path, '9', '10',
sbox.repo_url + '/A/D', None,
@@ -6060,7 +6052,6 @@ def merge_to_path_with_switched_children
'D/G' : Item(status=' U'),
'D/G/rho' : Item(status=' U'),
'D/H' : Item(status=' U'),
- 'D/H/omega' : Item(status=' U'),
})
expected_elision_output = wc.State(A_COPY_path, {
'' : Item(status=' U'),
@@ -6068,7 +6059,6 @@ def merge_to_path_with_switched_children
'D/G' : Item(status=' U'),
'D/G/rho' : Item(status=' U'),
'D/H' : Item(status=' U'),
- 'D/H/omega' : Item(status=' U'),
})
expected_status = wc.State(A_COPY_path, {
'' : Item(status=' M', wc_rev=10),
@@ -6089,7 +6079,7 @@ def merge_to_path_with_switched_children
'D/H' : Item(status=' M', wc_rev=10),
'D/H/chi' : Item(status=' ', wc_rev=10),
'D/H/psi' : Item(status='M ', wc_rev=10),
- 'D/H/omega' : Item(status='MM', wc_rev=10),
+ 'D/H/omega' : Item(status='M ', wc_rev=10),
})
expected_disk = wc.State('', {
'B' : Item(),
@@ -17173,8 +17163,10 @@ def noninheritable_mergeinfo_test_set_up
})
expected_mergeinfo_output = wc.State(B_branch_path, {
'' : Item(status=' U'),
+ 'lambda' : Item(status=' U'),
})
expected_elision_output = wc.State(B_branch_path, {
+ 'lambda' : Item(status=' U'),
})
expected_status = wc.State(B_branch_path, {
'' : Item(status=' M'),
@@ -17203,7 +17195,6 @@ def noninheritable_mergeinfo_test_set_up
# Test for issue #4056 "don't record non-inheritable mergeinfo if missing
# subtrees are not touched by the full-depth diff".
@Issue(4056)
-@XFail()
@SkipUnless(server_has_mergeinfo)
def unnecessary_noninheritable_mergeinfo_missing_subtrees(sbox):
"missing subtrees untouched by infinite depth merge"
@@ -17222,19 +17213,16 @@ def unnecessary_noninheritable_mergeinfo
# Merge r3 from ^/A/B to branch/B
#
- # Currently this fails because merge isn't smart enough to
- # realize that despite the shallow merge target, the diff can
- # only affect branch/B/lambda, which is still present, so there
+ # Merge is smart enough to realize that despite the shallow merge target,
+ # the diff can only affect branch/B/lambda, which is still present, so there
# is no need to record non-inheritable mergeinfo on the target
# or any subtree mergeinfo whatsoever:
#
# >svn pg svn:mergeinfo -vR
# Properties on 'branch\B':
# svn:mergeinfo
- # /A/B:3* <-- Should be inheritable
- # Properties on 'branch\B\lambda':
- # svn:mergeinfo
- # /A/B/lambda:3 <-- Not neccessary
+ # /A/B:3 <-- Nothing was skipped, so doesn't need
+ # to be non-inheritable.
svntest.actions.run_and_verify_merge(B_branch_path,
'2', '3',
sbox.repo_url + '/A/B', None,
Re: svn commit: r1209176 - in /subversion/trunk/subversion:
libsvn_client/merge.c libsvn_client/mergeinfo.h tests/cmdline/merge_authz_tests.py
tests/cmdline/merge_tests.py
Posted by Paul Burba <pt...@gmail.com>.
On Wed, Dec 7, 2011 at 6:30 AM, Julian Foad <ju...@btopenworld.com> wrote:
> Hi Paul.
>
>> Author: pburba
>> Date: Thu Dec 1 18:38:38 2011
>> New Revision: 1209176
>>
>> URL: http://svn.apache.org/viewvc?rev=1209176&view=rev
>> Log:
>> Fix issue #4056 "don't record non-inheritable mergeinfo if missing
>> subtrees are not touched by the full-depth diff".
>>
>> * subversion/libsvn_client/mergeinfo.h
>>
>> (svn_client__merge_path_t): Add a few new members.
>>
>> * subversion/libsvn_client/merge.c
>>
>> (calculate_merge_inheritance): Stop adjusting a rangelist in place and
>> instead simply communicate back to the caller they inheritance type
>> required to describe the merge.
>>
>> (insert_parent_and_sibs_of_sw_absent_del_subtree): Set one of the new
>> svn_client__merge_path_t members.
>>
>> (flag_subtrees_needing_mergeinfo): New. Takes an initial walk over
>
>
> Is there a description missing there?
Yes, I adjusted the log message.
> The other parts of the log message detail don't seem to mention a functional change so I guess it's in this function is it?
It is.
> - Julian
>
>
>> (record_mergeinfo_for_dir_merge): Factor out the bulk of the code which
>> determines if a subtree of interest *needs* new mergeinfo to describe a
>> merge -- see flag_subtrees_needing_mergeinfo for its new home. Leave
>> behind the code which actually *calculates* what the actual mergeinfo is
>> and records it.
>>
>> (do_directory_merge): Account for new differentiation between missing and
>> switched children.
>>
>> * subversion/tests/cmdline/merge_authz_tests.py
>>
>> (mergeinfo_and_skipped_paths): Expand test for greater coverage of
>> issue #4056 and adjust existing expectations to account for the more
>> concise mergeinfo produced by this fix.
>>
>> * subversion/tests/cmdline/merge_tests.py
>>
>> (merge_to_path_with_switched_children): Adjust existing expectations to
>> account for the more concise mergeinfo produced by this fix.
>>
>> (noninheritable_mergeinfo_test_set_up): Adjust test expectations a bit.
>> We still expect no spurious subtree mergeinfo, but how this is
>> accomplished (set it, then elide it) was not what the test
>> originally expected.
>>
>> (unnecessary_noninheritable_mergeinfo_missing_subtrees): Remove XFail
>> decorator and comment.
Re: svn commit: r1209176 - in /subversion/trunk/subversion: libsvn_client/merge.c libsvn_client/mergeinfo.h tests/cmdline/merge_authz_tests.py tests/cmdline/merge_tests.py
Posted by Julian Foad <ju...@btopenworld.com>.
Hi Paul.
> Author: pburba
> Date: Thu Dec 1 18:38:38 2011
> New Revision: 1209176
>
> URL: http://svn.apache.org/viewvc?rev=1209176&view=rev
> Log:
> Fix issue #4056 "don't record non-inheritable mergeinfo if missing
> subtrees are not touched by the full-depth diff".
>
> * subversion/libsvn_client/mergeinfo.h
>
> (svn_client__merge_path_t): Add a few new members.
>
> * subversion/libsvn_client/merge.c
>
> (calculate_merge_inheritance): Stop adjusting a rangelist in place and
> instead simply communicate back to the caller they inheritance type
> required to describe the merge.
>
> (insert_parent_and_sibs_of_sw_absent_del_subtree): Set one of the new
> svn_client__merge_path_t members.
>
> (flag_subtrees_needing_mergeinfo): New. Takes an initial walk over
Is there a description missing there? The other parts of the log message detail don't seem to mention a functional change so I guess it's in this function is it?
- Julian
> (record_mergeinfo_for_dir_merge): Factor out the bulk of the code which
> determines if a subtree of interest *needs* new mergeinfo to describe a
> merge -- see flag_subtrees_needing_mergeinfo for its new home. Leave
> behind the code which actually *calculates* what the actual mergeinfo is
> and records it.
>
> (do_directory_merge): Account for new differentiation between missing and
> switched children.
>
> * subversion/tests/cmdline/merge_authz_tests.py
>
> (mergeinfo_and_skipped_paths): Expand test for greater coverage of
> issue #4056 and adjust existing expectations to account for the more
> concise mergeinfo produced by this fix.
>
> * subversion/tests/cmdline/merge_tests.py
>
> (merge_to_path_with_switched_children): Adjust existing expectations to
> account for the more concise mergeinfo produced by this fix.
>
> (noninheritable_mergeinfo_test_set_up): Adjust test expectations a bit.
> We still expect no spurious subtree mergeinfo, but how this is
> accomplished (set it, then elide it) was not what the test
> originally expected.
>
> (unnecessary_noninheritable_mergeinfo_missing_subtrees): Remove XFail
> decorator and comment.