> Author: cmpilato > URL: http://svn.apache.org/viewvc?rev=1414810&view=rev > Log: > Teach the dry-run merge logic to account for additional flavors of > ra_serf editor drive ordering violations (*sigh*). [...] > > This change causes Subversion to check not just the most recently > added directory, but all added directories (which were already being > tracked elsewhere, anyway) before deeming "dir1/file" an obstructed > merge addition. > > * subversion/libsvn_client/merge.c > (merge_cmd_baton_t): Remove the 'added_path' member. > (dry_run_added_parent_p): New helper function. > (merge_file_added): Now use dry_run_added_parent_p() instead of > merge_b->added_path to look for added parent paths. > (merge_dir_added): Now use dry_run_added_parent_p() instead of > merge_b->added_path to record added paths and to check for added > parent paths. > (do_merge): Don't initialize the now-removed 'added_path' merge > context baton member.
If the logic is that the list of added paths is not necessarily contain all leaf nodes, then doesn't it follow that dry_run_deleted_p() also needs to be updated to check whether any parent of the path being checked is in the list? - Julian > Modified: subversion/trunk/subversion/libsvn_client/merge.c > ============================================================================== > +/* Return true iff we're in dry-run mode and a parent of EDIT_RELPATH > + would have been added by now if we weren't in dry-run mode. > + Used to avoid spurious notifications (e.g. conflicts) from a merge > + attempt into an existing target which would have been deleted if we > + weren't in dry_run mode (issue #2584). Assumes that WCPATH is > + still versioned (e.g. has an associated entry). */ > +static svn_boolean_t > +dry_run_added_parent_p(const merge_cmd_baton_t *merge_b, > + const char *edit_relpath, > + apr_pool_t *scratch_pool) > +{ > + int i; > + const char *abspath; > + > + if (!merge_b->dry_run) > + return FALSE; > + > + abspath = svn_dirent_join(merge_b->target->abspath, edit_relpath, > + scratch_pool); > + for (i = 0; i < (svn_path_component_count(edit_relpath) - 1); i++) > + { > + abspath = svn_dirent_dirname(abspath, scratch_pool); > + if (apr_hash_get(merge_b->dry_run_added, abspath, > + APR_HASH_KEY_STRING)) > + return TRUE; > + } > + return FALSE; > +} > + > /* Return whether any WC path was put in conflict by the merge > operation corresponding to MERGE_B. */ > static APR_INLINE svn_boolean_t > @@ -1857,8 +1883,8 @@ merge_file_added(svn_wc_notify_state_t * > > if (obstr_state != svn_wc_notify_state_inapplicable) > { > - if (merge_b->dry_run && merge_b->added_path > - && svn_dirent_is_child(merge_b->added_path, > mine_abspath, NULL)) > + if (merge_b->dry_run > + && dry_run_added_parent_p(merge_b, mine_relpath, > scratch_pool)) > { > if (content_state) > *content_state = svn_wc_notify_state_changed; > @@ -2337,13 +2363,15 @@ merge_dir_added(svn_wc_notify_state_t *s > > if (obstr_state != svn_wc_notify_state_inapplicable) > { > - if (state && merge_b->dry_run && > merge_b->added_path > - && svn_dirent_is_child(merge_b->added_path, > local_abspath, NULL)) > + if (state && merge_b->dry_run > + && dry_run_added_parent_p(merge_b, local_relpath, > scratch_pool)) > { > *state = svn_wc_notify_state_changed; > } > else if (state) > - *state = obstr_state; > + { > + *state = obstr_state; > + } > return SVN_NO_ERROR; > } > > @@ -2358,9 +2386,10 @@ merge_dir_added(svn_wc_notify_state_t *s > /* Unversioned or schedule-delete */ > if (merge_b->dry_run) > { > - merge_b->added_path = apr_pstrdup(merge_b->pool, > local_abspath); > - apr_hash_set(merge_b->dry_run_added, merge_b->added_path, > - APR_HASH_KEY_STRING, merge_b->added_path); > + const char *added_path = apr_pstrdup(merge_b->pool, > + local_abspath); > + apr_hash_set(merge_b->dry_run_added, added_path, > + APR_HASH_KEY_STRING, added_path); > } > else > { > @@ -2385,15 +2414,22 @@ merge_dir_added(svn_wc_notify_state_t *s > /* The dir is not known to Subversion, or is schedule-delete. > * We will make it schedule-add. */ > if (!merge_b->dry_run) > - SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath, > - svn_depth_infinity, > - copyfrom_url, copyfrom_rev, > - merge_b->ctx->cancel_func, > - merge_b->ctx->cancel_baton, > - NULL, NULL, /* no notification func! */ > - scratch_pool)); > + { > + SVN_ERR(svn_wc_add4(merge_b->ctx->wc_ctx, local_abspath, > + svn_depth_infinity, > + copyfrom_url, copyfrom_rev, > + merge_b->ctx->cancel_func, > + merge_b->ctx->cancel_baton, > + NULL, NULL, /* no notification func! */ > + scratch_pool)); > + } > else > - merge_b->added_path = apr_pstrdup(merge_b->pool, > local_abspath); > + { > + const char *added_path = apr_pstrdup(merge_b->pool, > + local_abspath); > + apr_hash_set(merge_b->dry_run_added, added_path, > + APR_HASH_KEY_STRING, added_path); > + } > if (state) > *state = svn_wc_notify_state_changed; > } > @@ -2431,9 +2467,6 @@ merge_dir_added(svn_wc_notify_state_t *s > } > break; > case svn_node_file: > - if (merge_b->dry_run) > - merge_b->added_path = NULL; > - > if (is_versioned && dry_run_deleted_p(merge_b, local_abspath)) > { > /* ### TODO: Retain record of this dir being added to > @@ -2455,8 +2488,6 @@ merge_dir_added(svn_wc_notify_state_t *s > } > break; > default: > - if (merge_b->dry_run) > - merge_b->added_path = NULL; > if (state) > *state = svn_wc_notify_state_unknown; > break; > @@ -9163,7 +9194,6 @@ do_merge(apr_hash_t **modified_subtrees, > be reset for each merge source iteration. */ > merge_cmd_baton.merge_source = *source; > merge_cmd_baton.implicit_src_gap = NULL; > - merge_cmd_baton.added_path = NULL; > merge_cmd_baton.add_necessitated_merge = FALSE; > merge_cmd_baton.dry_run_deletions = > dry_run ? apr_hash_make(iterpool) : NULL; >