subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From br...@apache.org
Subject svn commit: r1657947 [2/3] - in /subversion/branches/reuse-ra-session: ./ subversion/bindings/cxxhl/include/svncxxhl/ subversion/libsvn_fs/ subversion/libsvn_fs_fs/ subversion/libsvn_fs_x/ subversion/libsvn_repos/ subversion/libsvn_subr/ subversion/lib...
Date Fri, 06 Feb 2015 20:18:24 GMT
Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db_update_move.c Fri Feb  6 20:18:23 2015
@@ -152,18 +152,29 @@ verify_write_lock(svn_wc__db_wcroot_t *w
 typedef struct update_move_baton_t {
   svn_wc__db_t *db;
   svn_wc__db_wcroot_t *wcroot;
-  const char *move_root_dst_relpath;
 
-  /* The most recent conflict raised during this drive.  We rely on the
-     non-Ev2, depth-first, drive for this to make sense. */
-  const char *conflict_root_relpath;
+  int src_op_depth;
+  int dst_op_depth;
 
   svn_wc_operation_t operation;
   svn_wc_conflict_version_t *old_version;
   svn_wc_conflict_version_t *new_version;
-  apr_pool_t *result_pool;  /* For things that live as long as the baton. */
 } update_move_baton_t;
 
+/* Per node flags for tree conflict collection */
+typedef struct node_move_baton_t
+{
+  svn_boolean_t skip;
+  svn_boolean_t shadowed;
+  svn_boolean_t edited;
+
+  const char *src_relpath;
+  const char *dst_relpath;
+
+  update_move_baton_t *umb;
+  struct node_move_baton_t *pb;
+} node_move_baton_t;
+
 /*
  * Notifications are delayed until the entire update-move transaction
  * completes. These functions provide the necessary support by storing
@@ -171,24 +182,41 @@ typedef struct update_move_baton_t {
  * and spooling notifications out of that table after the transaction.
  */
 
-/* Add an entry to the notification list. */
+/* Add an entry to the notification list, and at the same time install
+   a conflict and/or work items. */
 static svn_error_t *
 update_move_list_add(svn_wc__db_wcroot_t *wcroot,
                      const char *local_relpath,
                      svn_wc_notify_action_t action,
                      svn_node_kind_t kind,
                      svn_wc_notify_state_t content_state,
-                     svn_wc_notify_state_t prop_state)
-
+                     svn_wc_notify_state_t prop_state,
+                     svn_skel_t *conflict,
+                     svn_skel_t *work_item,
+                     apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
 
+  if (conflict)
+    {
+      action = svn_wc_notify_tree_conflict;
+      content_state = svn_wc_notify_state_inapplicable;
+      prop_state = svn_wc_notify_state_inapplicable;
+    }
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_INSERT_UPDATE_MOVE_LIST));
   SVN_ERR(svn_sqlite__bindf(stmt, "sdddd", local_relpath,
                             action, kind, content_state, prop_state));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+  if (conflict)
+    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath, conflict,
+                                              scratch_pool));
+
+  if (work_item)
+    SVN_ERR(svn_wc__db_wq_add_internal(wcroot, work_item, scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -248,23 +276,25 @@ svn_wc__db_update_move_list_notify(svn_w
   return SVN_NO_ERROR;
 }
 
-/* Mark a tree-conflict on LOCAL_RELPATH if such a tree-conflict does
-   not already exist. */
+/* Create a tree-conflict for recording on LOCAL_RELPATH if such
+   a tree-conflict does not already exist. */
 static svn_error_t *
-mark_tree_conflict(const char *local_relpath,
-                   svn_wc__db_wcroot_t *wcroot,
-                   svn_wc__db_t *db,
-                   const svn_wc_conflict_version_t *old_version,
-                   const svn_wc_conflict_version_t *new_version,
-                   const char *move_root_dst_relpath,
-                   svn_wc_operation_t operation,
-                   svn_node_kind_t old_kind,
-                   svn_node_kind_t new_kind,
-                   const char *old_repos_relpath,
-                   svn_wc_conflict_reason_t reason,
-                   svn_wc_conflict_action_t action,
-                   const char *move_src_op_root_relpath,
-                   apr_pool_t *scratch_pool)
+create_tree_conflict(svn_skel_t **conflict_p,
+                     svn_wc__db_wcroot_t *wcroot,
+                     const char *local_relpath,
+                     const char *dst_op_root_relpath,
+                     svn_wc__db_t *db,
+                     const svn_wc_conflict_version_t *old_version,
+                     const svn_wc_conflict_version_t *new_version,
+                     svn_wc_operation_t operation,
+                     svn_node_kind_t old_kind,
+                     svn_node_kind_t new_kind,
+                     const char *old_repos_relpath,
+                     svn_wc_conflict_reason_t reason,
+                     svn_wc_conflict_action_t action,
+                     const char *move_src_op_root_relpath,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
 {
   svn_error_t *err;
   svn_skel_t *conflict;
@@ -288,7 +318,7 @@ mark_tree_conflict(const char *local_rel
   if (!new_repos_relpath)
     {
       const char *child_relpath = svn_relpath_skip_ancestor(
-                                            move_root_dst_relpath,
+                                            dst_op_root_relpath,
                                             local_relpath);
       SVN_ERR_ASSERT(child_relpath != NULL);
       new_repos_relpath = svn_relpath_join(new_version->path_in_repos,
@@ -296,7 +326,7 @@ mark_tree_conflict(const char *local_rel
     }
 
   err = svn_wc__db_read_conflict_internal(&conflict, wcroot, local_relpath,
-                                          scratch_pool, scratch_pool);
+                                          result_pool, scratch_pool);
   if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
     return svn_error_trace(err);
   else if (err)
@@ -348,11 +378,12 @@ mark_tree_conflict(const char *local_rel
                                                             scratch_pool));
 
           /* Already a suitable tree-conflict. */
+          *conflict_p = conflict;
           return SVN_NO_ERROR;
         }
     }
   else
-    conflict = svn_wc__conflict_skel_create(scratch_pool);
+    conflict = svn_wc__conflict_skel_create(result_pool);
 
   SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(
                      conflict, db,
@@ -361,7 +392,7 @@ mark_tree_conflict(const char *local_rel
                      reason,
                      action,
                      move_src_op_root_abspath,
-                     scratch_pool,
+                     result_pool,
                      scratch_pool));
 
   if (reason != svn_wc_conflict_reason_unversioned
@@ -384,53 +415,71 @@ mark_tree_conflict(const char *local_rel
     {
       SVN_ERR(svn_wc__conflict_skel_set_op_update(
                 conflict, conflict_old_version, conflict_new_version,
-                scratch_pool, scratch_pool));
+                result_pool, scratch_pool));
     }
   else
     {
       assert(operation == svn_wc_operation_switch);
       SVN_ERR(svn_wc__conflict_skel_set_op_switch(
                   conflict, conflict_old_version, conflict_new_version,
-                  scratch_pool, scratch_pool));
+                  result_pool, scratch_pool));
     }
 
-  SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
-                                            conflict, scratch_pool));
-
-  SVN_ERR(update_move_list_add(wcroot, local_relpath,
-                               svn_wc_notify_tree_conflict,
-                               new_kind,
-                               svn_wc_notify_state_inapplicable,
-                               svn_wc_notify_state_inapplicable));
+  *conflict_p = conflict;
   return SVN_NO_ERROR;
 }
 
-/* Checks if a specific local path is shadowed as seen from the move root */
+static svn_error_t *
+create_node_tree_conflict(svn_skel_t **conflict_p,
+                          node_move_baton_t *nmb,
+                          const char *dst_local_relpath,
+                          svn_node_kind_t old_kind,
+                          svn_node_kind_t new_kind,
+                          const char *old_repos_relpath,
+                          svn_wc_conflict_reason_t reason,
+                          svn_wc_conflict_action_t action,
+                          const char *move_src_op_root_relpath,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  update_move_baton_t *umb = nmb->umb;
+
+  return svn_error_trace(
+            create_tree_conflict(conflict_p, umb->wcroot, dst_local_relpath,
+                                 svn_relpath_limit(dst_local_relpath,
+                                                   umb->dst_op_depth,
+                                                   scratch_pool),
+                                 umb->db,
+                                 umb->old_version, umb->new_version,
+                                 umb->operation, old_kind, new_kind,
+                                 old_repos_relpath,
+                                 reason, action, move_src_op_root_relpath,
+                                 result_pool, scratch_pool));
+}
+
+/* Checks if a specific local path is shadowed as seen from the move root.
+   Helper for update_moved_away_node() */
 static svn_error_t *
 check_node_shadowed(svn_boolean_t *shadowed,
                     svn_wc__db_wcroot_t *wcroot,
                     const char *local_relpath,
-                    const char *move_root_dst_relpath,
+                    int move_root_dst_op_depth,
                     apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
-  /* ### This should really be optimized by using something smart
-         in the baton */
-
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_WORKING_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-
   if (have_row)
     {
-      int op_depth = -1;
+      int op_depth = svn_sqlite__column_int(stmt, 0);
 
-      *shadowed = (op_depth > relpath_depth(move_root_dst_relpath));
+      *shadowed = (op_depth > move_root_dst_op_depth);
     }
   else
     *shadowed = FALSE;
@@ -439,114 +488,158 @@ check_node_shadowed(svn_boolean_t *shado
   return SVN_NO_ERROR;
 }
 
-/* If LOCAL_RELPATH is a child of the most recently raised
-   tree-conflict or is shadowed then set *IS_CONFLICTED to TRUE and
-   raise a tree-conflict on the root of the obstruction if such a
-   tree-conflict does not already exist.  KIND is the kind of the
-   incoming LOCAL_RELPATH. This relies on the non-Ev2, depth-first,
-   drive. */
+/* Set a tree conflict for the shadowed node LOCAL_RELPATH, on the
+   ROOT OF THE OBSTRUCTION if such a tree-conflict does not already
+   exist.  KIND is the kind of the incoming LOCAL_RELPATH. */
 static svn_error_t *
-check_tree_conflict(svn_boolean_t *is_conflicted,
-                    update_move_baton_t *b,
-                    const char *local_relpath,
-                    svn_node_kind_t old_kind,
-                    svn_node_kind_t new_kind,
-                    const char *old_repos_relpath,
-                    svn_wc_conflict_action_t action,
-                    apr_pool_t *scratch_pool)
+mark_tc_on_op_root(node_move_baton_t *nmb,
+                   svn_node_kind_t old_kind,
+                   svn_node_kind_t new_kind,
+                   const char *old_repos_relpath,
+                   svn_wc_conflict_action_t action,
+                   apr_pool_t *scratch_pool)
 {
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  int dst_op_depth = relpath_depth(b->move_root_dst_relpath);
-  int op_depth;
-  const char *conflict_root_relpath = local_relpath;
+  update_move_baton_t *b = nmb->umb;
+  const char *conflict_root_relpath = nmb->dst_relpath;
   const char *move_dst_relpath, *dummy1;
   const char *dummy2, *move_src_op_root_relpath;
+  svn_skel_t *conflict;
 
-  if (b->conflict_root_relpath)
-    {
-      if (svn_relpath_skip_ancestor(b->conflict_root_relpath, local_relpath))
-        {
-          *is_conflicted = TRUE;
-          return SVN_NO_ERROR;
-        }
-      b->conflict_root_relpath = NULL;
-    }
+  SVN_ERR_ASSERT(nmb->shadowed);
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
-                                    STMT_SELECT_LOWEST_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, local_relpath,
-                            dst_op_depth));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (have_row)
-    op_depth = svn_sqlite__column_int(stmt, 0);
-  SVN_ERR(svn_sqlite__reset(stmt));
+  nmb->skip = TRUE;
 
-  if (!have_row)
+  while (nmb->pb && nmb->pb->shadowed)
     {
-      *is_conflicted = FALSE;
-      return SVN_NO_ERROR;
-    }
+      nmb = nmb->pb;
 
-  *is_conflicted = TRUE;
+      conflict_root_relpath = nmb->dst_relpath;
 
-  while (relpath_depth(conflict_root_relpath) > op_depth)
-    {
-      conflict_root_relpath = svn_relpath_dirname(conflict_root_relpath,
-                                                  scratch_pool);
       old_kind = new_kind = svn_node_dir;
       if (old_repos_relpath)
         old_repos_relpath = svn_relpath_dirname(old_repos_relpath,
                                                 scratch_pool);
       action = svn_wc_conflict_action_edit;
+
+      nmb->skip = TRUE;
     }
 
   SVN_ERR(svn_wc__db_op_depth_moved_to(&move_dst_relpath,
                                        &dummy1,
                                        &dummy2,
                                        &move_src_op_root_relpath,
-                                       dst_op_depth,
+                                       b->dst_op_depth,
                                        b->wcroot, conflict_root_relpath,
                                        scratch_pool, scratch_pool));
 
-  SVN_ERR(mark_tree_conflict(conflict_root_relpath,
-                             b->wcroot, b->db, b->old_version, b->new_version,
-                             b->move_root_dst_relpath, b->operation,
-                             old_kind, new_kind,
-                             old_repos_relpath,
-                             (move_dst_relpath
-                              ? svn_wc_conflict_reason_moved_away
-                              : svn_wc_conflict_reason_deleted),
-                             action, move_src_op_root_relpath,
-                             scratch_pool));
-  b->conflict_root_relpath = apr_pstrdup(b->result_pool, conflict_root_relpath);
+  SVN_ERR(create_node_tree_conflict(&conflict, nmb, conflict_root_relpath,
+                                    old_kind, new_kind,
+                                    old_repos_relpath,
+                                    (move_dst_relpath
+                                     ? svn_wc_conflict_reason_moved_away
+                                     : svn_wc_conflict_reason_deleted),
+                                    action, move_src_op_root_relpath,
+                                    scratch_pool, scratch_pool));
+
+  SVN_ERR(update_move_list_add(b->wcroot, conflict_root_relpath,
+                               svn_wc_notify_tree_conflict,
+                               new_kind,
+                               svn_wc_notify_state_inapplicable,
+                               svn_wc_notify_state_inapplicable,
+                               conflict, NULL, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+mark_node_edited(node_move_baton_t *nmb,
+                 apr_pool_t *scratch_pool)
+{
+  if (nmb->edited)
+    return SVN_NO_ERROR;
+
+  if (nmb->pb)
+    {
+      SVN_ERR(mark_node_edited(nmb->pb, scratch_pool));
+
+      if (nmb->pb->skip)
+        nmb->skip = TRUE;
+    }
+
+  nmb->edited = TRUE;
+
+  if (nmb->skip)
+    return SVN_NO_ERROR;
+
+  if (nmb->shadowed && !(nmb->pb && nmb->pb->shadowed))
+    {
+      svn_node_kind_t dst_kind, src_kind;
+      const char *dst_repos_relpath;
+
+      SVN_ERR(svn_wc__db_depth_get_info(NULL, &dst_kind, NULL,
+                                        &dst_repos_relpath, NULL, NULL, NULL,
+                                        NULL, NULL, NULL, NULL, NULL, NULL,
+                                        nmb->umb->wcroot, nmb->dst_relpath,
+                                        nmb->umb->dst_op_depth,
+                                        scratch_pool, scratch_pool));
+
+      SVN_ERR(svn_wc__db_depth_get_info(NULL, &src_kind, NULL, NULL,
+                                        NULL, NULL, NULL,
+                                        NULL, NULL, NULL, NULL, NULL, NULL,
+                                        nmb->umb->wcroot, nmb->src_relpath,
+                                        nmb->umb->src_op_depth,
+                                        scratch_pool, scratch_pool));
+
+      SVN_ERR(mark_tc_on_op_root(nmb,
+                                 dst_kind, src_kind,
+                                 dst_repos_relpath,
+                                 svn_wc_conflict_action_edit,
+                                 scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+mark_parent_edited(node_move_baton_t *nmb,
+                 apr_pool_t *scratch_pool)
+{
+  SVN_ERR_ASSERT(nmb && nmb->pb);
+
+  SVN_ERR(mark_node_edited(nmb->pb, scratch_pool));
+
+  if (nmb->pb->skip)
+    nmb->skip = TRUE;
 
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
-tc_editor_add_directory(update_move_baton_t *b,
+tc_editor_add_directory(node_move_baton_t *nmb,
                         const char *relpath,
                         apr_hash_t *props,
-                        svn_boolean_t shadowed,
                         apr_pool_t *scratch_pool)
 {
+  update_move_baton_t *b = nmb->umb;
   const char *move_dst_repos_relpath;
   svn_node_kind_t move_dst_kind;
-  svn_boolean_t is_conflicted;
-  const char *abspath;
+  const char *local_abspath;
   svn_node_kind_t old_kind;
-  svn_skel_t *work_item;
+  svn_skel_t *work_item = NULL;
   svn_wc_notify_action_t action = svn_wc_notify_update_add;
   svn_error_t *err;
+  svn_skel_t *conflict = NULL;
+
+  SVN_ERR(mark_parent_edited(nmb, scratch_pool));
+  if (nmb->skip)
+    return SVN_NO_ERROR;
 
   /* Update NODES, only the bits not covered by the later call to
      replace_moved_layer. */
   err = svn_wc__db_depth_get_info(NULL, &move_dst_kind, NULL,
                                   &move_dst_repos_relpath, NULL, NULL, NULL,
                                   NULL, NULL, NULL, NULL, NULL, NULL,
-                                  b->wcroot, relpath,
-                                  relpath_depth(b->move_root_dst_relpath),
+                                  b->wcroot, relpath, b->dst_op_depth,
                                   scratch_pool, scratch_pool);
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
     {
@@ -560,77 +653,77 @@ tc_editor_add_directory(update_move_bato
       old_kind = move_dst_kind;
     }
 
-  /* Check for NODES tree-conflict. */
-  SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
-                              old_kind, svn_node_dir,
-                              move_dst_repos_relpath,
-                              svn_wc_conflict_action_add,
-                              scratch_pool));
-  if (is_conflicted || shadowed)
-    return SVN_NO_ERROR;
+  if (nmb->shadowed)
+    {
+      SVN_ERR(mark_tc_on_op_root(nmb,
+                                 old_kind, svn_node_dir,
+                                 move_dst_repos_relpath,
+                                 svn_wc_conflict_action_add,
+                                 scratch_pool));
+      return SVN_NO_ERROR;
+    }
 
   /* Check for unversioned tree-conflict */
-  abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
-  SVN_ERR(svn_io_check_path(abspath, &old_kind, scratch_pool));
+  local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
+  SVN_ERR(svn_io_check_path(local_abspath, &old_kind, scratch_pool));
 
   switch (old_kind)
     {
     case svn_node_file:
     default:
-      SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
-                                 b->new_version, b->move_root_dst_relpath,
-                                 b->operation, old_kind, svn_node_dir,
-                                 move_dst_repos_relpath,
-                                 svn_wc_conflict_reason_unversioned,
-                                 svn_wc_conflict_action_add, NULL,
-                                 scratch_pool));
-      b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
+      SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath,
+                                        old_kind, svn_node_dir,
+                                        move_dst_repos_relpath,
+                                        svn_wc_conflict_reason_unversioned,
+                                        svn_wc_conflict_action_add, NULL,
+                                        scratch_pool, scratch_pool));
+      nmb->skip = TRUE;
       action = svn_wc_notify_tree_conflict;
-      is_conflicted = TRUE;
       break;
 
     case svn_node_none:
-      SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, abspath,
+      SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, local_abspath,
                                            scratch_pool, scratch_pool));
-
-      SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_item, scratch_pool));
       /* Fall through */
     case svn_node_dir:
       break;
     }
 
-  if (!is_conflicted)
-    SVN_ERR(update_move_list_add(b->wcroot, relpath,
-                                 action,
-                                 svn_node_dir,
-                                 svn_wc_notify_state_inapplicable,
-                                 svn_wc_notify_state_inapplicable));
+  SVN_ERR(update_move_list_add(b->wcroot, relpath,
+                               action,
+                               svn_node_dir,
+                               svn_wc_notify_state_inapplicable,
+                               svn_wc_notify_state_inapplicable,
+                               conflict, work_item, scratch_pool));
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
-tc_editor_add_file(update_move_baton_t *b,
+tc_editor_add_file(node_move_baton_t *nmb,
                    const char *relpath,
                    const svn_checksum_t *checksum,
                    apr_hash_t *props,
-                   svn_boolean_t shadowed,
                    apr_pool_t *scratch_pool)
 {
+  update_move_baton_t *b = nmb->umb;
   const char *move_dst_repos_relpath;
   svn_node_kind_t move_dst_kind;
   svn_node_kind_t old_kind;
-  svn_boolean_t is_conflicted;
-  const char *abspath;
-  svn_skel_t *work_item;
+  const char *local_abspath;
+  svn_skel_t *work_item = NULL;
+  svn_skel_t *conflict = NULL;
   svn_error_t *err;
 
+  SVN_ERR(mark_parent_edited(nmb, scratch_pool));
+  if (nmb->skip)
+    return SVN_NO_ERROR;
+
   /* Update NODES, only the bits not covered by the later call to
      replace_moved_layer. */
   err = svn_wc__db_depth_get_info(NULL, &move_dst_kind, NULL,
                                   &move_dst_repos_relpath, NULL, NULL, NULL,
                                   NULL, NULL, NULL, NULL, NULL, NULL,
-                                  b->wcroot, relpath,
-                                  relpath_depth(b->move_root_dst_relpath),
+                                  b->wcroot, relpath, b->dst_op_depth,
                                   scratch_pool, scratch_pool);
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
     {
@@ -645,47 +738,49 @@ tc_editor_add_file(update_move_baton_t *
     }
 
   /* Check for NODES tree-conflict. */
-  SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
-                              old_kind, svn_node_file, move_dst_repos_relpath,
-                              svn_wc_conflict_action_add,
-                              scratch_pool));
-  if (is_conflicted || shadowed)
-    return SVN_NO_ERROR;
-
-  /* Check for unversioned tree-conflict */
-  abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
-  SVN_ERR(svn_io_check_path(abspath, &old_kind, scratch_pool));
-
-  if (old_kind != svn_node_none)
+  if (nmb->shadowed)
     {
-      SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
-                                 b->new_version, b->move_root_dst_relpath,
-                                 b->operation, old_kind, svn_node_file,
+      SVN_ERR(mark_tc_on_op_root(nmb,
+                                 old_kind, svn_node_file,
                                  move_dst_repos_relpath,
-                                 svn_wc_conflict_reason_unversioned,
-                                 svn_wc_conflict_action_add, NULL,
+                                 svn_wc_conflict_action_add,
                                  scratch_pool));
-      b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
       return SVN_NO_ERROR;
     }
 
-  /* Update working file. */
-  SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
-                                        svn_dirent_join(b->wcroot->abspath,
-                                                        relpath,
-                                                        scratch_pool),
-                                        NULL,
-                                        FALSE /* FIXME: use_commit_times? */,
-                                        TRUE  /* record_file_info */,
-                                        scratch_pool, scratch_pool));
+  /* Check for unversioned tree-conflict */
+  local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
+  SVN_ERR(svn_io_check_path(local_abspath, &old_kind, scratch_pool));
 
-  SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_item, scratch_pool));
+  if (old_kind != svn_node_none)
+    {
+      SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath,
+                                        old_kind, svn_node_file,
+                                        move_dst_repos_relpath,
+                                        svn_wc_conflict_reason_unversioned,
+                                        svn_wc_conflict_action_add, NULL,
+                                        scratch_pool, scratch_pool));
+      nmb->skip = TRUE;
+    }
+  else
+    {
+      /* Update working file. */
+      SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
+                                            svn_dirent_join(b->wcroot->abspath,
+                                                            relpath,
+                                                            scratch_pool),
+                                            NULL,
+                                            FALSE /*FIXME: use_commit_times?*/,
+                                            TRUE  /* record_file_info */,
+                                            scratch_pool, scratch_pool));
+    }
 
   SVN_ERR(update_move_list_add(b->wcroot, relpath,
                                svn_wc_notify_update_add,
                                svn_node_file,
                                svn_wc_notify_state_inapplicable,
-                               svn_wc_notify_state_inapplicable));
+                               svn_wc_notify_state_inapplicable,
+                               conflict, work_item, scratch_pool));
   return SVN_NO_ERROR;
 }
 
@@ -810,41 +905,33 @@ update_working_props(svn_wc_notify_state
 }
 
 static svn_error_t *
-tc_editor_alter_directory(update_move_baton_t *b,
+tc_editor_alter_directory(node_move_baton_t *nmb,
                           const char *dst_relpath,
                           apr_hash_t *new_props,
-                          svn_boolean_t shadowed,
                           apr_pool_t *scratch_pool)
 {
+  update_move_baton_t *b = nmb->umb;
   const char *move_dst_repos_relpath;
   svn_revnum_t move_dst_revision;
   svn_node_kind_t move_dst_kind;
   working_node_version_t old_version, new_version;
   svn_wc__db_status_t status;
-  svn_boolean_t is_conflicted;
+  svn_skel_t *work_items = NULL;
+  svn_skel_t *conflict_skel = NULL;
+
+  if (new_props)
+    SVN_ERR(mark_node_edited(nmb, scratch_pool));
+  if (nmb->skip)
+    return SVN_NO_ERROR;
 
   SVN_ERR(svn_wc__db_depth_get_info(&status, &move_dst_kind, &move_dst_revision,
                                     &move_dst_repos_relpath, NULL, NULL, NULL,
                                     NULL, NULL, &old_version.checksum, NULL,
                                     NULL, &old_version.props,
-                                    b->wcroot, dst_relpath,
-                                    relpath_depth(b->move_root_dst_relpath),
+                                    b->wcroot, dst_relpath, b->dst_op_depth,
                                     scratch_pool, scratch_pool));
 
 
-  /* There might be not-present nodes of a different revision as the same
-     depth as a copy. This is commonly caused by copying/moving mixed revision
-     directories */
-  SVN_ERR_ASSERT(move_dst_kind == svn_node_dir);
-
-  SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath,
-                              move_dst_kind,
-                              svn_node_dir,
-                              move_dst_repos_relpath,
-                              svn_wc_conflict_action_edit,
-                              scratch_pool));
-  if (is_conflicted || shadowed)
-    return SVN_NO_ERROR;
 
   old_version.location_and_kind = b->old_version;
   new_version.location_and_kind = b->new_version;
@@ -858,7 +945,6 @@ tc_editor_alter_directory(update_move_ba
                                                 dst_relpath,
                                                 scratch_pool);
       svn_wc_notify_state_t prop_state;
-      svn_skel_t *conflict_skel = NULL;
       apr_hash_t *actual_props;
       apr_array_header_t *propchanges;
 
@@ -871,33 +957,29 @@ tc_editor_alter_directory(update_move_ba
 
       if (conflict_skel)
         {
-          svn_skel_t *work_items;
-
           SVN_ERR(create_conflict_markers(&work_items, dst_abspath,
                                           b->db, move_dst_repos_relpath,
                                           conflict_skel, b->operation,
                                           &old_version, &new_version,
                                           svn_node_dir,
                                           scratch_pool, scratch_pool));
-          SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, dst_relpath,
-                                                    conflict_skel,
-                                                    scratch_pool));
-          SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_items,
-                                             scratch_pool));
         }
 
     SVN_ERR(update_move_list_add(b->wcroot, dst_relpath,
                                  svn_wc_notify_update_update,
                                  svn_node_dir,
                                  svn_wc_notify_state_inapplicable,
-                                 prop_state));
+                                 prop_state,
+                                 conflict_skel, work_items, scratch_pool));
     }
 
   return SVN_NO_ERROR;
 }
 
-
-/* Merge the difference between OLD_VERSION and NEW_VERSION into
+/* Edit the file found at the move destination, which is initially at
+ * the old state.  Merge the changes into the "working"/"actual" file.
+ *
+ * Merge the difference between OLD_VERSION and NEW_VERSION into
  * the working file at LOCAL_RELPATH.
  *
  * The term 'old' refers to the pre-update state, which is the state of
@@ -912,16 +994,17 @@ tc_editor_alter_directory(update_move_ba
  * Set *WORK_ITEMS to any required work items, allocated in RESULT_POOL.
  * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
-update_working_file(update_move_baton_t *b,
-                    const char *local_relpath,
-                    const char *repos_relpath,
-                    svn_wc_operation_t operation,
-                    const working_node_version_t *old_version,
-                    const working_node_version_t *new_version,
-                    apr_pool_t *scratch_pool)
+tc_editor_alter_file(node_move_baton_t *nmb,
+                     const char *dst_relpath,
+                     const svn_checksum_t *new_checksum,
+                     apr_hash_t *new_props,
+                     apr_pool_t *scratch_pool)
 {
+  update_move_baton_t *b = nmb->umb;
+  const char *move_dst_repos_relpath;
+  working_node_version_t old_version, new_version;
   const char *local_abspath = svn_dirent_join(b->wcroot->abspath,
-                                              local_relpath,
+                                              dst_relpath,
                                               scratch_pool);
   const char *old_pristine_abspath;
   const char *new_pristine_abspath;
@@ -932,13 +1015,31 @@ update_working_file(update_move_baton_t
   svn_wc_notify_state_t prop_state, content_state;
   svn_skel_t *work_item, *work_items = NULL;
 
+  SVN_ERR(mark_node_edited(nmb, scratch_pool));
+  if (nmb->skip)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, NULL,
+                                    &move_dst_repos_relpath, NULL, NULL, NULL,
+                                    NULL, NULL, &old_version.checksum, NULL,
+                                    NULL, &old_version.props,
+                                    b->wcroot, dst_relpath, b->dst_op_depth,
+                                    scratch_pool, scratch_pool));
+
+  old_version.location_and_kind = b->old_version;
+  new_version.location_and_kind = b->new_version;
+
+  /* If new checksum is null that means no change; similarly props. */
+  new_version.checksum = new_checksum ? new_checksum : old_version.checksum;
+  new_version.props = new_props ? new_props : old_version.props;
+
   /* ### TODO: Only do this when there is no higher WORKING layer */
   SVN_ERR(update_working_props(&prop_state, &conflict_skel, &propchanges,
-                               &actual_props, b, local_relpath,
-                               old_version, new_version,
+                               &actual_props, b, dst_relpath,
+                               &old_version, &new_version,
                                scratch_pool, scratch_pool));
 
-  if (!svn_checksum_match(new_version->checksum, old_version->checksum))
+  if (!svn_checksum_match(new_version.checksum, old_version.checksum))
     {
       svn_boolean_t is_locally_modified;
 
@@ -969,11 +1070,11 @@ update_working_file(update_move_baton_t
            */
           SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath,
                                                b->db, b->wcroot->abspath,
-                                               old_version->checksum,
+                                               old_version.checksum,
                                                scratch_pool, scratch_pool));
           SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath,
                                                b->db, b->wcroot->abspath,
-                                               new_version->checksum,
+                                               new_version.checksum,
                                                scratch_pool, scratch_pool));
           SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel,
                                          &merge_outcome, b->db,
@@ -1006,123 +1107,67 @@ update_working_file(update_move_baton_t
   if (conflict_skel)
     {
       SVN_ERR(create_conflict_markers(&work_item, local_abspath, b->db,
-                                      repos_relpath, conflict_skel,
-                                      operation, old_version, new_version,
+                                      move_dst_repos_relpath, conflict_skel,
+                                      b->operation, &old_version, &new_version,
                                       svn_node_file,
                                       scratch_pool, scratch_pool));
 
-      SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, local_relpath,
-                                                conflict_skel,
-                                                scratch_pool));
-
       work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
     }
 
-  SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_items, scratch_pool));
-
-  SVN_ERR(update_move_list_add(b->wcroot, local_relpath,
+  SVN_ERR(update_move_list_add(b->wcroot, dst_relpath,
                                svn_wc_notify_update_update,
                                svn_node_file,
                                content_state,
-                               prop_state));
+                               prop_state,
+                               conflict_skel, work_items, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
-
-/* Edit the file found at the move destination, which is initially at
- * the old state.  Merge the changes into the "working"/"actual" file.
- */
 static svn_error_t *
-tc_editor_alter_file(update_move_baton_t *b, 
-                     const char *dst_relpath,
-                     const svn_checksum_t *new_checksum,
-                     apr_hash_t *new_props,
-                     svn_boolean_t shadowed,
-                     apr_pool_t *scratch_pool)
-{
-  const char *move_dst_repos_relpath;
-  svn_revnum_t move_dst_revision;
-  svn_node_kind_t move_dst_kind;
-  working_node_version_t old_version, new_version;
-  svn_boolean_t is_conflicted;
-  svn_wc__db_status_t status;
-
-  SVN_ERR(svn_wc__db_depth_get_info(&status, &move_dst_kind, &move_dst_revision,
-                                    &move_dst_repos_relpath, NULL, NULL, NULL,
-                                    NULL, NULL, &old_version.checksum, NULL,
-                                    NULL, &old_version.props,
-                                    b->wcroot, dst_relpath,
-                                    relpath_depth(b->move_root_dst_relpath),
-                                    scratch_pool, scratch_pool));
-
-  SVN_ERR_ASSERT(move_dst_kind == svn_node_file);
-
-  SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath,
-                              move_dst_kind,
-                              svn_node_file,
-                              move_dst_repos_relpath,
-                              svn_wc_conflict_action_edit,
-                              scratch_pool));
-  if (is_conflicted || shadowed)
-    return SVN_NO_ERROR;
-
-  old_version.location_and_kind = b->old_version;
-  new_version.location_and_kind = b->new_version;
-
-  /* If new checksum is null that means no change; similarly props. */
-  new_version.checksum = new_checksum ? new_checksum : old_version.checksum;
-  new_version.props = new_props ? new_props : old_version.props;
-
-  /* Update file and prop contents if the update has changed them. */
-  if (!svn_checksum_match(new_checksum, old_version.checksum) || new_props)
-    {
-      SVN_ERR(update_working_file(b, dst_relpath, move_dst_repos_relpath,
-                                  b->operation, &old_version, &new_version,
-                                  scratch_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-tc_editor_delete(update_move_baton_t *b,
+tc_editor_delete(node_move_baton_t *nmb,
                  const char *relpath,
-                 svn_boolean_t shadowed,
                  apr_pool_t *scratch_pool)
 {
+  update_move_baton_t *b = nmb->umb;
   svn_sqlite__stmt_t *stmt;
-  int op_depth = relpath_depth(b->move_root_dst_relpath);
   const char *move_dst_repos_relpath;
   svn_node_kind_t move_dst_kind;
-  svn_boolean_t is_conflicted;
-  svn_boolean_t must_delete_working_nodes = FALSE;
+  svn_boolean_t must_delete_wc_nodes = FALSE;
   const char *local_abspath;
   svn_boolean_t have_row;
   svn_boolean_t is_modified, is_all_deletes;
+  svn_skel_t *work_items = NULL;
+  svn_skel_t *conflict = NULL;
+
+  SVN_ERR(mark_parent_edited(nmb, scratch_pool));
+  if (nmb->skip)
+    return SVN_NO_ERROR;
 
   SVN_ERR(svn_wc__db_depth_get_info(NULL, &move_dst_kind, NULL,
                                     &move_dst_repos_relpath, NULL, NULL, NULL,
                                     NULL, NULL, NULL, NULL, NULL, NULL,
-                                    b->wcroot, relpath, op_depth,
+                                    b->wcroot, relpath, b->dst_op_depth,
                                     scratch_pool, scratch_pool));
 
   /* Check before retracting delete to catch delete-delete
      conflicts. This catches conflicts on the node itself; deleted
      children are caught as local modifications below.*/
-  SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
-                              move_dst_kind,
-                              svn_node_unknown,
-                              move_dst_repos_relpath,
-                              svn_wc_conflict_action_delete,
-                              scratch_pool));
-
-  if (shadowed || is_conflicted)
-    return SVN_NO_ERROR;
+  if (nmb->shadowed)
+    {
+      SVN_ERR(mark_tc_on_op_root(nmb,
+                                 move_dst_kind,
+                                 svn_node_unknown,
+                                 move_dst_repos_relpath,
+                                 svn_wc_conflict_action_delete,
+                                 scratch_pool));
+      return SVN_NO_ERROR;
+    }
 
   local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
-  SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes, b->db,
-                                      local_abspath,
+  SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes,
+                                      nmb->umb->db, local_abspath,
                                       NULL, NULL, scratch_pool));
   if (is_modified)
     {
@@ -1131,54 +1176,50 @@ tc_editor_delete(update_move_baton_t *b,
       if (!is_all_deletes)
         {
           /* No conflict means no NODES rows at the relpath op-depth
-             so it's easy to convert the modified tree into a copy. */
-          SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
-                                          STMT_UPDATE_OP_DEPTH_RECURSIVE));
-          SVN_ERR(svn_sqlite__bindf(stmt, "isdd", b->wcroot->wc_id, relpath,
-                                    op_depth, relpath_depth(relpath)));
-          SVN_ERR(svn_sqlite__step_done(stmt));
+             so it's easy to convert the modified tree into a copy.
+
+             Note the following assumptions for relpath:
+               * it is not shadowed
+               * it is not the/an op-root. (or we can't make us a copy)
+          */
+
+          SVN_ERR(svn_wc__db_op_make_copy_internal(b->wcroot, relpath,
+                                                   NULL, NULL, scratch_pool));
 
           reason = svn_wc_conflict_reason_edited;
         }
       else
         {
-
-          SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
-                                      STMT_DELETE_WORKING_OP_DEPTH_ABOVE));
-          SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
-                                    op_depth));
-          SVN_ERR(svn_sqlite__step_done(stmt));
-
           reason = svn_wc_conflict_reason_deleted;
-          must_delete_working_nodes = TRUE;
+          must_delete_wc_nodes = TRUE;
         }
-      is_conflicted = TRUE;
-      SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
-                                 b->new_version, b->move_root_dst_relpath,
-                                 b->operation,
-                                 move_dst_kind,
-                                 svn_node_none,
-                                 move_dst_repos_relpath, reason,
-                                 svn_wc_conflict_action_delete, NULL,
-                                 scratch_pool));
-      b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
+      SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath,
+                                        move_dst_kind, svn_node_none,
+                                        move_dst_repos_relpath, reason,
+                                        svn_wc_conflict_action_delete, NULL,
+                                        scratch_pool, scratch_pool));
+      nmb->skip = TRUE;
     }
+  else
+    must_delete_wc_nodes = TRUE;
 
-  if (!is_conflicted || must_delete_working_nodes)
+  if (must_delete_wc_nodes)
     {
       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-      svn_skel_t *work_item;
       svn_node_kind_t del_kind;
       const char *del_abspath;
 
+      /* Get all descendants of the node in reverse order (so children are
+         handled before their parents, but not strictly depth first) */
       SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
-                                        STMT_SELECT_CHILDREN_OP_DEPTH));
+                                        STMT_SELECT_DESCENDANTS_OP_DEPTH_RV));
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
-                                op_depth));
+                                b->dst_op_depth));
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
       while (have_row)
         {
           svn_error_t *err;
+          svn_skel_t *work_item;
 
           svn_pool_clear(iterpool);
 
@@ -1207,95 +1248,31 @@ tc_editor_delete(update_move_baton_t *b,
       SVN_ERR(svn_wc__db_depth_get_info(NULL, &del_kind, NULL, NULL, NULL,
                                         NULL, NULL, NULL, NULL, NULL, NULL,
                                         NULL, NULL,
-                                        b->wcroot, relpath, op_depth,
+                                        b->wcroot, relpath, b->dst_op_depth,
                                         iterpool, iterpool));
       if (del_kind == svn_node_dir)
-        SVN_ERR(svn_wc__wq_build_dir_remove(&work_item, b->db,
+        SVN_ERR(svn_wc__wq_build_dir_remove(&work_items, b->db,
                                             b->wcroot->abspath, local_abspath,
                                             FALSE /* recursive */,
-                                            iterpool, iterpool));
+                                            scratch_pool, iterpool));
       else
-        SVN_ERR(svn_wc__wq_build_file_remove(&work_item, b->db,
+        SVN_ERR(svn_wc__wq_build_file_remove(&work_items, b->db,
                                              b->wcroot->abspath, local_abspath,
                                              iterpool, iterpool));
-      SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_item, iterpool));
-
-      if (!is_conflicted)
-        SVN_ERR(update_move_list_add(b->wcroot, relpath,
-                                     svn_wc_notify_update_delete,
-                                     del_kind,
-                                     svn_wc_notify_state_inapplicable,
-                                     svn_wc_notify_state_inapplicable));
-      svn_pool_destroy(iterpool);
-    }
-  return SVN_NO_ERROR;
-}
-
-/* Delete handling for both WORKING and shadowed nodes */
-static svn_error_t *
-delete_move_leaf(svn_wc__db_wcroot_t *wcroot,
-                 const char *local_relpath,
-                 int op_depth,
-                 apr_pool_t *scratch_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  int op_depth_below;
 
-  /* Deleting the ROWS is valid as long as we update the parent before
-     committing the transaction.  The removed rows could have been
-     replacing a lower layer in which case we need to add base-deleted
-     rows. */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_HIGHEST_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                            svn_relpath_dirname(local_relpath, scratch_pool),
-                            op_depth));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (have_row)
-    op_depth_below = svn_sqlite__column_int(stmt, 0);
-  SVN_ERR(svn_sqlite__reset(stmt));
-  if (have_row)
-    {
-      /* Remove non-shadowing nodes. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_NO_LOWER_LAYER));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath,
-                                op_depth, op_depth_below));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-
-      /* Convert remaining shadowing nodes to presence='base-deleted'. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_REPLACE_WITH_BASE_DELETED));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                                op_depth));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-    }
-  else
-    {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_WORKING_OP_DEPTH));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                                op_depth));
-      SVN_ERR(svn_sqlite__step_done(stmt));
+        svn_pool_destroy(iterpool);
     }
 
-  /* Retract any base-delete for descendants. */
-  {
-    SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_WORKING_BASE_DELETE));
-    SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                              op_depth));
-    SVN_ERR(svn_sqlite__step_done(stmt));
-  }
-  /* And for the node itself */
-  SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, op_depth,
-                                           scratch_pool));
+  SVN_ERR(update_move_list_add(b->wcroot, relpath,
+                               svn_wc_notify_update_delete,
+                               move_dst_kind,
+                               svn_wc_notify_state_inapplicable,
+                               svn_wc_notify_state_inapplicable,
+                               conflict, work_items, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
-
 /*
  * Driver code.
  *
@@ -1496,65 +1473,49 @@ props_match(svn_boolean_t *match,
 /* ### Drive TC_EDITOR so as to ...
  */
 static svn_error_t *
-update_moved_away_node(update_move_baton_t *b,
+update_moved_away_node(node_move_baton_t *nmb,
                        svn_wc__db_wcroot_t *wcroot,
                        const char *src_relpath,
                        const char *dst_relpath,
-                       int src_op_depth,
-                       const char *move_root_dst_relpath,
-                       svn_boolean_t shadowed,
-                       svn_wc__db_t *db,
                        apr_pool_t *scratch_pool)
 {
+  update_move_baton_t *b = nmb->umb;
   svn_node_kind_t src_kind, dst_kind;
   const svn_checksum_t *src_checksum, *dst_checksum;
   apr_hash_t *src_props, *dst_props;
   apr_array_header_t *src_children, *dst_children;
-  int dst_op_depth = relpath_depth(move_root_dst_relpath);
 
   SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
   SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool));
 
   SVN_ERR(get_info(&src_props, &src_checksum, &src_children, &src_kind,
-                   src_relpath, src_op_depth,
+                   src_relpath, b->src_op_depth,
                    wcroot, scratch_pool, scratch_pool));
 
   SVN_ERR(get_info(&dst_props, &dst_checksum, &dst_children, &dst_kind,
-                   dst_relpath, dst_op_depth,
+                   dst_relpath, b->dst_op_depth,
                    wcroot, scratch_pool, scratch_pool));
 
   if (src_kind == svn_node_none
       || (dst_kind != svn_node_none && src_kind != dst_kind))
     {
-      SVN_ERR(tc_editor_delete(b, dst_relpath, shadowed,
-                               scratch_pool));
-
-      /* And perform some work that in some ways belongs in
-         replace_moved_layer() after creating all conflicts */
-      SVN_ERR(delete_move_leaf(b->wcroot, dst_relpath,
-                               relpath_depth(b->move_root_dst_relpath),
-                               scratch_pool));
+      SVN_ERR(tc_editor_delete(nmb, dst_relpath, scratch_pool));
     }
 
+  if (nmb->skip)
+    return SVN_NO_ERROR;
+
   if (src_kind != svn_node_none && src_kind != dst_kind)
     {
-      if (shadowed)
-        {
-          SVN_ERR(svn_wc__db_extend_parent_delete(
-                        b->wcroot, dst_relpath, src_kind,
-                        relpath_depth(b->move_root_dst_relpath), 
-                        scratch_pool));
-        }
       if (src_kind == svn_node_file || src_kind == svn_node_symlink)
         {
-          SVN_ERR(tc_editor_add_file(b, dst_relpath,
-                                     src_checksum, src_props,
-                                     shadowed, scratch_pool));
+          SVN_ERR(tc_editor_add_file(nmb, dst_relpath,
+                                     src_checksum, src_props, scratch_pool));
         }
       else if (src_kind == svn_node_dir)
         {
-          SVN_ERR(tc_editor_add_directory(b, dst_relpath, src_props,
-                                          shadowed, scratch_pool));
+          SVN_ERR(tc_editor_add_directory(nmb, dst_relpath,
+                                          src_props, scratch_pool));
         }
     }
   else if (src_kind != svn_node_none)
@@ -1565,17 +1526,14 @@ update_moved_away_node(update_move_baton
       SVN_ERR(props_match(&match, src_props, dst_props, scratch_pool));
       props = match ? NULL: src_props;
 
-
       if (src_kind == svn_node_file || src_kind == svn_node_symlink)
         {
           if (svn_checksum_match(src_checksum, dst_checksum))
             src_checksum = NULL;
 
           if (props || src_checksum)
-            SVN_ERR(tc_editor_alter_file(b, dst_relpath,
-                                         src_checksum, props,
-                                         shadowed,
-                                         scratch_pool));
+            SVN_ERR(tc_editor_alter_file(nmb, dst_relpath, src_checksum,
+                                         props, scratch_pool));
         }
       else if (src_kind == svn_node_dir)
         {
@@ -1583,12 +1541,14 @@ update_moved_away_node(update_move_baton
             = children_match(src_children, dst_children) ? NULL : src_children;
 
           if (props || children)
-            SVN_ERR(tc_editor_alter_directory(b, dst_relpath, props,
-                                              shadowed,
+            SVN_ERR(tc_editor_alter_directory(nmb, dst_relpath, props,
                                               scratch_pool));
         }
     }
 
+  if (nmb->skip)
+    return SVN_NO_ERROR;
+
   if (src_kind == svn_node_dir)
     {
       apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -1597,9 +1557,12 @@ update_moved_away_node(update_move_baton
       while (i < src_children->nelts || j < dst_children->nelts)
         {
           const char *child_name;
-          const char *src_child_relpath, *dst_child_relpath;
           svn_boolean_t src_only = FALSE, dst_only = FALSE;
-          svn_boolean_t child_shadowed = shadowed;
+          node_move_baton_t cnmb = { 0 };
+
+          cnmb.pb = nmb;
+          cnmb.umb = nmb->umb;
+          cnmb.shadowed = nmb->shadowed;
 
           svn_pool_clear(iterpool);
           if (i >= src_children->nelts)
@@ -1628,86 +1591,28 @@ update_moved_away_node(update_move_baton
               child_name = dst_only ? dst_name : src_name;
             }
 
-          src_child_relpath = svn_relpath_join(src_relpath, child_name,
-                                               iterpool);
-          dst_child_relpath = svn_relpath_join(dst_relpath, child_name,
-                                               iterpool);
-
-          if (!child_shadowed)
-            SVN_ERR(check_node_shadowed(&child_shadowed, wcroot, dst_child_relpath,
-                                        b->move_root_dst_relpath, iterpool));
-
-          SVN_ERR(update_moved_away_node(b, wcroot, src_child_relpath,
-                                         dst_child_relpath, src_op_depth,
-                                         move_root_dst_relpath, child_shadowed,
-                                         db, iterpool));
+          cnmb.src_relpath = svn_relpath_join(src_relpath, child_name,
+                                              iterpool);
+          cnmb.dst_relpath = svn_relpath_join(dst_relpath, child_name,
+                                              iterpool);
+
+          if (!cnmb.shadowed)
+            SVN_ERR(check_node_shadowed(&cnmb.shadowed, wcroot,
+                                        cnmb.dst_relpath, b->dst_op_depth,
+                                        iterpool));
+
+          SVN_ERR(update_moved_away_node(&cnmb, wcroot, cnmb.src_relpath,
+                                         cnmb.dst_relpath, iterpool));
 
           if (!dst_only)
             ++i;
           if (!src_only)
             ++j;
-        }
-    }
 
-  return SVN_NO_ERROR;
-}
-
-/* Update the single op-depth layer in the move destination subtree
-   rooted at DST_RELPATH to make it match the move source subtree
-   rooted at SRC_RELPATH. */
-static svn_error_t *
-replace_moved_layer(const char *src_relpath,
-                    const char *dst_relpath,
-                    int src_op_depth,
-                    svn_wc__db_wcroot_t *wcroot,
-                    apr_pool_t *scratch_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  int dst_op_depth = relpath_depth(dst_relpath);
-
-  SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
-  SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool));
-
-  /* Replace entire subtree at one op-depth. */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_LOCAL_RELPATH_OP_DEPTH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                            src_relpath, src_op_depth));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  while (have_row)
-    {
-      svn_error_t *err;
-      svn_sqlite__stmt_t *stmt2;
-      const char *src_cp_relpath = svn_sqlite__column_text(stmt, 0, NULL);
-      svn_node_kind_t kind = svn_sqlite__column_token(stmt, 1, kind_map);
-      const char *dst_cp_relpath
-        = svn_relpath_join(dst_relpath,
-                           svn_relpath_skip_ancestor(src_relpath,
-                                                     src_cp_relpath),
-                           scratch_pool);
-
-      err = svn_sqlite__get_statement(&stmt2, wcroot->sdb,
-                                      STMT_COPY_NODE_MOVE);
-      if (!err)
-        err = svn_sqlite__bindf(stmt2, "isdsds", wcroot->wc_id,
-                                src_cp_relpath, src_op_depth,
-                                dst_cp_relpath, dst_op_depth,
-                                svn_relpath_dirname(dst_cp_relpath,
-                                                    scratch_pool));
-      if (!err)
-        err = svn_sqlite__step_done(stmt2);
-
-      if (!err && strlen(dst_cp_relpath) > strlen(dst_relpath))
-        err = svn_wc__db_extend_parent_delete(wcroot, dst_cp_relpath, kind,
-                                              dst_op_depth, scratch_pool);
-
-      if (err)
-        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
-
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+          if (nmb->skip) /* Does parent now want a skip? */
+            break;
+        }
     }
-  SVN_ERR(svn_sqlite__reset(stmt));
 
   return SVN_NO_ERROR;
 }
@@ -1727,18 +1632,19 @@ static svn_error_t *
 drive_tree_conflict_editor(update_move_baton_t *b,
                            const char *src_relpath,
                            const char *dst_relpath,
-                           int src_op_depth,
                            svn_wc_operation_t operation,
                            svn_wc_conflict_reason_t local_change,
                            svn_wc_conflict_action_t incoming_change,
                            svn_wc_conflict_version_t *old_version,
                            svn_wc_conflict_version_t *new_version,
-                           svn_wc__db_t *db,
                            svn_wc__db_wcroot_t *wcroot,
                            svn_cancel_func_t cancel_func,
                            void *cancel_baton,
                            apr_pool_t *scratch_pool)
 {
+  node_move_baton_t nmb = { 0 };
+  SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
+  SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool));
   /*
    * Refuse to auto-resolve unsupported tree conflicts.
    */
@@ -1750,16 +1656,23 @@ drive_tree_conflict_editor(update_move_b
                             path_for_error_message(wcroot, src_relpath,
                                                    scratch_pool));
 
+  nmb.umb = b;
+  nmb.src_relpath = src_relpath;
+  nmb.dst_relpath = dst_relpath;
+  /* nmb.shadowed = FALSE; */
+  /* nmb.edited = FALSE; */
+  /* nmb.skip_children = FALSE; */
+
   /* We walk the move source (i.e. the post-update tree), comparing each node
    * with the equivalent node at the move destination and applying the update
    * to nodes at the move destination. */
-  SVN_ERR(update_moved_away_node(b, wcroot, src_relpath, dst_relpath,
-                                 src_op_depth,
-                                 dst_relpath, FALSE /* never shadowed */,
-                                 db, scratch_pool));
+  SVN_ERR(update_moved_away_node(&nmb, wcroot, src_relpath, dst_relpath,
+                                 scratch_pool));
 
-  SVN_ERR(replace_moved_layer(src_relpath, dst_relpath, src_op_depth,
-                              wcroot, scratch_pool));
+  SVN_ERR(svn_wc__db_op_copy_layer_internal(wcroot, src_relpath,
+                                            b->src_op_depth,
+                                            dst_relpath, NULL, NULL,
+                                            scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1843,30 +1756,28 @@ update_moved_away_conflict_victim(svn_wc
                                   void *cancel_baton,
                                   apr_pool_t *scratch_pool)
 {
-  update_move_baton_t umb;
+  update_move_baton_t umb = { NULL };
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   const char *dummy1, *dummy2, *dummy3;
-  int src_op_depth;
   const char *move_root_dst_abspath;
+  const char *move_root_dst_relpath;
 
   /* ### assumes wc write lock already held */
 
   /* Construct editor baton. */
-  memset(&umb, 0, sizeof(umb));
   SVN_ERR(svn_wc__db_op_depth_moved_to(
-            &dummy1, &umb.move_root_dst_relpath, &dummy2, &dummy3,
+            &dummy1, &move_root_dst_relpath, &dummy2, &dummy3,
             relpath_depth(move_src_op_root_relpath) - 1,
             wcroot, victim_relpath, scratch_pool, scratch_pool));
-  if (umb.move_root_dst_relpath == NULL)
+  if (move_root_dst_relpath == NULL)
     return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                              _("The node '%s' has not been moved away"),
                              path_for_error_message(wcroot, victim_relpath,
                                                     scratch_pool));
 
   move_root_dst_abspath
-    = svn_dirent_join(wcroot->abspath, umb.move_root_dst_relpath,
-                      scratch_pool);
+    = svn_dirent_join(wcroot->abspath, move_root_dst_relpath, scratch_pool);
   SVN_ERR(svn_wc__write_check(db, move_root_dst_abspath, scratch_pool));
 
   umb.operation = operation;
@@ -1874,7 +1785,8 @@ update_moved_away_conflict_victim(svn_wc
   umb.new_version= new_version;
   umb.db = db;
   umb.wcroot = wcroot;
-  umb.result_pool = scratch_pool;
+
+  umb.dst_op_depth = relpath_depth(move_root_dst_relpath);
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_HIGHEST_WORKING_NODE));
@@ -1883,7 +1795,7 @@ update_moved_away_conflict_victim(svn_wc
                             relpath_depth(move_src_op_root_relpath)));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (have_row)
-    src_op_depth = svn_sqlite__column_int(stmt, 0);
+    umb.src_op_depth = svn_sqlite__column_int(stmt, 0);
   SVN_ERR(svn_sqlite__reset(stmt));
   if (!have_row)
     return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
@@ -1891,7 +1803,7 @@ update_moved_away_conflict_victim(svn_wc
                              path_for_error_message(wcroot, victim_relpath,
                                                     scratch_pool));
 
-  if (src_op_depth == 0)
+  if (umb.src_op_depth == 0)
     SVN_ERR(suitable_for_move(wcroot, victim_relpath, scratch_pool));
 
   /* Create a new, and empty, list for notification information. */
@@ -1902,13 +1814,12 @@ update_moved_away_conflict_victim(svn_wc
   /* ... and drive it. */
   SVN_ERR(drive_tree_conflict_editor(&umb,
                                      victim_relpath,
-                                     umb.move_root_dst_relpath,
-                                     src_op_depth,
+                                     move_root_dst_relpath,
                                      operation,
                                      local_change, incoming_change,
                                      umb.old_version,
                                      umb.new_version,
-                                     db, wcroot,
+                                     wcroot,
                                      cancel_func, cancel_baton,
                                      scratch_pool));
 
@@ -2061,6 +1972,7 @@ bump_mark_tree_conflict(svn_wc__db_wcroo
   svn_node_kind_t new_kind;
   svn_wc_conflict_version_t *old_version;
   svn_wc_conflict_version_t *new_version;
+  svn_skel_t *conflict;
 
   /* Verify precondition: We are allowed to set a tree conflict here. */
   SVN_ERR(verify_write_lock(wcroot, move_src_root_relpath, scratch_pool));
@@ -2112,16 +2024,23 @@ bump_mark_tree_conflict(svn_wc__db_wcroo
                   repos_root_url, repos_uuid, new_repos_relpath, new_rev,
                   new_kind, scratch_pool);
 
-  SVN_ERR(mark_tree_conflict(move_src_root_relpath,
-                             wcroot, db, old_version, new_version,
-                             move_dst_op_root_relpath,
-                             svn_wc_operation_update,
-                             old_kind, new_kind,
-                             old_repos_relpath,
-                             svn_wc_conflict_reason_moved_away,
-                             svn_wc_conflict_action_edit,
-                             move_src_op_root_relpath,
-                             scratch_pool));
+  SVN_ERR(create_tree_conflict(&conflict, wcroot, move_src_root_relpath,
+                               move_dst_op_root_relpath,
+                               db, old_version, new_version,
+                               svn_wc_operation_update,
+                               old_kind, new_kind,
+                               old_repos_relpath,
+                               svn_wc_conflict_reason_moved_away,
+                               svn_wc_conflict_action_edit,
+                               move_src_op_root_relpath,
+                               scratch_pool, scratch_pool));
+
+  SVN_ERR(update_move_list_add(wcroot, move_src_root_relpath,
+                               svn_wc_notify_tree_conflict,
+                               new_kind,
+                               svn_wc_notify_state_inapplicable,
+                               svn_wc_notify_state_inapplicable,
+                               conflict, NULL, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2190,13 +2109,10 @@ bump_moved_layer(svn_boolean_t *recurse,
                  const char *local_relpath,
                  int op_depth,
                  const char *src_relpath,
-                 int src_op_depth,
-                 svn_node_kind_t src_kind,
+                 int src_del_depth,
                  svn_depth_t src_depth,
                  const char *dst_relpath,
-                 apr_hash_t *src_done,
                  svn_wc__db_t *db,
-                 apr_pool_t *result_pool,
                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
@@ -2204,8 +2120,6 @@ bump_moved_layer(svn_boolean_t *recurse,
   svn_skel_t *conflict;
   svn_boolean_t can_bump;
 
-  const char *src_root_relpath = src_relpath;
-
   SVN_ERR(verify_write_lock(wcroot, local_relpath, scratch_pool));
 
   *recurse = FALSE;
@@ -2214,7 +2128,7 @@ bump_moved_layer(svn_boolean_t *recurse,
                                     STMT_HAS_LAYER_BETWEEN));
 
   SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath,
-                            op_depth, src_op_depth));
+                            op_depth, src_del_depth));
 
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   SVN_ERR(svn_sqlite__reset(stmt));
@@ -2243,34 +2157,36 @@ bump_moved_layer(svn_boolean_t *recurse,
         can_bump = FALSE;
     }
 
-  if (!can_bump)
-    {
-      SVN_ERR(bump_mark_tree_conflict(wcroot, src_relpath,
-                                      src_root_relpath, dst_relpath,
-                                      db, scratch_pool));
-
-      return SVN_NO_ERROR;
-    }
-
-  while (relpath_depth(src_root_relpath) > src_op_depth)
-    src_root_relpath = svn_relpath_dirname(src_root_relpath, scratch_pool);
-
-
-  if (svn_hash_gets(src_done, src_relpath))
-    return SVN_NO_ERROR;
-
-  svn_hash_sets(src_done, apr_pstrdup(result_pool, src_relpath), "");
-
-  SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, wcroot,
-                                            src_root_relpath,
-                                            scratch_pool, scratch_pool));
+  {
+    const char *src_root_relpath = src_relpath;
+    while (relpath_depth(src_root_relpath) > src_del_depth)
+      src_root_relpath = svn_relpath_dirname(src_root_relpath, scratch_pool);
+
+    if (!can_bump)
+      {
+        SVN_ERR(bump_mark_tree_conflict(wcroot, src_relpath,
+                                        src_root_relpath, dst_relpath,
+                                        db, scratch_pool));
+
+        return SVN_NO_ERROR;
+      }
+
+    SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, wcroot,
+                                              src_root_relpath,
+                                              scratch_pool, scratch_pool));
+  }
 
   /* ### TODO: check this is the right sort of tree-conflict? */
   if (!conflict)
     {
       /* ### TODO: verify moved_here? */
-      SVN_ERR(replace_moved_layer(src_relpath, dst_relpath,
-                                 op_depth, wcroot, scratch_pool));
+
+      SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
+
+      SVN_ERR(svn_wc__db_op_copy_layer_internal(wcroot,
+                                                src_relpath, op_depth,
+                                                dst_relpath, NULL, NULL,
+                                                scratch_pool));
 
       *recurse = TRUE;
     }
@@ -2278,28 +2194,34 @@ bump_moved_layer(svn_boolean_t *recurse,
   return SVN_NO_ERROR;
 }
 
+/* Internal storage for bump_moved_away() */
+struct bump_pair_t
+{
+  const char *src_relpath;
+  const char *dst_relpath;
+  int src_del_op_depth;
+  svn_node_kind_t src_kind;
+};
 
 /* Bump moves of LOCAL_RELPATH and all its descendants that were
    originally below LOCAL_RELPATH at op-depth OP_DEPTH.
-
-   SRC_DONE is a hash with keys that are 'const char *' relpaths
-   that have already been bumped.  Any bumped paths are added to
-   SRC_DONE. */
+ */
 static svn_error_t *
 bump_moved_away(svn_wc__db_wcroot_t *wcroot,
                 const char *local_relpath,
                 int op_depth,
-                apr_hash_t *src_done,
                 svn_depth_t depth,
                 svn_wc__db_t *db,
-                apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   apr_pool_t *iterpool;
-  svn_error_t *err = NULL;
+  int i;
+  apr_array_header_t *pairs = apr_array_make(scratch_pool, 32,
+                                             sizeof(struct bump_pair_t*));
 
+  /* Build an array, as we can't execute the same Sqlite query recursively */
   iterpool = svn_pool_create(scratch_pool);
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -2309,51 +2231,52 @@ bump_moved_away(svn_wc__db_wcroot_t *wcr
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while(have_row)
     {
-      const char *src_relpath, *dst_relpath;
-      int src_op_depth;
-      svn_node_kind_t src_kind;
-      svn_depth_t src_depth;
+      struct bump_pair_t *bp = apr_pcalloc(scratch_pool, sizeof(*bp));
+
+      bp->src_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+      bp->dst_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
+      bp->src_del_op_depth = svn_sqlite__column_int(stmt, 2);
+      bp->src_kind = svn_sqlite__column_token(stmt, 3, kind_map);
+
+      APR_ARRAY_PUSH(pairs, struct bump_pair_t *) = bp;
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  for (i = 0; i < pairs->nelts; i++)
+    {
+      struct bump_pair_t *bp = APR_ARRAY_IDX(pairs, i, struct bump_pair_t *);
       svn_boolean_t skip;
+      svn_depth_t src_wc_depth;
 
       svn_pool_clear(iterpool);
 
-      src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
-      dst_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
-      src_op_depth = svn_sqlite__column_int(stmt, 2);
-      src_kind = svn_sqlite__column_token(stmt, 3, kind_map);
-
-      err = check_bump_layer(&skip, &src_depth, local_relpath, depth,
-          src_relpath, src_kind, iterpool);
 
-      if (err)
-        break;
+      SVN_ERR(check_bump_layer(&skip, &src_wc_depth, local_relpath, depth,
+                               bp->src_relpath, bp->src_kind, iterpool));
 
       if (!skip)
         {
           svn_boolean_t recurse;
 
-          err = bump_moved_layer(&recurse, wcroot,
-                                 local_relpath, op_depth,
-                                 src_relpath, src_op_depth, src_kind, src_depth,
-                                 dst_relpath,
-                                 src_done, db, result_pool, iterpool);
-
-          if (!err && recurse)
-            err = bump_moved_away(wcroot, dst_relpath, relpath_depth(dst_relpath),
-                                  src_done, depth, db, result_pool, iterpool);
+          SVN_ERR(bump_moved_layer(&recurse, wcroot,
+                                   local_relpath, op_depth,
+                                   bp->src_relpath, bp->src_del_op_depth,
+                                   src_wc_depth, bp->dst_relpath,
+                                   db, iterpool));
+
+          if (recurse)
+            SVN_ERR(bump_moved_away(wcroot, bp->dst_relpath,
+                                    relpath_depth(bp->dst_relpath),
+                                    depth, db, iterpool));
         }
-
-      if (err)
-        break;
-
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
 
-  err = svn_error_compose_create(err, svn_sqlite__reset(stmt));
-
   svn_pool_destroy(iterpool);
 
-  return svn_error_trace(err);
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -2363,8 +2286,6 @@ svn_wc__db_bump_moved_away(svn_wc__db_wc
                            svn_wc__db_t *db,
                            apr_pool_t *scratch_pool)
 {
-  apr_hash_t *src_done;
-
   SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
                                       STMT_CREATE_UPDATE_MOVE_LIST));
 
@@ -2409,9 +2330,7 @@ svn_wc__db_bump_moved_away(svn_wc__db_wc
         }
     }
 
-  src_done = apr_hash_make(scratch_pool);
-  SVN_ERR(bump_moved_away(wcroot, local_relpath, 0, src_done, depth, db,
-                          scratch_pool, scratch_pool));
+  SVN_ERR(bump_moved_away(wcroot, local_relpath, 0, depth, db, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2445,19 +2364,27 @@ resolve_delete_raise_moved_away(svn_wc__
       svn_node_kind_t src_kind = svn_sqlite__column_token(stmt, 1, kind_map);
       const char *dst_relpath = svn_sqlite__column_text(stmt, 2, NULL);
       const char *src_repos_relpath = svn_sqlite__column_text(stmt, 3, NULL);
+      svn_skel_t *conflict;
       svn_pool_clear(iterpool);
 
       SVN_ERR_ASSERT(src_repos_relpath != NULL);
 
-      err = mark_tree_conflict(src_relpath,
-                               wcroot, db, old_version, new_version,
-                               dst_relpath, operation,
-                               src_kind /* ### old kind */,
-                               src_kind /* ### new kind */,
-                               src_repos_relpath,
-                               svn_wc_conflict_reason_moved_away,
-                               action, local_relpath,
-                               iterpool);
+      err = create_tree_conflict(&conflict, wcroot, src_relpath, dst_relpath,
+                                 db, old_version, new_version, operation,
+                                 src_kind /* ### old kind */,
+                                 src_kind /* ### new kind */,
+                                 src_repos_relpath,
+                                 svn_wc_conflict_reason_moved_away,
+                                 action, local_relpath,
+                                 iterpool, iterpool);
+
+      if (!err)
+        err = update_move_list_add(wcroot, src_relpath,
+                                   svn_wc_notify_tree_conflict,
+                                   src_kind,
+                                   svn_wc_notify_state_inapplicable,
+                                   svn_wc_notify_state_inapplicable,
+                                   conflict, NULL, scratch_pool);
 
       if (err)
         return svn_error_compose_create(err, svn_sqlite__reset(stmt));
@@ -2605,7 +2532,8 @@ break_moved_away_children_internal(svn_w
                                      svn_wc_notify_move_broken,
                                      svn_node_unknown,
                                      svn_wc_notify_state_inapplicable,
-                                     svn_wc_notify_state_inapplicable);
+                                     svn_wc_notify_state_inapplicable,
+                                     NULL, NULL, scratch_pool);
         }
 
       if (err)

Modified: subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c (original)
+++ subversion/branches/reuse-ra-session/subversion/svn/conflict-callbacks.c Fri Feb  6 20:18:23 2015
@@ -792,7 +792,7 @@ handle_text_conflict(svn_wc_conflict_res
       else if (strcmp(opt->code, "df") == 0)
         {
           /* Re-check preconditions. */
-          if (! diff_allowed || desc->my_abspath)
+          if (! diff_allowed || ! desc->my_abspath)
             {
               SVN_ERR(svn_cmdline_fprintf(stderr, iterpool,
                              _("Invalid option; there's no "

Modified: subversion/branches/reuse-ra-session/subversion/svn/notify.c
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/svn/notify.c?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/svn/notify.c (original)
+++ subversion/branches/reuse-ra-session/subversion/svn/notify.c Fri Feb  6 20:18:23 2015
@@ -52,7 +52,7 @@ struct notify_baton
   svn_boolean_t is_export;
   svn_boolean_t is_wc_to_repos_copy;
   svn_boolean_t sent_first_txdelta;
-  svn_boolean_t in_external;
+  int in_external;
   svn_boolean_t had_print_error; /* Used to not keep printing error messages
                                     when we've already had one print error. */
 
@@ -636,7 +636,7 @@ notify_body(struct notify_baton *nb,
 
     case svn_wc_notify_update_external:
       /* Remember that we're now "inside" an externals definition. */
-      nb->in_external = TRUE;
+      ++nb->in_external;
 
       /* Currently this is used for checkouts and switches too.  If we
          want different output, we'll have to add new actions. */
@@ -653,7 +653,7 @@ notify_body(struct notify_baton *nb,
       if (nb->in_external)
         {
           svn_handle_warning2(stderr, n->err, "svn: ");
-          nb->in_external = FALSE;
+          --nb->in_external;
           SVN_ERR(svn_cmdline_printf(pool, "\n"));
         }
       /* Otherwise, we'll just print two warnings.  Why?  Because
@@ -752,7 +752,7 @@ notify_body(struct notify_baton *nb,
 
       if (nb->in_external)
         {
-          nb->in_external = FALSE;
+          --nb->in_external;
           SVN_ERR(svn_cmdline_printf(pool, "\n"));
         }
       break;
@@ -1117,7 +1117,7 @@ svn_cl__get_notifier(svn_wc_notify_func2
   nb->is_checkout = FALSE;
   nb->is_export = FALSE;
   nb->is_wc_to_repos_copy = FALSE;
-  nb->in_external = FALSE;
+  nb->in_external = 0;
   nb->had_print_error = FALSE;
   nb->conflict_stats = conflict_stats;
   SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));

Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/externals_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/externals_tests.py?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/externals_tests.py Fri Feb  6 20:18:23 2015
@@ -3547,6 +3547,43 @@ def replace_tree_with_foreign_external(s
                                         None, None, None, None, None, 1,
                                         '-r', '2', wc_dir)
 
+def nested_notification(sbox):
+  "notification for nested externals"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  repo_dir = sbox.repo_dir
+
+  sbox.simple_mkdir('D1')
+  sbox.simple_mkdir('D2')
+  sbox.simple_mkdir('D3')
+  sbox.simple_mkdir('D4')
+  sbox.simple_propset('svn:externals', '^/D2 X', 'D1')
+  sbox.simple_propset('svn:externals', '^/D3 X', 'D2')
+  sbox.simple_propset('svn:externals', '^/D4 X', 'D3')
+  sbox.simple_commit()
+  expected_output = [
+    'Updating \'' + sbox.ospath('D1') + '\':\n',
+    '\n',
+    'Fetching external item into \'' + sbox.ospath('D1/X') + '\':\n',
+    ' U   ' + sbox.ospath('D1/X') + '\n',
+    '\n',
+    'Fetching external item into \'' + sbox.ospath('D1/X/X') + '\':\n',
+    ' U   ' + sbox.ospath('D1/X/X') + '\n',
+    '\n',
+    'Fetching external item into \'' + sbox.ospath('D1/X/X/X') + '\':\n',
+    'Updated external to revision 2.\n',
+    '\n',
+    'External at revision 2.\n',
+    '\n',
+    'External at revision 2.\n',
+    '\n',
+    'At revision 2.\n'
+    ]
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'update', sbox.ospath('D1'))
+
+
 ########################################################################
 # Run the tests
 
@@ -3607,6 +3644,7 @@ test_list = [ None,
               switch_relative_externals,
               copy_file_external_to_repo,
               replace_tree_with_foreign_external,
+              nested_notification,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/info_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/info_tests.py?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/tests/cmdline/info_tests.py (original)
+++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/info_tests.py Fri Feb  6 20:18:23 2015
@@ -208,7 +208,7 @@ def info_with_tree_conflicts(sbox):
 def info_on_added_file(sbox):
   """info on added file"""
 
-  svntest.actions.make_repo_and_wc(sbox)
+  sbox.build()
   wc_dir = sbox.wc_dir
 
   # create new file
@@ -251,7 +251,7 @@ def info_on_added_file(sbox):
 
 def info_on_mkdir(sbox):
   """info on new dir with mkdir"""
-  svntest.actions.make_repo_and_wc(sbox)
+  sbox.build()
   wc_dir = sbox.wc_dir
 
   # create a new directory using svn mkdir

Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/log_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/log_tests.py?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/log_tests.py Fri Feb  6 20:18:23 2015
@@ -227,12 +227,7 @@ def merge_history_repos(sbox):
   branch_c = os.path.join('branches', 'c')
 
   # Create an empty repository - r0
-  svntest.main.safe_rmtree(sbox.repo_dir, 1)
-  svntest.main.safe_rmtree(sbox.wc_dir, 1)
-  svntest.main.create_repos(sbox.repo_dir)
-
-  svntest.actions.run_and_verify_svn(None, None, [], "co", sbox.repo_url,
-                                     sbox.wc_dir)
+  sbox.build(empty=True)
   was_cwd = os.getcwd()
   os.chdir(sbox.wc_dir)
 
@@ -751,8 +746,7 @@ def log_with_empty_repos(sbox):
   "'svn log' on an empty repository"
 
   # Create virgin repos
-  svntest.main.safe_rmtree(sbox.repo_dir, 1)
-  svntest.main.create_repos(sbox.repo_dir)
+  sbox.build(create_wc=False, empty=True)
 
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'log',

Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py (original)
+++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/move_tests.py Fri Feb  6 20:18:23 2015
@@ -1241,10 +1241,10 @@ def move_missing(sbox):
 def nested_replaces(sbox):
   "nested replaces"
 
-  repo_dir, repo_url = sbox.add_repo_path('blank')
-  wc_dir = sbox.add_wc_path('blank')
-  svntest.main.create_repos(repo_dir)
-  ospath = lambda dirent: sbox.ospath(dirent, wc_dir)
+  sbox.build(create_wc=False, empty=True)
+  repo_url = sbox.repo_url
+  wc_dir = sbox.wc_dir
+  ospath = sbox.ospath
 
   ## r1: setup
   svntest.actions.run_and_verify_svnmucc(None, None, [],

Modified: subversion/branches/reuse-ra-session/subversion/tests/cmdline/schedule_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/tests/cmdline/schedule_tests.py?rev=1657947&r1=1657946&r2=1657947&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/tests/cmdline/schedule_tests.py (original)
+++ subversion/branches/reuse-ra-session/subversion/tests/cmdline/schedule_tests.py Fri Feb  6 20:18:23 2015
@@ -569,10 +569,9 @@ def status_add_deleted_directory(sbox):
 def add_recursive_already_versioned(sbox):
   "'svn add' should traverse already-versioned dirs"
 
+  sbox.build()
   wc_dir = sbox.wc_dir
 
-  svntest.actions.make_repo_and_wc(sbox)
-
   # Create some files, then schedule them for addition
   delta_path = sbox.ospath('delta')
   zeta_path = sbox.ospath('A/B/zeta')



Mime
View raw message