Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h	(revision 15336)
+++ subversion/include/svn_client.h	(working copy)
@@ -687,11 +687,28 @@
  * this function can use to query for a commit log message when one is
  * needed.
  *
- * If @a ctx->notify_func2 is non-null, when the directory has been created
+ * If @a parents is TRUE, create parent directories.
+ *
+ * If @a ctx->notify_func is non-null, when the directory has been created
  * (successfully) in the working copy, call @a ctx->notify_func2 with
  * @a ctx->notify_baton2 and the path of the new directory.  Note that this is
- * only called for items added to the working copy.  */
+ * only called for items added to the working copy.  
+ *
+ * @since New in 1.3.
+ */
 svn_error_t *
+svn_client_mkdir2 (svn_client_commit_info_t **commit_info,
+                   const apr_array_header_t *paths,
+                   svn_boolean_t parents,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool);
+
+/** Similar to svn_client_mkdir2(), but with the @a parents parameter always
+ *  always set to @c FALSE. 
+ *
+ *  @deprecated Provided for backwards compatibility with the 1.2 API.
+ */
+svn_error_t *
 svn_client_mkdir (svn_client_commit_info_t **commit_info,
                   const apr_array_header_t *paths,
                   svn_client_ctx_t *ctx,
@@ -1371,6 +1388,8 @@
  * until a commit occurs.  This scheduling can be removed with
  * svn_client_revert().
  *
+ * If @a parents is TRUE, create parent directories.
+ *
  * @a ctx->log_msg_func/@a ctx->log_msg_baton are a callback/baton combo that
  * this function can use to query for a commit log message when one is
  * needed.
@@ -1378,8 +1397,25 @@
  * If @a ctx->notify_func2 is non-null, invoke it with @a ctx->notify_baton2
  * for each item added at the new location, passing the new, relative path of
  * the added item.
+ *
+ * @since New in 1.3.
  */
 svn_error_t *
+svn_client_copy2 (svn_client_commit_info_t **commit_info,
+                  const char *src_path,
+                  const svn_opt_revision_t *src_revision,
+                  const char *dst_path,
+                  svn_boolean_t parents,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool);
+
+/**
+ * Similar to svn_client_copy2(), but with the @a parents parameter 
+ * always set to @c FALSE.
+ *
+ * @deprecated Provided for backwards compatibility with the 1.2 API.
+ */
+svn_error_t *
 svn_client_copy (svn_client_commit_info_t **commit_info,
                  const char *src_path,
                  const svn_opt_revision_t *src_revision,
@@ -1421,6 +1457,8 @@
  *     and @a force is not set, the copy will fail. If @a force is set such 
  *     items will be removed.
  *
+ * If @a parents is TRUE create parent directories.
+ *
  * @a ctx->log_msg_func/@a ctx->log_msg_baton are a callback/baton combo that
  * this function can use to query for a commit log message when one is needed.
  *
@@ -1431,9 +1469,25 @@
  *
  * ### Is this really true?  What about svn_wc_notify_commit_replaced()? ###
  *
- * @since New in 1.2.
+ * @since New in 1.3.
  */ 
 svn_error_t *
+svn_client_move3 (svn_client_commit_info_t **commit_info,
+                  const char *src_path,
+                  const char *dst_path,
+                  svn_boolean_t force,
+                  svn_boolean_t parents,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool);
+
+/**
+ * Similar to @c svn_client_copy3, but with the @a parents parameter always
+ * set to @c FALSE.
+ *
+ * @deprecated Provided for backwards compatibility with the 1.2 API.
+ */
+
+svn_error_t *
 svn_client_move2 (svn_client_commit_info_t **commit_info,
                   const char *src_path,
                   const char *dst_path,
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h	(revision 15336)
+++ subversion/libsvn_client/client.h	(working copy)
@@ -636,6 +636,33 @@
                                 svn_client_ctx_t *ctx,
                                 apr_pool_t *pool);
 
+/* Create and add working copy directories, including parent directories if 
+   needed. Setting parents to TRUE results in parent directories getting
+   created.  */
+svn_error_t *
+svn_client__mksubdir (const char *path,
+                      svn_boolean_t parents,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *pool);
+
+/* Return the non-existent url path components and the existing url path */
+svn_error_t *
+svn_client__url_new_paths (const char **existing_url,
+                           apr_array_header_t **new_paths,
+                           svn_ra_session_t **ra_session,
+                           svn_revnum_t *latest_rev,
+                           const svn_delta_editor_t **editor,
+                           void **edit_baton,
+                           svn_client_ctx_t *ctx,
+                           const char *url,
+                           const char *base_dir,
+                           svn_wc_adm_access_t *base_access,
+                           const char *log_msg,
+                           apr_array_header_t *commit_items,
+                           svn_client_commit_info_t **commit_info,
+                           svn_boolean_t is_commit,
+                           apr_pool_t *pool);
+
 
 #ifdef __cplusplus
 }
Index: subversion/libsvn_client/copy.c
===================================================================
--- subversion/libsvn_client/copy.c	(revision 15336)
+++ subversion/libsvn_client/copy.c	(working copy)
@@ -66,6 +66,7 @@
                const char *dst_path,
                svn_boolean_t is_move,
                svn_boolean_t force,
+               svn_boolean_t parents,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
 {
@@ -81,6 +82,17 @@
                               _("Path '%s' does not exist"),
                               svn_path_local_style (src_path, pool));
 
+  /* If parents if TRUE create intermediate directories */
+  if (parents)
+    {
+      /* Make sure that the dst does not exist */
+      SVN_ERR(svn_io_check_path(dst_path, &dst_kind, pool));
+      if (dst_kind == svn_node_none)
+        {
+          SVN_ERR(svn_client__mksubdir(dst_path,TRUE,ctx,pool));
+        }
+    }
+
   /* If DST_PATH does not exist, then its basename will become a new
      file or dir added to its parent (possibly an implicit '.').  If
      DST_PATH is a dir, then SRC_PATH's basename will become a new
@@ -271,10 +283,129 @@
 
 
 static svn_error_t *
+repos_to_repos_p_copy (const svn_delta_editor_t *editor,
+                       void *edit_baton,
+                       apr_array_header_t *parent_dirs,
+                       struct path_driver_cb_baton *cb_baton,
+                       apr_pool_t *pool)
+{
+  int i;
+  void *root_baton;
+  apr_array_header_t *batons = NULL;
+  int num_batons;
+  void *file_baton;
+  int num_dirs; /* num of intermediate dirs to open */
+  apr_array_header_t *dirs_to_open;
+  const char *first_path;
+  void *dir_baton;
+  void *parent_baton;
+   
+  first_path = APR_ARRAY_IDX (parent_dirs, 0, const char*);
+  num_dirs = svn_path_component_count (first_path) - 1;
+  
+  dirs_to_open = svn_path_decompose (first_path, pool);
+
+  if (cb_baton->src_kind == svn_node_dir)
+    num_batons = parent_dirs->nelts + num_dirs + 1; 
+  else
+    num_batons = parent_dirs->nelts + num_dirs;
+
+  batons = apr_array_make (pool, num_batons, sizeof (void *));
+
+  SVN_ERR (editor->open_root (edit_baton, SVN_INVALID_REVNUM,
+                              pool, &root_baton));
+
+  *((void **) apr_array_push (batons)) = root_baton;
+
+  /* Open the intermediate directories */
+  if (num_dirs)
+    {
+      const char *edit_path = "", *dir;
+
+      parent_baton = root_baton;
+
+      for (i = 0; i < num_dirs; i++)
+        {
+          dir = APR_ARRAY_IDX (dirs_to_open, i, const char *);
+          edit_path = svn_path_join (edit_path, dir, pool);
+          editor->open_directory (edit_path, parent_baton, SVN_INVALID_REVNUM,
+                                  pool, &dir_baton);
+          *((void **) apr_array_push (batons)) = dir_baton;
+          parent_baton = dir_baton;
+
+        }
+    }
+  else
+    {
+      parent_baton = root_baton;
+    }
+
+  /* create the parent directories */
+  for (i = 0; i < parent_dirs->nelts; i++)
+    {
+      const char *component = APR_ARRAY_IDX (parent_dirs, i, const char *);
+
+      SVN_ERR (editor->add_directory (component, parent_baton, NULL, 
+                                      SVN_INVALID_REVNUM, pool, &dir_baton));
+      *((void **) apr_array_push (batons)) = dir_baton;
+      parent_baton = dir_baton;
+    }
+  /* copy target files/directories */
+  if (cb_baton->src_kind == svn_node_file)
+    {
+      const char *bname, *dst_file;
+
+      bname = svn_path_uri_decode (svn_path_basename (cb_baton->src_url, 
+                                                      pool), pool);
+      dst_file = svn_path_join (APR_ARRAY_IDX (parent_dirs, 
+                                               parent_dirs->nelts - 1,
+                                               const char *), bname, pool);
+      SVN_ERR (editor->add_file (dst_file, dir_baton, cb_baton->src_url,
+                                 cb_baton->src_revnum, pool, &file_baton));
+      SVN_ERR (editor->close_file (file_baton, NULL, pool));
+
+    }
+  else if (cb_baton->src_kind == svn_node_dir)
+    {
+      const char *bname, *dst_dir;
+
+      bname = svn_path_uri_decode (svn_path_basename (cb_baton->src_url,
+                                                      pool), pool);
+      dst_dir = svn_path_join (APR_ARRAY_IDX (parent_dirs,
+                                              parent_dirs->nelts - 1,
+                                              const char *), bname, pool);
+      SVN_ERR (editor->add_directory (dst_dir, dir_baton, cb_baton->src_url,
+                                      cb_baton->src_revnum, pool, 
+                                      &dir_baton));
+      *((void **) apr_array_push (batons)) = dir_baton; 
+   }
+
+  if (cb_baton->is_move)
+    {
+      SVN_ERR (editor->delete_entry (cb_baton->src_path, SVN_INVALID_REVNUM,
+                                               root_baton, pool));
+    }
+  
+  if (batons && batons->nelts)
+    {
+      void **baton;
+
+      while ((baton = (void **) apr_array_pop (batons)))
+        {
+          SVN_ERR (editor->close_directory (*baton, pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
 repos_to_repos_copy (svn_client_commit_info_t **commit_info,
                      const char *src_url, 
                      const svn_opt_revision_t *src_revision, 
                      const char *dst_url, 
+                     svn_boolean_t parents,
                      svn_client_ctx_t *ctx,
                      svn_boolean_t is_move,
                      apr_pool_t *pool)
@@ -291,6 +422,12 @@
   svn_boolean_t resurrection = FALSE;
   struct path_driver_cb_baton cb_baton;
   svn_error_t *err;
+  const char *existing_url;
+  apr_array_header_t *parent_dirs;
+  int i;
+  svn_boolean_t make_parent_dirs = FALSE; /* check if parent dirs are really
+                                             needed */
+  const char *path_prefix;
 
   /* We have to open our session to the longest path common to both
      SRC_URL and DST_URL in the repository so we can do existence
@@ -327,6 +464,24 @@
     return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                               _("Cannot move URL '%s' into itself"), src_url);
 
+  if (parents)
+    {
+      SVN_ERR (svn_client__url_new_paths (&existing_url, &parent_dirs,
+                                          &ra_session, NULL, &editor,
+                                          &edit_baton, ctx, dst_url, NULL,
+                                          NULL, "", NULL, commit_info,
+                                          FALSE, pool));
+
+      /* Check for existing url */
+      if (parent_dirs->nelts)
+        {
+          make_parent_dirs = TRUE;
+          path_prefix = svn_path_is_child(top_url, existing_url, pool);
+        }
+      if ((path_prefix == NULL) || (!parent_dirs->nelts))
+        path_prefix = "";
+    }
+
   /* Open an RA session for the URL. Note that we don't have a local
      directory, nor a place to put temp files. */
   err = svn_client__open_ra_session_internal (&ra_session, top_url,
@@ -385,52 +540,87 @@
        _("Path '%s' does not exist in revision %ld"),
        src_url, src_revnum);
 
-  /* Figure out the basename that will result from this operation. */
-  SVN_ERR (svn_ra_check_path (ra_session, dst_rel, youngest, &dst_kind, pool));
-  if (dst_kind == svn_node_none)
+
+  if (!make_parent_dirs)
     {
-      /* do nothing */
-    }
-  else if (dst_kind == svn_node_file)
-    {
-      /* We disallow the overwriting of files. */
-      return svn_error_createf (SVN_ERR_FS_ALREADY_EXISTS, NULL,
-                                _("Path '%s' already exists"), dst_rel);
-    }
-  else if (dst_kind == svn_node_dir)
-    {
-      /* As a matter of client-side policy, we prevent overwriting any
-         pre-existing directory.  So we append src_url's basename to
-         dst_rel, and see if that already exists.  */
-      svn_node_kind_t attempt_kind;
-      const char *bname;
+      /* Figure out the basename that will result from this operation. */
+      SVN_ERR (svn_ra_check_path (ra_session, dst_rel, youngest, &dst_kind, 
+                                  pool));
 
-      bname = svn_path_uri_decode (svn_path_basename (src_url, pool), pool);
-      dst_rel = svn_path_join (dst_rel, bname, pool);
-      SVN_ERR (svn_ra_check_path (ra_session, dst_rel, youngest,
-                                  &attempt_kind, pool));
-      if (attempt_kind != svn_node_none)
-        return svn_error_createf (SVN_ERR_FS_ALREADY_EXISTS, NULL,
-                                  _("Path '%s' already exists"), dst_rel);
+      if (dst_kind == svn_node_none)
+        {
+          /* do nothing */
+        }
+      else if (dst_kind == svn_node_file)
+        {
+          /* We disallow the overwriting of files. */
+          return svn_error_createf (SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                                    _("Path '%s' already exists"), dst_rel);
+        }
+      else if (dst_kind == svn_node_dir)
+        {
+          /* As a matter of client-side policy, we prevent overwriting any
+          pre-existing directory.  So we append src_url's basename to
+          dst_rel, and see if that already exists.  */
+          svn_node_kind_t attempt_kind;
+          const char *bname;
+
+          bname = svn_path_uri_decode (svn_path_basename (src_url, pool), 
+                                                          pool);
+          dst_rel = svn_path_join (dst_rel, bname, pool);
+          SVN_ERR (svn_ra_check_path (ra_session, dst_rel, youngest,
+                                      &attempt_kind, pool));
+          if (attempt_kind != svn_node_none)
+            return svn_error_createf (SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                                      _("Path '%s' already exists"), dst_rel);
+        }
+      else
+        {
+          return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
+                                    _("Unrecognized node kind of '%s'"), 
+                                    dst_url);
+        }
     }
-  else
-    {
-      return svn_error_createf (SVN_ERR_NODE_UNKNOWN_KIND, NULL,
-                                _("Unrecognized node kind of '%s'"), dst_url);
-    }
-
   /* Create a new commit item and add it to the array. */
   if (ctx->log_msg_func)
     {
       svn_client_commit_item_t *item;
       const char *tmp_file;
-      apr_array_header_t *commit_items 
-        = apr_array_make (pool, 2, sizeof (item));
+      apr_array_header_t *commit_items = apr_array_make (pool, 1,
+                                                 sizeof (const char *));;
       
-      item = apr_pcalloc (pool, sizeof (*item));
-      item->url = svn_path_join (top_url, dst_rel, pool);
-      item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
-      (*((svn_client_commit_item_t **) apr_array_push (commit_items))) = item;
+      if (!make_parent_dirs)
+        {
+          item = apr_pcalloc (pool, sizeof (*item));
+          item->url = svn_path_join (top_url, dst_rel, pool);
+          item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
+          (*((svn_client_commit_item_t **) apr_array_push (commit_items))) = 
+                                                                         item;
+        }
+       else if (make_parent_dirs)
+        {
+          const char *temp_path;
+          const char *bname;
+          bname = svn_path_uri_decode (svn_path_basename (src_url, pool),
+                                                          pool);
+
+          temp_path = existing_url;
+          for (i = 0; i < (parent_dirs->nelts + 1); i++)
+            {
+              const char *path = APR_ARRAY_IDX (parent_dirs, i,
+                                                const char *);
+              item = apr_pcalloc (pool, sizeof (*item));
+              
+              if (i == parent_dirs->nelts)
+                item->url = svn_path_join (dst_url, bname, pool);
+              else
+                item->url = svn_path_join (temp_path, path, pool);
+              item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
+              APR_ARRAY_PUSH (commit_items, svn_client_commit_item_t *) = 
+                                                                        item;
+              temp_path = item->url;
+            }
+        }
       if (is_move && (! resurrection))
         {
           item = apr_pcalloc (pool, sizeof (*item));
@@ -449,43 +639,76 @@
 
 
   /* Fetch RA commit editor. */
-  SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool));
-  SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, message,
-                                     svn_client__commit_callback,
+  SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, 
+                                         pool));
+  SVN_ERR (svn_ra_get_commit_editor (ra_session, &editor, &edit_baton, 
+                                     message, svn_client__commit_callback,
                                      commit_baton, 
                                      NULL, TRUE, /* No lock tokens */
                                      pool));
 
   /* Setup our PATHS for the path-based editor drive. */
-  APR_ARRAY_PUSH (paths, const char *) = dst_rel;
-  if (is_move && (! resurrection))
+  if (!make_parent_dirs)
+    APR_ARRAY_PUSH (paths, const char *) = dst_rel;
+  else if (make_parent_dirs)
+    {
+      const char *temp="";
+
+      for (i=0; i< parent_dirs->nelts; i++)
+        {
+          temp = svn_path_join (path_prefix, APR_ARRAY_IDX (parent_dirs, i, 
+                                const char *), pool); 
+          APR_ARRAY_PUSH (paths, const char *) = temp;
+          path_prefix = temp;
+        }  
+    }
+  if (is_move && (! resurrection) && (!make_parent_dirs))
     APR_ARRAY_PUSH (paths, const char *) = src_rel;
 
-  /* Setup the callback baton. */
-  cb_baton.editor = editor;
-  cb_baton.edit_baton = edit_baton;
-  cb_baton.src_kind = src_kind;
-  cb_baton.src_url = src_url;
-  cb_baton.src_path = src_rel;
-  cb_baton.dst_path = dst_rel;
-  cb_baton.is_move = is_move;
-  cb_baton.src_revnum = src_revnum;
-  cb_baton.resurrection = resurrection;
+    /* Setup the callback baton. */
+    cb_baton.editor = editor;
+    cb_baton.edit_baton = edit_baton;
+    cb_baton.src_kind = src_kind;
+    cb_baton.src_url = src_url;
+    cb_baton.src_path = src_rel;
+    if (!make_parent_dirs)
+      cb_baton.dst_path = dst_rel;
+    cb_baton.is_move = is_move;
+    cb_baton.src_revnum = src_revnum;
+    cb_baton.resurrection = resurrection;
 
-  /* Call the path-based editor driver. */
-  err = svn_delta_path_driver (editor, edit_baton, youngest, paths,
-                               path_driver_cb_func, &cb_baton, pool);
-  if (err)
+  if (!make_parent_dirs)
     {
-      /* At least try to abort the edit (and fs txn) before throwing err. */
-      svn_error_clear (editor->abort_edit (edit_baton, pool));
-      return err;
+      /* Call the path-based editor driver. */
+      err = svn_delta_path_driver (editor, edit_baton, youngest, paths,
+                                   path_driver_cb_func, &cb_baton, pool);
+
+      if (err)
+        {
+          /* At least try to abort the edit (and fs txn) before 
+           throwing err. */
+          svn_error_clear (editor->abort_edit (edit_baton, pool));
+          return err;
+        }
+      }
+  else if (make_parent_dirs)
+    {
+      const char *bname;
+
+      bname = svn_path_uri_decode (svn_path_basename (src_url, pool),
+                                                          pool);
+      cb_baton.dst_path = svn_path_join (APR_ARRAY_IDX (paths, 
+                                                        parent_dirs->nelts - 1,
+                                                       const char *),
+                                                        bname, pool);
+      SVN_ERR (repos_to_repos_p_copy (editor, edit_baton, paths, 
+                                       &cb_baton, pool));
     }
 
-  /* Close the edit. */
-  SVN_ERR (editor->close_edit (edit_baton, pool));
+    /* Close the edit. */
+    SVN_ERR (editor->close_edit (edit_baton, pool));
 
-  return SVN_NO_ERROR;
+    return SVN_NO_ERROR;
 }
 
 
@@ -750,6 +973,7 @@
 repos_to_wc_copy (const char *src_url,
                   const svn_opt_revision_t *src_revision,
                   const char *dst_path, 
+                  svn_boolean_t parents,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
 {
@@ -816,6 +1040,14 @@
    * 2 under A.
    */
 
+  /* Create parent directories */
+  if (parents)
+    {
+      SVN_ERR (svn_io_check_path (dst_path, &dst_kind, pool));
+      if (dst_kind == svn_node_none)
+        SVN_ERR (svn_client__mksubdir (dst_path, TRUE, ctx, pool));
+    }
+
   /* First, figure out about dst. */
   SVN_ERR (svn_io_check_path (dst_path, &dst_kind, pool));
   if (dst_kind == svn_node_dir)
@@ -1012,6 +1244,7 @@
             const char *dst_path,
             svn_boolean_t is_move,
             svn_boolean_t force,
+            svn_boolean_t parents,
             svn_client_ctx_t *ctx,
             apr_pool_t *pool)
 {
@@ -1090,6 +1323,7 @@
     {
       SVN_ERR (wc_to_wc_copy (src_path, dst_path,
                               is_move, force,
+                              parents,
                               ctx,
                               pool));
     }
@@ -1101,13 +1335,13 @@
   else if ((src_is_url) && (! dst_is_url))
     {
       SVN_ERR (repos_to_wc_copy (src_path, src_revision, 
-                                 dst_path, ctx,
+                                 dst_path, parents, ctx,
                                  pool));
     }
   else
     {
       SVN_ERR (repos_to_repos_copy (commit_info, src_path, src_revision,
-                                    dst_path, ctx, is_move, pool));
+                                    dst_path, parents, ctx, is_move, pool));
     }
 
   return SVN_NO_ERROR;
@@ -1118,6 +1352,26 @@
 /* Public Interfaces */
 
 svn_error_t *
+svn_client_copy2 (svn_client_commit_info_t **commit_info,
+                  const char *src_path,
+                  const svn_opt_revision_t *src_revision,
+                  const char *dst_path,
+                  svn_boolean_t parents,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool)
+{
+  return setup_copy (commit_info, 
+                     src_path, src_revision, dst_path,
+                     FALSE /* is_move */,
+                     TRUE /* force, set to avoid deletion check */,
+                     parents,
+                     ctx,
+                     pool);
+}
+
+/* Public Interfaces */
+
+svn_error_t *
 svn_client_copy (svn_client_commit_info_t **commit_info,
                  const char *src_path,
                  const svn_opt_revision_t *src_revision,
@@ -1125,10 +1379,32 @@
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool)
 {
-  return setup_copy (commit_info, 
-                     src_path, src_revision, dst_path,
-                     FALSE /* is_move */,
-                     TRUE /* force, set to avoid deletion check */,
+   return svn_client_copy2 (commit_info,
+                            src_path,
+                            src_revision,
+                            dst_path,
+                            FALSE,
+                            ctx,
+                            pool);
+}
+
+svn_error_t *
+svn_client_move3 (svn_client_commit_info_t **commit_info,
+                  const char *src_path,
+                  const char *dst_path,
+                  svn_boolean_t force,
+                  svn_boolean_t parents,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool)
+{
+  const svn_opt_revision_t src_revision
+    = { svn_opt_revision_unspecified, { 0 } };
+
+  return setup_copy (commit_info,
+                     src_path, &src_revision, dst_path,
+                     TRUE /* is_move */,
+                     force,
+                     parents,
                      ctx,
                      pool);
 }
@@ -1149,6 +1425,7 @@
                      src_path, &src_revision, dst_path,
                      TRUE /* is_move */,
                      force,
+                     FALSE,
                      ctx,
                      pool);
 }
@@ -1181,6 +1458,7 @@
                      src_path, src_revision, dst_path,
                      TRUE /* is_move */,
                      force,
+                     FALSE,                     
                      ctx,
                      pool);
 }
Index: subversion/libsvn_client/add.c
===================================================================
--- subversion/libsvn_client/add.c	(revision 15336)
+++ subversion/libsvn_client/add.c	(working copy)
@@ -36,6 +36,7 @@
 #include "svn_props.h"
 #include "client.h"
 
+#include "svn_sorts.h"
 #include "svn_private_config.h"
 
 
@@ -492,10 +493,10 @@
                                 SVN_INVALID_REVNUM, pool, dir_baton);
 }
 
-
 static svn_error_t *
 mkdir_urls (svn_client_commit_info_t **commit_info,
             const apr_array_header_t *paths,
+            svn_boolean_t parents,
             svn_client_ctx_t *ctx,
             apr_pool_t *pool)
 {
@@ -509,40 +510,142 @@
   const char *common;
   int i;
 
-  /* Condense our list of mkdir targets. */
-  SVN_ERR (svn_path_condense_targets (&common, &targets, paths, FALSE, pool));
-  if (! targets->nelts)
+  if (parents)
     {
-      const char *bname;
-      svn_path_split (common, &common, &bname, pool);
-      APR_ARRAY_PUSH (targets, const char *) = bname;
-    }
-  else
-    {
-      svn_boolean_t resplit = FALSE;
+      /* Get the common base URL to which a session can be opened,
+         and the list of targets with which to drive the delta path
+         driver function. Users can specify multiple paths like,
+         svn mkdir -m "" --parents \    
+                        http://host/repos/branches/newdir/newdir2 \
+                        http://host/repos/tags/newdir/newdir2
+         Here the common url is http://host/repos, the path prefixes
+         are "branches", and "tags" and the targets are
+         branches/newdir, branches/newdir/newdir2, tags/newdir,
+         tags/newdir/newdir2 etc. The path prefixes need to be
+         determined since the same new directory names can be specified
+         with different paths as in the example above.
+      */
+      int j;
+      apr_array_header_t *urls = apr_array_make (pool, 1, 
+                                                 sizeof (const char *));
+      apr_array_header_t *new_paths = apr_array_make (pool, 1,
+                                                      sizeof (const char *));
+      apr_array_header_t *prefix;
+      apr_hash_t *targets_hash = apr_hash_make (pool);
+      apr_hash_index_t *hi; 
+      apr_hash_t *new_path_count =  apr_hash_make (pool); 
 
-      /* We can't "mkdir" the root of an editor drive, so if one of
-         our targets is the empty string, we need to back everything
-         up by a path component. */
-      for (i = 0; i < targets->nelts; i++)
+      for (i = 0; i < paths->nelts; i++)
         {
-          const char *path = APR_ARRAY_IDX (targets, i, const char *);
-          if (! *path)
+          const char *existing_path;   /* portion of the url that exists */
+          apr_array_header_t *new_entries;
+          const char *path = APR_ARRAY_IDX (paths, i, const char*);
+
+          SVN_ERR (svn_client__url_new_paths (&existing_path, &new_entries, 
+                                              &ra_session, NULL, &editor, 
+                                              &edit_baton, ctx, path, NULL, 
+                                              NULL, "", NULL, commit_info, 
+                                              FALSE, pool));
+          if (existing_path == path)
             {
-              resplit = TRUE;
-              break;
+              return svn_error_createf (SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                     _("URL '%s' already exists"), path);
             }
+          for (j = 0; j < new_entries->nelts; j++)
+            {
+              APR_ARRAY_PUSH (new_paths, const char *) = 
+                                APR_ARRAY_IDX (new_entries, j, const char*);
+            }
+          APR_ARRAY_PUSH (urls, const char *) = existing_path;
+          apr_hash_set (new_path_count, path, APR_HASH_KEY_STRING,
+                        (const int *)new_entries->nelts);
         }
-      if (resplit)
+
+      /* Find common url from list of valid urls; prefix is the array of
+         paths to be prefixed to targets
+       */
+      SVN_ERR (svn_path_condense_targets (&common, &prefix, urls, FALSE,
+                                          pool));
+
+      /* From list of new paths to be created, build the target paths */
+      for (i = 0; i < paths->nelts; i++)
         {
+          int npaths;
+          int n1, n2;
+          const char *target_prefix;
+          const char *target_path;
+
+          npaths = (int ) apr_hash_get (new_path_count,  
+                                        APR_ARRAY_IDX (paths, i, const char*),
+                                        APR_HASH_KEY_STRING);
+          n1 = (i == 0) ? 0 : n2;
+          n2 = (i == 0) ? npaths : (n2 + npaths);
+
+          if (prefix->nelts)
+            target_prefix = APR_ARRAY_IDX (prefix, i, const char *);
+          else if ((!prefix->nelts) || (svn_path_is_empty (APR_ARRAY_IDX
+                                        (prefix, i, const char *))))
+            target_prefix = "";
+
+          for (j = n1; j < n2 ; j++)
+            {
+              target_path = svn_path_join (target_prefix, APR_ARRAY_IDX(
+                                           new_paths, j, const char *),
+                                           pool); 
+              apr_hash_set (targets_hash, target_path, APR_HASH_KEY_STRING,
+                            (const char*)common);
+              target_prefix = target_path;
+            }
+        }
+
+      targets = apr_array_make (pool, 1, sizeof (const char *));
+
+      for (hi = apr_hash_first (pool, targets_hash); hi != NULL;
+           hi = apr_hash_next (hi))
+        {
+          const void *pname;
+          void *pval;
+
+          apr_hash_this (hi, &pname, NULL, &pval);
+          APR_ARRAY_PUSH (targets, const char *) = pname;
+        }
+      qsort (targets->elts, targets->nelts,
+             targets->elt_size, svn_sort_compare_paths);
+    }
+  else if (!parents)
+    { 
+      SVN_ERR (svn_path_condense_targets (&common, &targets, paths, 
+                                                FALSE, pool));
+      if (! targets->nelts)
+        {
           const char *bname;
           svn_path_split (common, &common, &bname, pool);
+          APR_ARRAY_PUSH (targets, const char *) = bname;
+        }
+      else
+        {
+          svn_boolean_t resplit = FALSE;
+
           for (i = 0; i < targets->nelts; i++)
             {
               const char *path = APR_ARRAY_IDX (targets, i, const char *);
-              path = svn_path_join (bname, path, pool);
-              APR_ARRAY_IDX (targets, i, const char *) = path;
+              if (! *path)
+                {
+                  resplit = TRUE;
+                  break;
+                }
             }
+          if (resplit)
+            {
+              const char *bname;
+              svn_path_split (common, &common, &bname, pool);
+              for (i = 0; i < targets->nelts; i++)
+                {
+                  const char *path = APR_ARRAY_IDX (targets, i, const char *);
+                  path = svn_path_join (bname, path, pool);
+                  APR_ARRAY_IDX (targets, i, const char *) = path;
+                }
+            }
         }
     }
 
@@ -616,43 +719,90 @@
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
 {
+  return svn_client_mkdir2 (commit_info, paths, FALSE, ctx, pool);
+}
+
+/** Make a directory and add it to the repository.
+  * If the parent directory doesn't exist, create it.
+  */
+
+svn_error_t *
+svn_client__mksubdir (const char *path,
+                      svn_boolean_t parents,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *pool)
+{
+  svn_error_t *err;
+  
+  /* if we're making parents as needed, we have to check for existence first */
+  if (parents)
+    {
+      const char *path_parent, *path_name;
+      svn_node_kind_t node_kind;
+
+      svn_path_split(path, &path_parent, &path_name, pool);
+
+      /* find out if the file exists */
+      SVN_ERR(svn_io_check_path(path_parent, &node_kind, pool));
+
+      if (node_kind == svn_node_none)
+        {
+          /* recurse to create parent */
+          SVN_ERR(svn_client__mksubdir(path_parent, TRUE,
+                                       ctx, pool));
+        }
+    }
+
+  SVN_ERR(svn_io_dir_make (path, APR_OS_DEFAULT, pool));
+  
+  err = svn_client_add3(path, FALSE, FALSE, FALSE, ctx, pool);
+  
+  /* We just created a new directory, but couldn't add it to
+     version control. Don't leave unversioned directoies behind. */
+  if (err)
+    {
+      /* ### If this returns an error, should we link it onto
+         err instead, so that the user is warned that we just
+         created an unversioned directory? */
+
+      svn_error_clear (svn_io_remove_dir (path, pool));
+    }
+
+  return err;
+}
+
+svn_error_t *
+svn_client_mkdir2 (svn_client_commit_info_t **commit_info,
+                   const apr_array_header_t *paths,
+                   svn_boolean_t parents,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
   if (! paths->nelts)
     return SVN_NO_ERROR;
   
   if (svn_path_is_url (APR_ARRAY_IDX (paths, 0, const char *)))
     {
-      SVN_ERR (mkdir_urls (commit_info, paths, ctx, pool));
+      SVN_ERR (mkdir_urls (commit_info, paths, parents, ctx, pool));
     }
   else
     {
       /* This is a regular "mkdir" + "svn add" */
       apr_pool_t *subpool = svn_pool_create (pool);
-      svn_error_t *err;
       int i;
 
       for (i = 0; i < paths->nelts; i++)
         {
           const char *path = APR_ARRAY_IDX (paths, i, const char *);
 
-          svn_pool_clear (subpool);
-
           /* See if the user wants us to stop. */
           if (ctx->cancel_func)
             SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
 
-          SVN_ERR (svn_io_dir_make (path, APR_OS_DEFAULT, subpool));
-          err = svn_client_add3 (path, FALSE, FALSE, FALSE, ctx, subpool);
+          SVN_ERR (svn_client__mksubdir (path, parents, 
+                                         ctx, subpool));
 
-          /* We just created a new directory, but couldn't add it to
-             version control. Don't leave unversioned directoies behind. */
-          if (err)
-            {
-              /* ### If this returns an error, should we link it onto
-                 err instead, so that the user is warned that we just
-                 created an unversioned directory? */
-              svn_error_clear (svn_io_remove_dir (path, subpool));
-              return err;
-            }
+          svn_pool_clear (subpool);
         }
       svn_pool_destroy (subpool);
     }
Index: subversion/libsvn_client/commit.c
===================================================================
--- subversion/libsvn_client/commit.c	(revision 15336)
+++ subversion/libsvn_client/commit.c	(working copy)
@@ -629,6 +629,82 @@
                                    pool);
 }
 
+svn_error_t *
+svn_client__url_new_paths (const char **existing_url,
+                           apr_array_header_t **new_paths,
+                           svn_ra_session_t **ra_session,
+                           svn_revnum_t *latest_rev,
+                           const svn_delta_editor_t **editor,
+                           void **edit_baton,
+                           svn_client_ctx_t *ctx,
+                           const char *url,
+                           const char *base_dir,
+                           svn_wc_adm_access_t *base_access,
+                           const char *log_msg,
+                           apr_array_header_t *commit_items,
+                           svn_client_commit_info_t **commit_info,
+                           svn_boolean_t is_commit,
+                           apr_pool_t *pool)
+
+{
+  const char *temp;
+  const char *dir;
+  svn_error_t *err = SVN_NO_ERROR;
+  int i, j;
+  const char *component;
+  apr_pool_t *subpool;
+
+  *new_paths = apr_array_make (pool, 4, sizeof (const char *));
+
+  subpool = svn_pool_create (pool);
+  do
+    {
+      svn_pool_clear (subpool);
+
+      /* See if the user is interested in cancelling this operation. */
+      if (ctx->cancel_func)
+        SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
+
+      if (err)
+        {
+          /* If get_ra_editor below failed we either tried to open
+             an invalid url, or else some other kind of error.  In case
+             the url was bad we back up a directory and try again. */
+          
+          if (err->apr_err != SVN_ERR_FS_NO_SUCH_ENTRY)
+            return err;
+          else
+            svn_error_clear (err);
+          
+          svn_path_split (url, &temp, &dir, pool);
+          APR_ARRAY_PUSH (*new_paths, const char*) = dir;
+          url = temp;
+        }
+    }
+  while ((err = get_ra_editor (ra_session, NULL,
+                               editor, edit_baton, ctx, url, base_dir,
+                               NULL, log_msg, NULL, commit_info,
+                               FALSE, NULL, TRUE, subpool)));
+  /* Reverse the order of the components we added to our NEW_ENTRIES array. */
+  if ((*new_paths)->nelts)
+    {
+      for (i = 0; i < ((*new_paths)->nelts / 2); i++)
+        {
+          j = (*new_paths)->nelts - i - 1;
+          component = 
+            APR_ARRAY_IDX (*new_paths, i, const char *);
+          APR_ARRAY_IDX (*new_paths, i, const char *) =
+            APR_ARRAY_IDX (*new_paths, j, const char *);
+          APR_ARRAY_IDX (*new_paths, j, const char *) = 
+            component;
+        }
+    }
+  if (existing_url != NULL)
+    *existing_url = url;
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** Public Interfaces. ***/
 
@@ -649,10 +725,7 @@
   apr_hash_t *excludes = apr_hash_make (pool);
   svn_node_kind_t kind;
   const char *base_dir = path;
-  apr_array_header_t *new_entries = apr_array_make (pool, 4, 
-                                                    sizeof (const char *));
-  const char *temp;
-  const char *dir;
+  apr_array_header_t *new_entries;
   apr_pool_t *subpool;
 
   /* Create a new commit item and add it to the array. */
@@ -690,53 +763,11 @@
   /* Figure out all the path components we need to create just to have
      a place to stick our imported tree. */
   subpool = svn_pool_create (pool);
-  do
-    {
-      svn_pool_clear (subpool);
+  SVN_ERR (svn_client__url_new_paths (NULL, &new_entries, &ra_session,
+                                      NULL, &editor, &edit_baton, ctx, url,
+                                      base_dir, NULL, log_msg, NULL,
+                                      commit_info, FALSE, subpool));
 
-      /* See if the user is interested in cancelling this operation. */
-      if (ctx->cancel_func)
-        SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
-
-      if (err)
-        {
-          /* If get_ra_editor below failed we either tried to open
-             an invalid url, or else some other kind of error.  In case
-             the url was bad we back up a directory and try again. */
-          
-          if (err->apr_err != SVN_ERR_FS_NO_SUCH_ENTRY)
-            return err;
-          else
-            svn_error_clear (err);
-          
-          svn_path_split (url, &temp, &dir, pool);
-          *((const char **) apr_array_push (new_entries)) = 
-            svn_path_uri_decode (dir, pool);
-          url = temp;
-        }
-    }
-  while ((err = get_ra_editor (&ra_session, NULL,
-                               &editor, &edit_baton, ctx, url, base_dir,
-                               NULL, log_msg, NULL, commit_info,
-                               FALSE, NULL, TRUE, subpool)));
-
-  /* Reverse the order of the components we added to our NEW_ENTRIES array. */
-  if (new_entries->nelts)
-    {
-      int i, j;
-      const char *component;
-      for (i = 0; i < (new_entries->nelts / 2); i++)
-        {
-          j = new_entries->nelts - i - 1;
-          component = 
-            APR_ARRAY_IDX (new_entries, i, const char *);
-          APR_ARRAY_IDX (new_entries, i, const char *) =
-            APR_ARRAY_IDX (new_entries, j, const char *);
-          APR_ARRAY_IDX (new_entries, j, const char *) = 
-            component;
-        }
-    }
-  
   /* An empty NEW_ENTRIES list the first call to get_ra_editor() above
      succeeded.  That means that URL corresponds to an already
      existing filesystem entity. */
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h	(revision 15336)
+++ subversion/clients/cmdline/cl.h	(working copy)
@@ -76,7 +76,8 @@
   svn_cl__strict_opt,
   svn_cl__targets_opt,
   svn_cl__version_opt,
-  svn_cl__xml_opt
+  svn_cl__xml_opt,
+  svn_cl__parents_opt
 } svn_cl__longopt_t;
 
 
@@ -141,6 +142,7 @@
   svn_boolean_t autoprops;       /* enable automatic properties */
   svn_boolean_t no_autoprops;    /* disable automatic properties */
   const char *native_eol;        /* override system standard eol marker */
+  svn_boolean_t parents;         /* create parent directories */
 } svn_cl__opt_state_t;
 
 
Index: subversion/clients/cmdline/move-cmd.c
===================================================================
--- subversion/clients/cmdline/move-cmd.c	(revision 15336)
+++ subversion/clients/cmdline/move-cmd.c	(working copy)
@@ -69,8 +69,8 @@
          _("Cannot specify revisions (except HEAD) with move operations"));
     }
 
-  err = svn_client_move2 (&commit_info, src_path, dst_path,
-                          opt_state->force, ctx, pool);
+  err = svn_client_move3 (&commit_info, src_path, dst_path,
+                          opt_state->force, opt_state->parents, ctx, pool);
 
   if (err)
     err = svn_cl__may_need_force (err);
Index: subversion/clients/cmdline/mkdir-cmd.c
===================================================================
--- subversion/clients/cmdline/mkdir-cmd.c	(revision 15336)
+++ subversion/clients/cmdline/mkdir-cmd.c	(working copy)
@@ -72,7 +72,8 @@
                                            NULL, ctx->config, subpool));
     }
 
-  err = svn_client_mkdir (&commit_info, targets, ctx, subpool);
+  err = svn_client_mkdir2 (&commit_info, targets, opt_state->parents,
+                          ctx, subpool);
 
   if (ctx->log_msg_func)
     err = svn_cl__cleanup_log_msg (ctx->log_msg_baton, err);
Index: subversion/clients/cmdline/copy-cmd.c
===================================================================
--- subversion/clients/cmdline/copy-cmd.c	(revision 15336)
+++ subversion/clients/cmdline/copy-cmd.c	(working copy)
@@ -110,9 +110,9 @@
     SVN_ERR (svn_cl__make_log_msg_baton (&(ctx->log_msg_baton), opt_state, 
                                          NULL, ctx->config, pool));
 
-  err = svn_client_copy (&commit_info, src_path,
+  err = svn_client_copy2 (&commit_info, src_path,
                          &(opt_state->start_revision),
-                         dst_path, ctx, pool);
+                         dst_path, opt_state->parents, ctx, pool);
 
   if (ctx->log_msg_func)
     SVN_ERR (svn_cl__cleanup_log_msg (ctx->log_msg_baton, err));
Index: subversion/clients/cmdline/main.c
===================================================================
--- subversion/clients/cmdline/main.c	(revision 15336)
+++ subversion/clients/cmdline/main.c	(working copy)
@@ -149,6 +149,8 @@
                       N_("maximum number of log entries")},
     {"no-unlock",     svn_cl__no_unlock_opt, 0,
                       N_("don't unlock the targets")},
+    {"parents",       svn_cl__parents_opt, 0, 
+                      N_("make parent directories as needed")},
     {0,               0, 0, 0}
   };
 
@@ -253,7 +255,7 @@
        "    WC  -> URL:  immediately commit a copy of WC to URL\n"
        "    URL -> WC:   check out URL into WC, schedule for addition\n"
        "    URL -> URL:  complete server-side copy;  used to branch & tag\n"),
-    {'r', 'q',
+    {'r', 'q', svn_cl__parents_opt,
      SVN_CL__LOG_MSG_OPTIONS, SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
   
   { "delete", svn_cl__delete, {"del", "remove", "rm"},
@@ -482,9 +484,12 @@
        "via\n"
        "    an immediate commit.\n"
        "\n"
-       "  In both cases, all the intermediate directories must already "
+       "  In case 1, intermediate directories are created as needed if\n"
+       "    --parents is specified.\n"
+       "\n"
+       "  Otherwise, all the intermediate directories must already "
        "exist.\n"),
-    {'q',
+    {'q', svn_cl__parents_opt,
      SVN_CL__LOG_MSG_OPTIONS, SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
 
   { "move", svn_cl__move, {"mv", "rename", "ren"},
@@ -496,7 +501,7 @@
        "  SRC and DST can both be working copy (WC) paths or URLs:\n"
        "    WC  -> WC:   move and schedule for addition (with history)\n"
        "    URL -> URL:  complete server-side rename.\n"),    
-    {'r', 'q', svn_cl__force_opt,
+    {'r', 'q', svn_cl__force_opt, svn_cl__parents_opt,
      SVN_CL__LOG_MSG_OPTIONS, SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt} },
   
   { "propdel", svn_cl__propdel, {"pdel", "pd"},
@@ -980,6 +985,9 @@
       case svn_cl__revprop_opt:
         opt_state.revprop = TRUE;
         break;
+      case svn_cl__parents_opt:
+        opt_state.parents = TRUE;
+        break;
       case 'R':
         opt_state.recursive = TRUE;
         break;
Index: subversion/tests/clients/cmdline/copy_tests.py
===================================================================
--- subversion/tests/clients/cmdline/copy_tests.py	(revision 15336)
+++ subversion/tests/clients/cmdline/copy_tests.py	(working copy)
@@ -21,7 +21,7 @@
 
 # Our testing module
 import svntest
-from svntest import SVNAnyOutput
+from svntest import wc, SVNAnyOutput
 
 # (abbreviation)
 Skip = svntest.testcase.Skip
@@ -1615,8 +1615,202 @@
       found_it = 1
   if not found_it:
     raise svntest.Failure
+#----------------------------------------------------------------------
+def copy_url_mkdir_parents(sbox):
+  "create parent directories and copy url-to-url"
 
+  sbox.build()
 
+  src_url = svntest.main.current_repo_url + '/iota'
+  X_url = svntest.main.current_repo_url + '/X/X2/X3'
+
+  svntest.actions.run_and_verify_svn(None,
+                                     ["\n", "Committed revision 2.\n"], [],
+                                     'cp', '-m', 'log_msg', '--parents',
+                                     '--username',
+                                     svntest.main.wc_author,
+                                     '--password',
+                                     svntest.main.wc_passwd,
+                                     src_url, X_url)
+
+  # verify svn copy with a wc update
+  expected_output = wc.State(sbox.wc_dir, {
+    'X'           : Item(status='A '),
+    'X/X2'        : Item(status='A '),
+    'X/X2/X3'     : Item(status='A '),
+    'X/X2/X3/iota': Item(status='A ')
+    })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'X'            : Item(),
+    'X/X2'         : Item(),
+    'X/X2/X3'      : Item(),
+    'X/X2/X3/iota' : Item("This is the file 'iota'.\n")
+    })
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2)
+  expected_status.add({
+    'X'            : Item(status='  ', wc_rev=2),
+    'X/X2'         : Item(status='  ', wc_rev=2),
+    'X/X2/X3'      : Item(status='  ', wc_rev=2),
+    'X/X2/X3/iota' : Item(status='  ', wc_rev=2)
+   })
+
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status)
+#----------------------------------------------------------------------
+def move_url_mkdir_parents(sbox):
+  "create parents directories and move url-to-url"
+
+  sbox.build()
+
+  src_url = svntest.main.current_repo_url + '/iota'
+  X_url = svntest.main.current_repo_url + '/X/X2/X3'
+
+  svntest.actions.run_and_verify_svn(None,
+                                     ["\n", "Committed revision 2.\n"], [],
+                                     'mv', '-m', 'log_msg', '--parents',
+                                     '--username',
+                                     svntest.main.wc_author,
+                                     '--password',
+                                     svntest.main.wc_passwd,
+                                     src_url, X_url)
+
+  # verify svn copy with a wc update
+  expected_output = wc.State(sbox.wc_dir, {
+    'iota'        : Item(status='D '),
+    'X'           : Item(status='A '),
+    'X/X2'        : Item(status='A '),
+    'X/X2/X3'     : Item(status='A '),
+    'X/X2/X3/iota': Item(status='A ')
+    })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('iota')
+  expected_disk.add({
+    'X'            : Item(),
+    'X/X2'         : Item(),
+    'X/X2/X3'      : Item(),
+    'X/X2/X3/iota' : Item("This is the file 'iota'.\n")
+    })
+
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2)
+  expected_status.remove('iota')
+  expected_status.add({
+    'X'            : Item(status='  ', wc_rev=2),
+    'X/X2'         : Item(status='  ', wc_rev=2),
+    'X/X2/X3'      : Item(status='  ', wc_rev=2),
+    'X/X2/X3/iota' : Item(status='  ', wc_rev=2)
+   })
+
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status)
+#----------------------------------------------------------------------
+def copy_wc_to_wc_parents(sbox):
+  "create parent dirs and copy between wc dirs"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  iota_path = os.path.join(wc_dir, 'iota')
+  Y_path = os.path.join(wc_dir, 'Y', 'Y2')
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'cp', '--parents',
+                                     iota_path, Y_path)
+
+  expected_output =  wc.State(sbox.wc_dir, {
+    'Y'           : Item(verb='Adding'),
+    'Y/Y2'        : Item(verb='Adding'),
+    'Y/Y2/iota'   : Item(verb='Adding'),
+   })
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2)
+  expected_status.add({
+    'Y'            : Item(status='  ', wc_rev=2),
+    'Y/Y2'         : Item(status='  ', wc_rev=2),
+    'Y/Y2/iota'    : Item(status='  ', wc_rev=2)
+   })
+  expected_status.tweak(wc_rev=1)
+  expected_status.tweak('Y', 'Y/Y2', 'Y/Y2/iota', wc_rev=2)
+
+  svntest.actions.run_and_verify_commit (wc_dir, expected_output,
+                                         expected_status,
+                                         None, None, None, None, None,
+                                         wc_dir)
+#----------------------------------------------------------------------
+def move_wc_to_wc_parents(sbox):
+  "create parent dirs and move between wc dirs"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  iota_path = os.path.join(wc_dir, 'iota')
+  Y_path = os.path.join(wc_dir, 'Y', 'Y2')
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'mv','--parents',
+                                     iota_path, Y_path)
+
+  expected_output =  wc.State(sbox.wc_dir, {
+    'Y'           : Item(verb='Adding'),
+    'Y/Y2'        : Item(verb='Adding'),
+    'Y/Y2/iota'   : Item(verb='Adding'),
+    'iota'        : Item(verb='Deleting'),
+   })
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2)
+  expected_status.add({
+    'Y'            : Item(status='  ', wc_rev=2),
+    'Y/Y2'         : Item(status='  ', wc_rev=2),
+    'Y/Y2/iota'    : Item(status='  ', wc_rev=2)
+   })
+  expected_status.remove('iota')
+  expected_status.tweak(wc_rev=1)
+  expected_status.tweak('Y', 'Y/Y2', 'Y/Y2/iota', wc_rev=2)
+
+  svntest.actions.run_and_verify_commit (wc_dir, expected_output,
+                                         None,
+                                         None, None, None, None, None,
+                                         wc_dir)
+#----------------------------------------------------------------------
+def copy_url_to_wc_parents(sbox):
+  "copy from url to wc with parent dirs"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  iota_url = svntest.main.current_repo_url + '/iota'
+  Y_path = os.path.join(wc_dir, 'Y', 'Y2')
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'cp', '--parents',
+                                     iota_url, Y_path)
+
+  expected_output =  wc.State(sbox.wc_dir, {
+    'Y'           : Item(verb='Adding'),
+    'Y/Y2'        : Item(verb='Adding'),
+    'Y/Y2/iota'   : Item(verb='Adding'),
+   })
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2)
+  expected_status.add({
+    'Y'            : Item(status='  ', wc_rev=2),
+    'Y/Y2'         : Item(status='  ', wc_rev=2),
+    'Y/Y2/iota'    : Item(status='  ', wc_rev=2)
+   })
+  expected_status.tweak(wc_rev=1)
+  expected_status.tweak('Y', 'Y/Y2', 'Y/Y2/iota', wc_rev=2)
+
+  svntest.actions.run_and_verify_commit (wc_dir, expected_output,
+                                         expected_status,
+                                         None, None, None, None, None,
+                                         wc_dir)
+#----------------------------------------------------------------------
 ########################################################################
 # Run the tests
 
@@ -1652,6 +1846,11 @@
               old_dir_url_to_url,
               wc_copy_dir_to_itself,
               mixed_wc_to_url,
+              copy_url_mkdir_parents,
+              move_url_mkdir_parents,
+              copy_wc_to_wc_parents,
+              move_wc_to_wc_parents,
+              copy_url_to_wc_parents,
              ]
 
 if __name__ == '__main__':
Index: subversion/tests/clients/cmdline/basic_tests.py
===================================================================
--- subversion/tests/clients/cmdline/basic_tests.py	(revision 15336)
+++ subversion/tests/clients/cmdline/basic_tests.py	(working copy)
@@ -1613,6 +1613,104 @@
 
 
 #----------------------------------------------------------------------
+def basic_mkdir_url_p(sbox):
+  "basic mkdir parent url"
+
+  sbox.build()
+
+  X_url = svntest.main.current_repo_url + '/X/X2/X3'
+  Y_url = svntest.main.current_repo_url + '/Y/Y2/Y3'
+
+  # 'mkdir --parents' with multiple paths
+  svntest.actions.run_and_verify_svn("mkdir --parents URL/parentdir/subdir \
+                                      URL/parentdir2/subdir2 ...",
+                                     ["\n", "Committed revision 2.\n"], [],
+                                     'mkdir', '--parents', '-m', 'log_msg', 
+                                     X_url, Y_url)
+
+  # verify the 'mkdir --parents' with a wc update
+  expected_output = wc.State(sbox.wc_dir, {
+    'X'      : Item(status='A '),
+    'X/X2'   : Item(status='A '),
+    'X/X2/X3': Item(status='A '),
+    'Y'      : Item(status='A '),
+    'Y/Y2'   : Item(status='A '),
+    'Y/Y2/Y3': Item(status='A ')
+    })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'X'       : Item(),
+    'X/X2'    : Item(),
+    'X/X2/X3' : Item(),
+    'Y'       : Item(),
+    'Y/Y2'    : Item(),
+    'Y/Y2/Y3' : Item()
+    })
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 2)
+  expected_status.add({
+   'X'       : Item(status='  ', wc_rev=2),
+   'X/X2'    : Item(status='  ', wc_rev=2),
+   'X/X2/X3' : Item(status='  ', wc_rev=2),
+   'Y'       : Item(status='  ', wc_rev=2),
+   'Y/Y2'    : Item(status='  ', wc_rev=2),
+   'Y/Y2/Y3' : Item(status='  ', wc_rev=2)
+  })
+
+  svntest.actions.run_and_verify_update(sbox.wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status)
+#----------------------------------------------------------------------
+def basic_mkdir_missing_parent(sbox):
+  "basic mkdir missingparent/path (should fail)"
+
+  sbox.build()
+
+  Y_Z_path = os.path.join(sbox.wc_dir, 'Y', 'Z')
+
+  svntest.actions.run_and_verify_svn("mkdir dir/subdir", [],
+                                     SVNAnyOutput,
+                                     'mkdir', Y_Z_path)
+#----------------------------------------------------------------------
+def basic_mkdir_missing_parent_p(sbox):
+  "basic mkdir --parents missingparent/path"
+
+  sbox.build()
+
+  Y_Z_path = os.path.join(sbox.wc_dir, 'Y', 'Z')
+
+  svntest.actions.run_and_verify_svn("mkdir dir/subdir", None, [],
+                                     'mkdir', '--parents', Y_Z_path)
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  expected_status.add({
+    'Y'   : Item(status='A ', wc_rev=0),
+    'Y/Z' : Item(status='A ', wc_rev=0)
+    })
+
+  svntest.actions.run_and_verify_status(sbox.wc_dir,
+                                        expected_status)
+#----------------------------------------------------------------------
+def basic_mkdir_wcpath(sbox):
+  "basic mkdir wcpath"
+
+  sbox.build()
+
+  Y_path = os.path.join(sbox.wc_dir, 'Y')
+  Y_Z_path = os.path.join(sbox.wc_dir, 'Y', 'Z')
+
+  svntest.actions.run_and_verify_svn("mkdir dir dir/subdir", None, [],
+                                     'mkdir', Y_path, Y_Z_path)
+
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  expected_status.add({
+    'Y'   : Item(status='A ', wc_rev=0),
+    'Y/Z' : Item(status='A ', wc_rev=0)
+    })
+
+  svntest.actions.run_and_verify_status(sbox.wc_dir,
+                                        expected_status)
+#----------------------------------------------------------------------
 ########################################################################
 # Run the tests
 
@@ -1646,6 +1744,10 @@
               basic_add_no_ignores,
               repos_root,
               basic_peg_revision,
+              basic_mkdir_url_p,
+              basic_mkdir_wcpath,
+              basic_mkdir_missing_parent,
+              basic_mkdir_missing_parent_p,
               ### todo: more tests needed:
               ### test "svn rm http://some_url"
               ### not sure this file is the right place, though.
