Index: subversion/libsvn_ra/wrapper_template.h
===================================================================
--- subversion/libsvn_ra/wrapper_template.h	(revision 14704)
+++ subversion/libsvn_ra/wrapper_template.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra/wrapper_template.h
     (compat_get_commit_editor): Changed to use svn_commit_callback2_t
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -99,7 +99,7 @@
                                               **editor,
                                               void **edit_baton,
                                               const char *log_msg,
-                                              svn_commit_callback_t callback,
+                                              svn_commit_callback2_t callback,
                                               void *callback_baton,
                                               apr_pool_t *pool)
 {
Index: subversion/libsvn_ra/ra_loader.c
===================================================================
--- subversion/libsvn_ra/ra_loader.c	(revision 14704)
+++ subversion/libsvn_ra/ra_loader.c	(working copy)
@@ -337,6 +337,23 @@
                                              lock_tokens, keep_locks, pool);
 }
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra/ra_loader.c
     (svn_ra_get_commit_editor2): New version of svn_ra_get_commit_editor
     which takes svn_commit_callback2_t as the callback type
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** since v1.3
+  */
+svn_error_t *svn_ra_get_commit_editor2 (svn_ra_session_t *session,
+                                        const svn_delta_editor_t **editor,
+                                        void **edit_baton,
+                                        const char *log_msg,
+                                        svn_commit_callback2_t callback,
+                                        void *callback_baton,
+                                        apr_hash_t *lock_tokens,
+                                        svn_boolean_t keep_locks,
+                                        apr_pool_t *pool)
+{
+  return session->vtable->get_commit_editor (session, editor, edit_baton,
+                                             log_msg, callback, callback_baton,
+                                             lock_tokens, keep_locks, pool);
+}
+
 svn_error_t *svn_ra_get_file (svn_ra_session_t *session,
                               const char *path,
                               svn_revnum_t revision,
Index: subversion/libsvn_ra/ra_loader.h
===================================================================
--- subversion/libsvn_ra/ra_loader.h	(revision 14704)
+++ subversion/libsvn_ra/ra_loader.h	(working copy)
@@ -80,7 +80,7 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/include/svn_repos.h
     (svn_ra__vtable_t): Using  svn_commit_callback2_t as callback
     parameter for get_commit_editor
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                                      const svn_delta_editor_t **editor,
                                      void **edit_baton,
                                      const char *log_msg,
-                                     svn_commit_callback_t callback,
+                                     svn_commit_callback2_t callback,
                                      void *callback_baton,
                                      apr_hash_t *lock_tokens,
                                      svn_boolean_t keep_locks,
Index: subversion/include/svn_repos.h
===================================================================
--- subversion/include/svn_repos.h	(revision 14704)
+++ subversion/include/svn_repos.h	(working copy)
@@ -607,6 +607,20 @@
                                            svn_commit_callback_t callback,
                                            void *callback_baton,
                                            apr_pool_t *pool);

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/include/svn_repos.h
     (svn_repos_get_commit_editor3): New version of
     svn_repos_get_commit_editor2, which takes svn_commit_callback2_t
     as the callback type
     (svn_repos_get_commit_editor2): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** Since 1.3
+  * uses the svn_commit_callback2_t callback
+  */
+svn_error_t *svn_repos_get_commit_editor3 (const svn_delta_editor_t **editor,
+                                           void **edit_baton,
+                                           svn_repos_t *repos,
+                                           svn_fs_txn_t *txn,
+                                           const char *repos_url,
+                                           const char *base_path,
+                                           const char *user,
+                                           const char *log_msg,
+                                           svn_commit_callback2_t callback,
+                                           void *callback_baton,
+                                           apr_pool_t *pool);
 
 
 /**
Index: subversion/include/svn_types.h
===================================================================
--- subversion/include/svn_types.h	(revision 14704)
+++ subversion/include/svn_types.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/include/svn_types.h
     (svn_commit_callback2_t): New version of svn_commit_callback_t
     with a new parameter post_commit_err.
     (svn_commit_callback_t): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -351,6 +351,17 @@
     const char *author,
     void *baton);
 
+/** @since New in 1.3. 
+ *
+ * v2. to accomodate post-commit error
+ */
+typedef svn_error_t * (*svn_commit_callback2_t) (



+    svn_revnum_t new_revision,
+    const char *date,
+    const char *author,
+    const char *post_commit_err,
+    void *baton);
+
 
 /** The maximum amount we (ideally) hold in memory at a time when
  * processing a stream of data.
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h	(revision 14704)
+++ subversion/include/svn_client.h	(working copy)
@@ -277,7 +277,27 @@
 
 } svn_client_commit_info_t;
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/include/svn_client.h
     (svn_client_commit_info2_t): New version of 
     svn_client_commit_info_t now containing the post_commit_err
     parameter to hold the post-commit hook's stderr
     (svn_client_commit_info_t): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** @since New in 1.3.
+ * Information about commits passed back to client from this module.
+ * v2. to accomodate post-commit hook's stderr
+ */
+typedef struct svn_client_commit_info2_t
+{
+  /** just-committed revision. */
+  svn_revnum_t revision;
 
+  /** server-side date of the commit. */
+  const char *date;
+
+  /** author of the commit. */
+  const char *author;
+
+  /** post-commit hook's stderr. */
+  const char *post_commit_err;
+
+} svn_client_commit_info2_t;
+
+
 /** @{
  * State flags for use with the @c svn_client_commit_item_t structure
  *
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_mkdir2): New version of svn_client_mkdir now taking
     svn_client_commit_info2_t as the commit_info type
     (svn_client_mkdir): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -678,6 +698,14 @@
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool);
                   
+/** since v1.3
+ */
+svn_error_t *
+svn_client_mkdir2 (svn_client_commit_info2_t **commit_info,
+                   const apr_array_header_t *paths,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool);
+                  
 
 /** Delete items from a repository or working copy.
  *
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/include/svn_repos.h
     (svn_repos_get_commit_editor3): New version of
     svn_repos_get_commit_editor2, which takes svn_commit_callback2_t
     as the callback type
     (svn_repos_get_commit_editor2): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -714,6 +742,14 @@
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool);
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_delete2): New version of svn_client_delete
     which now takes svn_client_commit_info2_t as commit_info type
     (svn_client_delete): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** since v1.3
+  */
+svn_error_t *
+svn_client_delete2 (svn_client_commit_info2_t **commit_info,
+                    const apr_array_header_t *paths,
+                    svn_boolean_t force,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *pool);
 
 /** Import file or directory @a path into repository directory @a url at
  * head, authenticating with the authentication baton cached in @a ctx, 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_import2): New version of svn_client_import
     which now takes svn_client_commit_info2_t as type for
     the commit_info parameter.
     (svn_client_import): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -751,6 +787,15 @@
  * option. However, doing so is a bit involved, and we don't need it
  * right now.  
  */
+/** since v1.3
+  */
+svn_error_t *svn_client_import2 (svn_client_commit_info2_t **commit_info,
+                                 const char *path,
+                                 const char *url,
+                                 svn_boolean_t nonrecursive,
+                                 svn_client_ctx_t *ctx,
+                                 apr_pool_t *pool);
+
 svn_error_t *svn_client_import (svn_client_commit_info_t **commit_info,
                                 const char *path,
                                 const char *url,
@@ -759,6 +804,17 @@
                                 apr_pool_t *pool);
 
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_commit3): New version of svn_client_commit
     which now takes svn_client_commit_info2_t for commit_info
     (svn_client_commit2): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** @since New in 1.3.
+  * using svn_client_commit_info2_t
+  */
+svn_error_t *
+svn_client_commit3 (svn_client_commit_info2_t **commit_info,
+                    const apr_array_header_t *targets,
+                    svn_boolean_t recurse,
+                    svn_boolean_t keep_locks,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *pool);
+
 /** @since New in 1.2.
  *
  * Commit files or directories into repository, authenticating with
@@ -1347,7 +1403,17 @@
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool);
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_copy2): New version of svn_client_copy which now takes
     svn_client_commit_info2_t as the commit_info type.
     (svn_client_copy): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** since v1.3
+  */
+svn_error_t *
+svn_client_copy2 (svn_client_commit_info2_t **commit_info,
+                  const char *src_path,
+                  const svn_opt_revision_t *src_revision,
+                  const char *dst_path,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool);
 
+
 /**
  * @since New in 1.2.
  *
@@ -1393,7 +1459,19 @@
  *
  * ### Is this really true?  What about svn_wc_notify_commit_replaced()? ###
  */ 
+
+/** since v1.3
+  * using svn_client_commit_info2_t
+  */
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_move3): New version of svn_client_move but now
     uses svn_client_commit_info2_t for the commit_info parameter type
     (svn_client_move2): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 svn_error_t *
+svn_client_move3 (svn_client_commit_info2_t **commit_info,
+                  const char *src_path,
+                  const char *dst_path,
+                  svn_boolean_t force,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool);
+
+svn_error_t *
 svn_client_move2 (svn_client_commit_info_t **commit_info,
                   const char *src_path,
                   const char *dst_path,
Index: subversion/include/svn_ra.h
===================================================================
--- subversion/include/svn_ra.h	(revision 14704)
+++ subversion/include/svn_ra.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/include/svn_ra.h
     (svn_ra_get_commit_editor2): New version of svn_ra_get_commit_editor
     which takes svn_commit_callback2_t as the callback type
     (svn_ra_get_commit_editor): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -506,6 +506,16 @@
                                        svn_boolean_t keep_locks,
                                        apr_pool_t *pool);
 
+svn_error_t *svn_ra_get_commit_editor2 (svn_ra_session_t *session,
+                                        const svn_delta_editor_t **editor,
+                                        void **edit_baton,
+                                        const char *log_msg,
+                                        svn_commit_callback2_t callback,
+                                        void *callback_baton,
+                                        apr_hash_t *lock_tokens,
+                                        svn_boolean_t keep_locks,
+                                        apr_pool_t *pool);
+
 /**
  * @since New in 1.2.
  *
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_ra_plugin_t): Changed to take svn_commit_callback2_t
     as parameter for get_commit_editor.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -1124,7 +1134,7 @@
                                      const svn_delta_editor_t **editor,
                                      void **edit_baton,
                                      const char *log_msg,
-                                     svn_commit_callback_t callback,
+                                     svn_commit_callback2_t callback,
                                      void *callback_baton,
                                      apr_pool_t *pool);
 
Index: subversion/libsvn_ra_local/ra_plugin.c
===================================================================
--- subversion/libsvn_ra_local/ra_plugin.c	(revision 14704)
+++ subversion/libsvn_ra_local/ra_plugin.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra_local/ra_plugin.c
     (deltify_etc_baton): Now takes svn_commit_callback2_t for callback
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -408,7 +408,7 @@
   const char *fs_path;             /* fs-path part of split session URL */
   apr_hash_t *lock_tokens;         /* tokens to unlock, if any */
   apr_pool_t *pool;                /* pool for scratch work */
-  svn_commit_callback_t callback;  /* the original callback */
+  svn_commit_callback2_t callback;  /* the original callback */
   void *callback_baton;            /* the original callback's baton */
 };
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (deltify_etc): Now takes an extra parameter - post_commit_err
     and passes it on to the callback.
     (svn_ra_local__get_commit_editor): Now takes svn_commit_callback2_t
     for the callback parameter. Also call svn_repos_get_commit_editor3
     instead of svn_repos_get_commit_editor2
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -420,6 +420,7 @@
 deltify_etc (svn_revnum_t new_revision,
              const char *date,
              const char *author,
+             const char *post_commit_err,
              void *baton)
 {
   struct deltify_etc_baton *db = baton;
@@ -430,7 +431,8 @@
   /* Invoke the original callback first, in case someone's waiting to
      know the revision number so they can go off and annotate an
      issue or something. */
-  err1 = (*db->callback) (new_revision, date, author, db->callback_baton);
+  err1 = (*db->callback) (new_revision, date, author,
+                          post_commit_err, db->callback_baton);
 
   /* Maybe unlock the paths. */
   if (db->lock_tokens)
@@ -478,7 +480,7 @@
                                  const svn_delta_editor_t **editor,
                                  void **edit_baton,
                                  const char *log_msg,
-                                 svn_commit_callback_t callback,
+                                 svn_commit_callback2_t callback,
                                  void *callback_baton,
                                  apr_hash_t *lock_tokens,
                                  svn_boolean_t keep_locks,
@@ -525,7 +527,7 @@
     }
               
   /* Get the repos commit-editor */     
-  SVN_ERR (svn_repos_get_commit_editor2
+  SVN_ERR (svn_repos_get_commit_editor3
            (editor, edit_baton, sess_baton->repos, NULL,
             svn_path_uri_decode (sess_baton->repos_url, pool),
             sess_baton->fs_path,
Index: subversion/libsvn_client/delete.c
===================================================================
--- subversion/libsvn_client/delete.c	(revision 14704)
+++ subversion/libsvn_client/delete.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_client/delete.c
     (delete_urls2): New version of delete_urls which uses
     svn_client_commit_info2_t as commit_info type, thus making is
     post-commit hook's stderr aware.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -109,6 +109,106 @@
 
 
 static svn_error_t *
+delete_urls2 (svn_client_commit_info2_t **commit_info,
+              const apr_array_header_t *paths,
+              svn_client_ctx_t *ctx,
+              apr_pool_t *pool)
+{
+  svn_ra_session_t *ra_session;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  void *commit_baton;
+  const char *log_msg;
+  svn_node_kind_t kind;
+  apr_array_header_t *targets;
+  svn_error_t *err;
+  const char *common;
+  int i;
+  apr_pool_t *subpool = svn_pool_create (pool);
+
+  /* Condense our list of deletion targets. */
+  SVN_ERR (svn_path_condense_targets (&common, &targets, paths, TRUE, pool));
+  if (! targets->nelts)
+    {
+      const char *bname;
+      svn_path_split (common, &common, &bname, pool);
+      APR_ARRAY_PUSH (targets, const char *) = bname;
+    }
+
+  /* Create new commit items and add them 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, targets->nelts, sizeof (item));
+          
+      for (i = 0; i < targets->nelts; i++)
+        {
+          const char *path = APR_ARRAY_IDX (targets, i, const char *);
+          item = apr_pcalloc (pool, sizeof (*item));
+          item->url = svn_path_join (common, path, pool);
+          item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE;
+          APR_ARRAY_PUSH (commit_items, svn_client_commit_item_t *) = item;
+        }
+      SVN_ERR ((*ctx->log_msg_func) (&log_msg, &tmp_file, commit_items, 
+                                     ctx->log_msg_baton, pool));
+      if (! log_msg)
+        return SVN_NO_ERROR;
+    }
+  else
+    log_msg = "";
+
+  /* Open an RA session for the URL. Note that we don't have a local
+     directory, nor a place to put temp files. */
+  SVN_ERR (svn_client__open_ra_session (&ra_session, common, NULL,
+                                        NULL, NULL, FALSE, TRUE,
+                                        ctx, pool));
+
+  /* Verify that each thing to be deleted actually exists (to prevent
+     the creation of a revision that has no changes, since the
+     filesystem allows for no-op deletes). */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      const char *path = APR_ARRAY_IDX (targets, i, const char *);
+      svn_pool_clear (subpool);
+      path = svn_path_uri_decode (path, pool);
+      APR_ARRAY_IDX (targets, i, const char *) = path;
+      SVN_ERR (svn_ra_check_path (ra_session, path, SVN_INVALID_REVNUM,
+                                  &kind, subpool));
+      if (kind == svn_node_none)
+        return svn_error_createf (SVN_ERR_FS_NOT_FOUND, NULL,
+                                  "URL '%s' does not exist",
+                                  svn_path_local_style (path, pool));
+    }
+  svn_pool_destroy (subpool);
+
+  /* Fetch RA commit editor */
+  SVN_ERR (svn_client__commit_get_baton2 (&commit_baton, commit_info, pool));
+  SVN_ERR (svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton,
+                                      log_msg, svn_client__commit_callback2,
+                                      commit_baton,
+                                      NULL, TRUE, /* No lock tokens */
+                                      pool));
+
+  /* Call the path-based editor driver. */
+  err = svn_delta_path_driver (editor, edit_baton, SVN_INVALID_REVNUM, 
+                               targets, path_driver_cb_func, 
+                               (void *)editor, 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;
+    }
+
+  /* Close the edit. */
+  SVN_ERR (editor->close_edit (edit_baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 delete_urls (svn_client_commit_info_t **commit_info,
              const apr_array_header_t *paths,
              svn_client_ctx_t *ctx,
@@ -233,6 +333,55 @@
 
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_delete2): New version of svn_client_delete
     now using svn_client_commit_info2_t as commit_info type.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 svn_error_t *
+svn_client_delete2 (svn_client_commit_info2_t **commit_info,
+                    const apr_array_header_t *paths,
+                    svn_boolean_t force, 
+                    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 (delete_urls2 (commit_info, paths, ctx, pool));
+    }
+  else
+    {
+      apr_pool_t *subpool = svn_pool_create (pool);
+      int i;
+
+      for (i = 0; i < paths->nelts; i++)
+        {
+          svn_wc_adm_access_t *adm_access;
+          const char *path = APR_ARRAY_IDX (paths, i, const char *);
+          const char *parent_path;
+
+          svn_pool_clear (subpool);
+          parent_path = svn_path_dirname (path, subpool);
+
+          /* See if the user wants us to stop. */
+          if (ctx->cancel_func)
+            SVN_ERR (ctx->cancel_func (ctx->cancel_baton));
+
+          /* Let the working copy library handle the PATH. */
+          SVN_ERR (svn_wc_adm_open3 (&adm_access, NULL, parent_path, 
+                                     TRUE, 0, ctx->cancel_func,
+                                     ctx->cancel_baton, subpool));
+          SVN_ERR (svn_client__wc_delete (path, adm_access, force, 
+                                          FALSE,
+                                          ctx->notify_func2,
+                                          ctx->notify_baton2,
+                                          ctx, subpool));
+          SVN_ERR (svn_wc_adm_close (adm_access));
+        }
+      svn_pool_destroy (subpool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client_delete (svn_client_commit_info_t **commit_info,
                    const apr_array_header_t *paths,
                    svn_boolean_t force, 
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h	(revision 14704)
+++ subversion/libsvn_client/client.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_client/client.h
     (svn_client__commit_get_baton2): New version of
     svn_client__commit_get_baton, which takes svn_client_commit_info2_t
     as the type for the info parameter.
     (svn_client__commit_get_baton): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -248,6 +248,10 @@
                                            svn_client_commit_info_t **info,
                                            apr_pool_t *pool);
 
+svn_error_t *svn_client__commit_get_baton2 (void **baton,
+                                            svn_client_commit_info2_t **info,
+                                            apr_pool_t *pool);
+
 /* The commit_callback function for storing svn_client_commit_info_t
    pointed by commit_baton. If the commit_info supplied by get_baton
    points to NULL after close_edit, it means the commit is a no-op.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client__commit_callback2): New version of
     svn_client__commit_callback, now providing for the stderr output
     of the post-commit hook.
     (svn_client__commit_callback): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -257,6 +261,15 @@
                                           const char *author,
                                           void *baton);
 
+/** @since New in 1.3.
+ * v2. To accomodate post-commit hook's stderr
+ */ 
+svn_error_t *svn_client__commit_callback2 (svn_revnum_t revision,
+                                           const char *date,
+                                           const char *author,
+                                           const char *post_commit_err,
+                                           void *baton);
+
 /* ---------------------------------------------------------------- */
 
 /*** Status ***/
Index: subversion/libsvn_client/copy.c
===================================================================
--- subversion/libsvn_client/copy.c	(revision 14704)
+++ subversion/libsvn_client/copy.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_client/copy.c
     (repos_to_repos_copy2): New version of repos_to_repos_copy
     svn_client_commit_info2_t for commit_info.
     (repos_to_repos_copy): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -269,7 +269,227 @@
   return SVN_NO_ERROR;
 }
 
+/** since  v1.3
+  */
+static svn_error_t *
+repos_to_repos_copy2 (svn_client_commit_info2_t **commit_info,
+                      const char *src_url, 
+                      const svn_opt_revision_t *src_revision, 
+                      const char *dst_url, 
+                      svn_client_ctx_t *ctx,
+                      svn_boolean_t is_move,
+                      apr_pool_t *pool)
+{
+  apr_array_header_t *paths = apr_array_make (pool, 2, sizeof (const char *));
+  const char *top_url, *src_rel, *dst_rel, *message;
+  svn_revnum_t youngest;
+  svn_ra_session_t *ra_session;
+  svn_node_kind_t src_kind, dst_kind;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  void *commit_baton;
+  svn_revnum_t src_revnum;
+  svn_boolean_t resurrection = FALSE;
+  struct path_driver_cb_baton cb_baton;
+  svn_error_t *err;
 
+  /* 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
+     checks on both paths, and so we can operate on both paths in the
+     case of a move. */
+  top_url = svn_path_get_longest_ancestor (src_url, dst_url, pool);
+
+  /* Special edge-case!  (issue #683)  If you're resurrecting a
+     deleted item like this:  'svn cp -rN src_URL dst_URL', then it's
+     possible for src_URL == dst_URL == top_url.  In this situation,
+     we want to open an RA session to the *parent* of all three. */
+  if (strcmp (src_url, dst_url) == 0)
+    {
+      resurrection = TRUE;
+      top_url = svn_path_dirname (top_url, pool);
+    }
+
+  /* Get the portions of the SRC and DST URLs that are relative to
+     TOP_URL, and URI-decode those sections. */
+  src_rel = svn_path_is_child (top_url, src_url, pool);
+  if (src_rel)
+    src_rel = svn_path_uri_decode (src_rel, pool);
+  else
+    src_rel = "";
+
+  dst_rel = svn_path_is_child (top_url, dst_url, pool);
+  if (dst_rel)
+    dst_rel = svn_path_uri_decode (dst_rel, pool);
+  else
+    dst_rel = "";
+
+  /* We can't move something into itself, period. */
+  if (svn_path_is_empty (src_rel) && is_move)
+    return svn_error_createf (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                              _("Cannot move URL '%s' into itself"), src_url);
+
+  /* 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 (&ra_session, top_url,
+                                     NULL,
+                                     NULL, NULL, FALSE, TRUE, 
+                                     ctx, pool);
+
+  /* If the two URLs appear not to be in the same repository, then
+     top_url will be empty and the call to svn_ra_open()
+     above will have failed.  Below we check for that, and propagate a
+     descriptive error back to the user.
+   
+     Ideally, we'd contact the repositories and compare their UUIDs to
+     determine whether or not src and dst are in the same repository,
+     instead of depending on an essentially textual comparison.
+     However, it is simpler to assume that if someone is using the
+     same repository, then they will use the same hostname/path to
+     refer to it both times.  Conversely, if the repositories are
+     different, then they can't share a non-empty prefix, so top_url
+     would still be "" and svn_ra_get_library() would still error.
+     Thus we can get this check without extra network turnarounds to
+     fetch the UUIDs.
+   */
+  if (err)
+    {
+      if ((err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
+          && ((top_url == NULL) || (top_url[0] == '\0')))
+        {
+          return svn_error_createf
+            (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+             _("Source and dest appear not to be in the same repository "
+               "(src: '%s'; dst: '%s')"),
+             src_url, dst_url);
+        }
+      else
+        return err;
+    }
+
+  /* Pass NULL for the path, to ensure error if trying to get a
+     revision based on the working copy. */
+  SVN_ERR (svn_client__get_revision_number
+           (&src_revnum, ra_session, src_revision, NULL, pool));
+  
+  /* Fetch the youngest revision. */
+  SVN_ERR (svn_ra_get_latest_revnum (ra_session, &youngest, pool));
+
+  /* Use YOUNGEST for copyfrom args if not provided. */
+  if (! SVN_IS_VALID_REVNUM (src_revnum))
+    src_revnum = youngest;
+  
+  /* Verify that SRC_URL exists in the repository. */
+  SVN_ERR (svn_ra_check_path (ra_session, src_rel, src_revnum, &src_kind,
+                              pool));
+  if (src_kind == svn_node_none)
+    return svn_error_createf 
+      (SVN_ERR_FS_NOT_FOUND, NULL,
+       _("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)
+    {
+      /* 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);
+    }
+
+  /* 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));
+      
+      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 (is_move && (! resurrection))
+        {
+          item = apr_pcalloc (pool, sizeof (*item));
+          item->url = svn_path_join (top_url, src_rel, pool);
+          item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE;
+          (*((svn_client_commit_item_t **) apr_array_push (commit_items))) = 
+            item;
+        }
+      SVN_ERR ((*ctx->log_msg_func) (&message, &tmp_file, commit_items, 
+                                     ctx->log_msg_baton, pool));
+      if (! message)
+        return SVN_NO_ERROR;
+    }
+  else
+    message = "";
+
+
+  /* Fetch RA commit editor. */
+  SVN_ERR (svn_client__commit_get_baton2 (&commit_baton, commit_info, pool));
+  SVN_ERR (svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton, message,
+                                     svn_client__commit_callback2,
+                                     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))
+    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;
+
+  /* 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;
+    }
+
+  /* Close the edit. */
+  SVN_ERR (editor->close_edit (edit_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, 
@@ -744,7 +964,172 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (wc_to_repos_copy2): New version of
     wc_to_repos_copy, which takes svn_client_commit_info2_t as
     commit_info type.
     (wc_to_repos_copy): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   return reconcile_errors (cmt_err, unlock_err, cleanup_err, pool);
 }
 
+static svn_error_t *
+wc_to_repos_copy2 (svn_client_commit_info2_t **commit_info,
+                   const char *src_path, 
+                   const char *dst_url, 
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *pool)
+{
+  const char *anchor, *target, *base_name, *message;
+  svn_ra_session_t *ra_session;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  svn_node_kind_t src_kind, dst_kind;
+  void *commit_baton;
+  apr_hash_t *committables, *tempfiles = NULL;
+  svn_wc_adm_access_t *adm_access, *dir_access;
+  apr_array_header_t *commit_items;
+  svn_error_t *cmt_err = SVN_NO_ERROR;
+  svn_error_t *unlock_err = SVN_NO_ERROR;
+  svn_error_t *cleanup_err = SVN_NO_ERROR;
+  svn_boolean_t commit_in_progress = FALSE;
+  const char *base_path;
+  const char *base_url;
 
+  /* The commit process uses absolute paths, so we need to open the access
+     baton using absolute paths, and so we really need to use absolute
+     paths everywhere. */
+  SVN_ERR (svn_path_get_absolute (&base_path, src_path, pool));
+
+  SVN_ERR (svn_wc_adm_probe_open3 (&adm_access, NULL, base_path,
+                                   FALSE, -1, ctx->cancel_func,
+                                   ctx->cancel_baton, pool));
+
+  /* Split the DST_URL into an anchor and target. */
+  svn_path_split (dst_url, &anchor, &target, pool);
+
+  /* Open an RA session for the anchor URL. */
+  SVN_ERR (svn_client__open_ra_session (&ra_session, anchor,
+                                        svn_wc_adm_access_path (adm_access),
+                                        adm_access, NULL, TRUE, TRUE, 
+                                        ctx, pool));
+
+  /* Figure out the basename that will result from this operation. */
+  SVN_ERR (svn_ra_check_path (ra_session, svn_path_uri_decode (target, pool),
+                               SVN_INVALID_REVNUM, &dst_kind, pool));
+  
+  /* BASE_URL defaults to DST_URL. */
+  base_url = apr_pstrdup (pool, dst_url);
+  if (dst_kind == svn_node_none)
+    {
+      /* DST_URL doesn't exist under its parent URL, so the URL we
+         will be creating is DST_URL. */
+    }
+  else if (dst_kind == svn_node_dir)
+    {
+      /* DST_URL is an existing directory URL.  The URL we will be
+         creating, then, is DST_URL+BASENAME. */
+      svn_path_split (base_path, NULL, &base_name, pool);
+      base_url = svn_path_url_add_component (base_url, base_name, pool);
+    }
+  else
+    {
+      /* DST_URL is an existing file, which can't be overwritten or
+         used as a container, so error out. */
+      return svn_error_createf (SVN_ERR_FS_ALREADY_EXISTS, NULL,
+                                _("File '%s' already exists"), 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;
+
+      commit_items = apr_array_make (pool, 1, sizeof (item));      
+      item = apr_pcalloc (pool, sizeof (*item));
+      item->url = base_url;
+      item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
+      (*((svn_client_commit_item_t **) apr_array_push (commit_items))) = item;
+      
+      SVN_ERR ((*ctx->log_msg_func) (&message, &tmp_file, commit_items, 
+                                     ctx->log_msg_baton, pool));
+      if (! message)
+        return SVN_NO_ERROR;
+    }
+  else
+    message = "";
+
+  /* Crawl the working copy for commit items. */
+  SVN_ERR (svn_io_check_path (base_path, &src_kind, pool));
+  if (src_kind == svn_node_dir)
+     SVN_ERR (svn_wc_adm_retrieve (&dir_access, adm_access, base_path, pool));
+  else
+    dir_access = adm_access;
+  if ((cmt_err = svn_client__get_copy_committables (&committables, 
+                                                    base_url,
+                                                    base_path,
+                                                    dir_access,
+                                                    ctx,
+                                                    pool)))
+    goto cleanup;
+
+  /* ### todo: There should be only one hash entry, which currently
+     has a hacked name until we have the entries files storing
+     canonical repository URLs.  Then, the hacked name can go away and
+     be replaced with a entry->repos (or whereever the entry's
+     canonical repos URL is stored). */
+  if (! ((commit_items = apr_hash_get (committables, 
+                                       SVN_CLIENT__SINGLE_REPOS_NAME, 
+                                       APR_HASH_KEY_STRING))))
+    goto cleanup;
+
+  /* Sort and condense our COMMIT_ITEMS. */
+  if ((cmt_err = svn_client__condense_commit_items (&base_url, 
+                                                    commit_items, 
+                                                    pool)))
+    goto cleanup;
+
+  /* Open an RA session to BASE_URL. */
+  if ((cmt_err = svn_client__open_ra_session (&ra_session, base_url,
+                                              NULL, NULL, commit_items,
+                                              FALSE, FALSE,
+                                              ctx, pool)))
+    goto cleanup;
+
+  /* Fetch RA commit editor. */
+  SVN_ERR (svn_client__commit_get_baton2 (&commit_baton, commit_info, pool));
+  if ((cmt_err = svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton, 
+                                            message,
+                                            svn_client__commit_callback2,
+                                            commit_baton, 
+                                            NULL, TRUE, /* No lock tokens */
+                                            pool)))
+    goto cleanup;
+
+  /* Make a note that we have a commit-in-progress. */
+  commit_in_progress = TRUE;
+
+  /* Perform the commit. */
+  cmt_err = svn_client__do_commit (base_url, commit_items, adm_access,
+                                   editor, edit_baton, 
+                                   0, /* ### any notify_path_offset needed? */
+                                   &tempfiles, ctx, pool);
+
+  commit_in_progress = FALSE;
+
+  /* Sleep to ensure timestamp integrity. */
+  svn_sleep_for_timestamps ();
+
+ cleanup:
+  /* Abort the commit if it is still in progress. */
+  if (commit_in_progress)
+    svn_error_clear (editor->abort_edit (edit_baton, pool));
+
+  /* It's only a read lock, so unlocking is harmless. */
+  unlock_err = svn_wc_adm_close (adm_access);
+
+  /* Remove any outstanding temporary text-base files. */
+  if (tempfiles)
+    cleanup_err = remove_tmpfiles (tempfiles,
+                                   ctx->cancel_func, ctx->cancel_baton,
+                                   pool);
+
+  return reconcile_errors (cmt_err, unlock_err, cleanup_err, pool);
+}
+
+
 static svn_error_t *
 repos_to_wc_copy (const char *src_url,
                   const svn_opt_revision_t *src_revision,
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (setup_copy2): New version of setup_copy, but now takes
     svn_client_commit_info2_t as commit_info type.
     (setup_copy): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -1005,6 +1390,114 @@
 
 
 static svn_error_t *
+setup_copy2 (svn_client_commit_info2_t **commit_info,
+             const char *src_path,
+             const svn_opt_revision_t *src_revision,
+             const char *dst_path,
+             svn_boolean_t is_move,
+             svn_boolean_t force,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *pool)
+{
+  svn_boolean_t src_is_url, dst_is_url;
+
+  /* Are either of our paths URLs? */
+  src_is_url = svn_path_is_url (src_path);
+  dst_is_url = svn_path_is_url (dst_path);
+
+  if (!src_is_url && !dst_is_url
+      && svn_path_is_child (src_path, dst_path, pool))
+    return svn_error_createf
+      (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+       _("Cannot copy path '%s' into its own child '%s'"),
+       svn_path_local_style (src_path, pool),
+       svn_path_local_style (dst_path, pool));
+
+  if (is_move)
+    {
+      if (src_is_url == dst_is_url)
+        {
+          if (strcmp (src_path, dst_path) == 0)
+            return svn_error_createf
+              (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+               _("Cannot move path '%s' into itself"),
+               svn_path_local_style (src_path, pool));
+        }
+      else
+        {
+          /* Disallow moves between the working copy and the repository. */
+          return svn_error_create 
+            (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+             _("No support for repos <--> working copy moves"));
+        }
+    }
+  else
+    {
+      if (!src_is_url)
+        {
+          if (src_revision->kind != svn_opt_revision_unspecified
+              && src_revision->kind != svn_opt_revision_working)
+            {
+              /* We can convert the working copy path to a URL based on the
+                 entries file. */
+              svn_wc_adm_access_t *adm_access;  /* ### FIXME local */
+              const svn_wc_entry_t *entry;
+              SVN_ERR (svn_wc_adm_probe_open3 (&adm_access, NULL,
+                                               src_path, FALSE, 0,
+                                               ctx->cancel_func,
+                                               ctx->cancel_baton, 
+                                               pool));
+              SVN_ERR (svn_wc_entry (&entry, src_path, adm_access, FALSE,
+                                     pool));
+              SVN_ERR (svn_wc_adm_close (adm_access));
+
+              if (! entry)
+                return svn_error_createf
+                  (SVN_ERR_UNVERSIONED_RESOURCE, NULL,
+                   _("'%s' is not under version control"),
+                   svn_path_local_style (src_path, pool));
+
+              if (! entry->url)
+                return svn_error_createf
+                  (SVN_ERR_ENTRY_MISSING_URL, NULL,
+                   _("'%s' does not seem to have a URL associated with it"),
+                   svn_path_local_style (src_path, pool));
+
+              src_path = entry->url;
+              src_is_url = TRUE;
+            }
+        }
+    }
+
+  /* Now, call the right handler for the operation. */
+  if ((! src_is_url) && (! dst_is_url))
+    {
+      SVN_ERR (wc_to_wc_copy (src_path, dst_path,
+                              is_move, force,
+                              ctx,
+                              pool));
+    }
+  else if ((! src_is_url) && (dst_is_url))
+    {
+      SVN_ERR (wc_to_repos_copy2 (commit_info, src_path, dst_path, 
+                                 ctx, pool));
+    }
+  else if ((src_is_url) && (! dst_is_url))
+    {
+      SVN_ERR (repos_to_wc_copy (src_path, src_revision, 
+                                 dst_path, ctx,
+                                 pool));
+    }
+  else
+    {
+      SVN_ERR (repos_to_repos_copy2 (commit_info, src_path, src_revision,
+                                    dst_path, ctx, is_move, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
 setup_copy (svn_client_commit_info_t **commit_info,
             const char *src_path,
             const svn_opt_revision_t *src_revision,
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_copy2): New version of svn_client_copy which now
     takes svn_client_commit_info2_t for the commit_info parameter.
     (svn_client_copy): Deprecated
     (svn_client_move3): New version of svn_client_move2 which now
     takes svn_client_commit_info2_t for the commit_info parameter.
     (svn_client_move2): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -1132,8 +1625,47 @@
                      pool);
 }
 
+/** since v1.3
+  */
+svn_error_t *
+svn_client_copy2 (svn_client_commit_info2_t **commit_info,
+                  const char *src_path,
+                  const svn_opt_revision_t *src_revision,
+                  const char *dst_path,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool)
+{
+  return setup_copy2 (commit_info, 
+                      src_path, src_revision, dst_path,
+                      FALSE /* is_move */,
+                      TRUE /* force, set to avoid deletion check */,
+                      ctx,
+                      pool);
+}
 
+
+/** since 1.3
+  */
 svn_error_t *
+svn_client_move3 (svn_client_commit_info2_t **commit_info,
+                  const char *src_path,
+                  const char *dst_path,
+                  svn_boolean_t force,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool)
+{
+  const svn_opt_revision_t src_revision
+    = { svn_opt_revision_unspecified, { 0 } };
+
+  return setup_copy2 (commit_info,
+                      src_path, &src_revision, dst_path,
+                      TRUE /* is_move */,
+                      force,
+                      ctx,
+                      pool);
+}
+
+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/commit_util.c
===================================================================
--- subversion/libsvn_client/commit_util.c	(revision 14704)
+++ subversion/libsvn_client/commit_util.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_client/commit_util.c
     (commit_baton2): New version of commit_baton using
     svn_client_commit_info2_t for the info type.
     (commit_baton): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -1309,6 +1309,14 @@
   apr_pool_t *pool;
 };
 
+/** @since New in 1.3.
+ * Using svn_client_commit_info2_t
+ */
+struct commit_baton2 {
+  svn_client_commit_info2_t **info;
+  apr_pool_t *pool;
+};
+
 svn_error_t *svn_client__commit_get_baton (void **baton,
                                            svn_client_commit_info_t **info,
                                            apr_pool_t *pool)
@@ -1321,6 +1329,20 @@
   return SVN_NO_ERROR;
 }
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client__commit_get_baton2): New version of
     svn_client__commit_get_baton, which takes svn_client_commit_info2_t
     as the info type
     (svn_client__commit_get_baton): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/**  since v1.3
+  */
+svn_error_t *svn_client__commit_get_baton2 (void **baton,
+                                            svn_client_commit_info2_t **info,
+                                            apr_pool_t *pool)
+{
+  struct commit_baton2 *cb = apr_pcalloc (pool, sizeof (*cb));
+  cb->info = info;
+  cb->pool = pool;
+  *baton = cb;
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *svn_client__commit_callback (svn_revnum_t revision,
                                           const char *date,
                                           const char *author,
@@ -1337,7 +1359,25 @@
   return SVN_NO_ERROR;
 }
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client__commit_callback2): New version of
     svn_client__commit_callback, which takes the post_commit_err
     parameter.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+svn_error_t *svn_client__commit_callback2 (svn_revnum_t revision,
+                                           const char *date,
+                                           const char *author,
+                                           const char *post_commit_err,
+                                           void *baton)
+{
+  struct commit_baton2 *cb = baton;
+  svn_client_commit_info2_t **info = cb->info;
 
+  *info = apr_palloc (cb->pool, sizeof (**info));
+  (*info)->date = date ? apr_pstrdup (cb->pool, date) : NULL;
+  (*info)->author = author ? apr_pstrdup (cb->pool, author) : NULL;
+  (*info)->revision = revision;
+  (*info)->post_commit_err = post_commit_err ? apr_pstrdup (cb->pool, post_commit_err) : NULL;
+
+  return SVN_NO_ERROR;
+}
+
+
 #ifdef SVN_CLIENT_COMMIT_DEBUG
 
 /*** Temporary test editor ***/
Index: subversion/libsvn_client/commit.c
===================================================================
--- subversion/libsvn_client/commit.c	(revision 14704)
+++ subversion/libsvn_client/commit.c	(working copy)
@@ -606,16 +606,226 @@
   
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_client/commit.c
     (get_ra_editor2): New version of get_ra_editor, but is aware of
     the post-commit hook's stderr. Takes svn_client_commit_info2_t
     as parameter and calls svn_client__commit_get_baton2 and
     svn_ra_get_commit_editor2.
     (get_ra_editor): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   /* Fetch RA commit editor. */
   SVN_ERR (svn_client__commit_get_baton (&commit_baton, commit_info, pool));
-  return svn_ra_get_commit_editor (*ra_session, editor, edit_baton, log_msg,
-                                   svn_client__commit_callback,
-                                   commit_baton, lock_tokens, keep_locks,
-                                   pool);
+  return svn_ra_get_commit_editor2 (*ra_session, editor, edit_baton, log_msg,
+                                    svn_client__commit_callback2,
+                                    commit_baton, lock_tokens, keep_locks,
+                                    pool);
 }
 
+/** since v1.3
+  */
+static svn_error_t *
+get_ra_editor2 (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 *base_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_info2_t **commit_info,
+                svn_boolean_t is_commit,
+                apr_hash_t *lock_tokens,
+                svn_boolean_t keep_locks,
+                apr_pool_t *pool)
+{
+  void *commit_baton;
+
+  /* Open an RA session to URL. */
+  SVN_ERR (svn_client__open_ra_session (ra_session,
+                                        base_url, base_dir, base_access,
+                                        commit_items,
+                                        is_commit, !is_commit,
+                                        ctx, pool));
+
+  /* If this is an import (aka, not a commit), we need to verify that
+     our repository URL exists. */
+  if (! is_commit)
+    {
+      svn_node_kind_t kind;
+
+      SVN_ERR (svn_ra_check_path (*ra_session, "", SVN_INVALID_REVNUM,
+                                  &kind, pool));
+      if (kind == svn_node_none)
+        return svn_error_createf (SVN_ERR_FS_NO_SUCH_ENTRY, NULL,
+                                  _("Path '%s' does not exist"),
+                                  base_url);
+    }
+
+  /* Fetch the latest revision if requested. */
+  if (latest_rev)
+    SVN_ERR (svn_ra_get_latest_revnum (*ra_session, latest_rev, pool));
+  
+  /* Fetch RA commit editor. */
+  SVN_ERR (svn_client__commit_get_baton2 (&commit_baton, commit_info, pool));
+  return svn_ra_get_commit_editor2 (*ra_session, editor, edit_baton, log_msg,
+                                    svn_client__commit_callback2,
+                                    commit_baton, lock_tokens, keep_locks,
+                                    pool);
+}
+
 
 /*** Public Interfaces. ***/
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_import2): New version of svn_client_import
     using svn_client_commit_info2_t for the commit_info parameter.
     This new function is post-commit hook's stderr aware.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 svn_error_t *
+svn_client_import2 (svn_client_commit_info2_t **commit_info,
+                    const char *path,
+                    const char *url,
+                    svn_boolean_t nonrecursive,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *pool)
+{
+  svn_error_t *err = SVN_NO_ERROR;
+  const char *log_msg = "";
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  svn_ra_session_t *ra_session;
+  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_pool_t *subpool;
+
+  /* Create a new commit item and add it to the array. */
+  if (ctx->log_msg_func)
+    {
+      /* If there's a log message gatherer, create a temporary commit
+         item array solely to help generate the log message.  The
+         array is not used for the import itself. */
+      svn_client_commit_item_t *item;
+      const char *tmp_file;
+      apr_array_header_t *commit_items 
+        = apr_array_make (pool, 1, sizeof (item));
+      
+      item = apr_pcalloc (pool, sizeof (*item));
+      item->path = apr_pstrdup (pool, path);
+      item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
+      (*((svn_client_commit_item_t **) apr_array_push (commit_items))) = item;
+      
+      SVN_ERR ((*ctx->log_msg_func) (&log_msg, &tmp_file, commit_items, 
+                                     ctx->log_msg_baton, pool));
+      if (! log_msg)
+        return SVN_NO_ERROR;
+      if (tmp_file)
+        {
+          const char *abs_path;
+          SVN_ERR (svn_path_get_absolute (&abs_path, tmp_file, pool));
+          apr_hash_set (excludes, abs_path, APR_HASH_KEY_STRING, (void *)1);
+        }
+    }
+
+  SVN_ERR (svn_io_check_path (path, &kind, pool));
+  if (kind == svn_node_file)
+    svn_path_split (path, &base_dir, NULL, pool);
+
+  /* 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);
+
+      /* 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_editor2 (&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. */
+  if (kind == svn_node_file && (! new_entries->nelts))
+    return svn_error_createf
+      (SVN_ERR_ENTRY_EXISTS, NULL,
+       _("Path '%s' already exists"), url);
+
+  /* The repository doesn't know about the reserved administrative
+     directory. */
+  if (new_entries->nelts && 
+      (strcmp (APR_ARRAY_IDX (new_entries, 
+                              new_entries->nelts - 1, 
+                              const char *), SVN_WC_ADM_DIR_NAME) == 0))
+    return svn_error_createf
+      (SVN_ERR_CL_ADM_DIR_RESERVED, NULL,
+       _("'%s' is a reserved name and cannot be imported"),
+       /* ### Is svn_path_local_style() really necessary for this? */
+       svn_path_local_style (SVN_WC_ADM_DIR_NAME, pool));
+
+
+  /* If an error occurred during the commit, abort the edit and return
+     the error.  We don't even care if the abort itself fails.  */
+  if ((err = import (path, new_entries, editor, edit_baton, 
+                     nonrecursive, excludes, ctx, subpool)))
+    {
+      svn_error_clear (editor->abort_edit (edit_baton, subpool));
+      return err;
+    }
+
+  /* Transfer *COMMIT_INFO from the subpool to the callers pool */
+  if (*commit_info)
+    {
+      svn_client_commit_info2_t *tmp_commit_info;
+
+      tmp_commit_info = apr_palloc(pool, sizeof(*tmp_commit_info));
+      *tmp_commit_info = **commit_info;
+      if (tmp_commit_info->date)
+        tmp_commit_info->date = apr_pstrdup (pool, tmp_commit_info->date);
+      if (tmp_commit_info->author)
+        tmp_commit_info->author = apr_pstrdup (pool, tmp_commit_info->author);
+      if (tmp_commit_info->post_commit_err)
+        tmp_commit_info->post_commit_err
+          = apr_pstrdup (pool, tmp_commit_info->post_commit_err);
+      *commit_info = tmp_commit_info;
+    }
+
+  svn_pool_destroy (subpool);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client_import (svn_client_commit_info_t **commit_info,
                    const char *path,
                    const char *url,
@@ -1594,6 +1804,465 @@
 }
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_commit3): New version of svn_client_commit
     using svn_client_commit_info2_t, and calling other functions
     that passback the post-commit hook's stderr.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 svn_error_t *
+svn_client_commit3 (svn_client_commit_info2_t **commit_info,
+                    const apr_array_header_t *targets,
+                    svn_boolean_t recurse,
+                    svn_boolean_t keep_locks,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *pool)
+{
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  svn_ra_session_t *ra_session;
+  const char *log_msg;
+  const char *base_dir;
+  const char *base_url;
+  const char *target;
+  apr_array_header_t *rel_targets;
+  apr_array_header_t *dirs_to_lock;
+  apr_array_header_t *dirs_to_lock_recursive;
+  svn_boolean_t lock_base_dir_recursive = FALSE;
+  apr_hash_t *committables, *lock_tokens, *tempfiles = NULL;
+  svn_wc_adm_access_t *base_dir_access;
+  apr_array_header_t *commit_items;
+  svn_error_t *cmt_err = SVN_NO_ERROR, *unlock_err = SVN_NO_ERROR;
+  svn_error_t *bump_err = SVN_NO_ERROR, *cleanup_err = SVN_NO_ERROR;
+  svn_boolean_t commit_in_progress = FALSE;
+  const char *display_dir = "";
+  int i;
+
+  /* Committing URLs doesn't make sense, so error if it's tried. */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      target = APR_ARRAY_IDX (targets, i, const char *);
+      if (svn_path_is_url (target))
+        return svn_error_createf
+          (SVN_ERR_ILLEGAL_TARGET, NULL,
+           _("'%s' is a URL, but URLs cannot be commit targets"), target);
+    }
+
+  /* Condense the target list. */
+  SVN_ERR (svn_path_condense_targets (&base_dir, &rel_targets, targets,
+                                      recurse, pool));
+
+  /* No targets means nothing to commit, so just return. */
+  if (! base_dir)
+    return SVN_NO_ERROR;
+
+  /* Prepare an array to accumulate dirs to lock */
+  dirs_to_lock = apr_array_make (pool, 1, sizeof (target));
+  dirs_to_lock_recursive = apr_array_make (pool, 1, sizeof (target));
+
+  /* If we calculated only a base_dir and no relative targets, this
+     must mean that we are being asked to commit (effectively) a
+     single path. */
+  if ((! rel_targets) || (! rel_targets->nelts))
+    {
+      const char *parent_dir, *name;
+
+      SVN_ERR (svn_wc_get_actual_target (base_dir, &parent_dir, &name, pool));
+      if (*name)
+        {
+          svn_node_kind_t kind;
+
+          /* Our new "grandfather directory" is the parent directory
+             of the former one. */
+          base_dir = apr_pstrdup (pool, parent_dir);
+
+          /* Make the array if it wasn't already created. */
+          if (! rel_targets)
+            rel_targets = apr_array_make (pool, targets->nelts, sizeof (name));
+
+          /* Now, push this name as a relative path to our new
+             base directory. */
+          APR_ARRAY_PUSH (rel_targets, const char *) = name;
+
+          target = svn_path_join (base_dir, name, pool);
+          SVN_ERR (svn_io_check_path (target, &kind, pool));
+
+          /* If the final target is a dir, we want to recursively lock it */
+          if (kind == svn_node_dir)
+            {
+              if (recurse)
+                APR_ARRAY_PUSH (dirs_to_lock_recursive, const char *) = target;
+              else
+                APR_ARRAY_PUSH (dirs_to_lock, const char *) = target;
+            }
+        }
+      else
+        {
+          /* This will recursively lock the base_dir further down */
+          lock_base_dir_recursive = TRUE;
+        }
+    }
+  else
+    {
+      apr_pool_t *subpool = svn_pool_create (pool);
+
+      SVN_ERR (adjust_rel_targets (&base_dir, &rel_targets,
+                                   base_dir, rel_targets,
+                                   pool));
+
+      for (i = 0; i < rel_targets->nelts; i++)
+        {
+          const char *parent_dir, *name;
+
+          svn_pool_clear (subpool);
+          target = svn_path_join (base_dir,
+                                  APR_ARRAY_IDX (rel_targets, i, const char *),
+                                  subpool);
+          SVN_ERR (svn_wc_get_actual_target (target, &parent_dir, 
+                                             &name, subpool));
+
+          if (*name)
+            {
+              svn_node_kind_t kind;
+
+              target = svn_path_join (parent_dir, name, subpool);
+          
+              SVN_ERR (svn_io_check_path (target, &kind, subpool));
+
+              /* If the final target is a dir, we want to recursively
+                 lock it */
+              if (kind == svn_node_dir)
+                {
+                  if (recurse)
+                    APR_ARRAY_PUSH (dirs_to_lock_recursive, 
+                                    const char *) = apr_pstrdup (pool, target);
+                  else
+                    APR_ARRAY_PUSH (dirs_to_lock, 
+                                    const char *) = apr_pstrdup (pool, target);
+                }
+            }
+
+          target = parent_dir;
+          while (strcmp (target, base_dir))
+            {
+              if (target[0] == '/' && target[1] == '\0')
+                abort();
+
+              APR_ARRAY_PUSH (dirs_to_lock,
+                              const char *) = apr_pstrdup (pool, target);
+              target = svn_path_dirname(target, subpool);
+            }
+        }
+      svn_pool_destroy (subpool);
+    }
+
+  SVN_ERR (svn_wc_adm_open3 (&base_dir_access, NULL, base_dir,
+                             TRUE,  /* Write lock */
+                             lock_base_dir_recursive ? -1 : 0, /* Depth */
+                             ctx->cancel_func, ctx->cancel_baton,
+                             pool));
+
+  if (!lock_base_dir_recursive)
+    {
+      svn_wc_adm_access_t *adm_access;
+      apr_array_header_t *unique_dirs_to_lock;
+
+      /* Sort the paths in a depth-last directory-ish order. */
+      qsort (dirs_to_lock->elts, dirs_to_lock->nelts,
+             dirs_to_lock->elt_size, svn_sort_compare_paths);
+      qsort (dirs_to_lock_recursive->elts, dirs_to_lock_recursive->nelts,
+             dirs_to_lock_recursive->elt_size, svn_sort_compare_paths);
+
+      /* Remove any duplicates */
+      SVN_ERR (svn_path_remove_redundancies (&unique_dirs_to_lock,
+                                             dirs_to_lock_recursive,
+                                             pool));
+      dirs_to_lock_recursive = unique_dirs_to_lock;
+
+      /* Remove dirs and descendants from dirs_to_lock if there is
+         any ancestor in dirs_to_lock_recursive */
+      SVN_ERR (remove_redundancies (&unique_dirs_to_lock,
+                                    dirs_to_lock,
+                                    dirs_to_lock_recursive,
+                                    pool));
+      dirs_to_lock = unique_dirs_to_lock;
+
+      /* First lock all the dirs to be locked non-recursively */
+      if (dirs_to_lock)
+        {
+          for (i = 0; i < dirs_to_lock->nelts ; ++i)
+            {
+              target = APR_ARRAY_IDX (dirs_to_lock, i, const char *);
+
+              SVN_ERR (svn_wc_adm_open3 (&adm_access, base_dir_access,
+                                         target,
+                                         TRUE,  /* Write lock */
+                                         0,     /* Depth */
+                                         ctx->cancel_func,
+                                         ctx->cancel_baton,
+                                         pool));
+            }
+        }
+
+      /* Lock the rest of the targets (recursively) */
+      if (dirs_to_lock_recursive)
+        {
+          for (i = 0; i < dirs_to_lock_recursive->nelts ; ++i)
+            {
+              target = APR_ARRAY_IDX (dirs_to_lock_recursive, i, const char *);
+
+              SVN_ERR (svn_wc_adm_open3 (&adm_access, base_dir_access,
+                                         target,
+                                         TRUE, /* Write lock */
+                                         -1,   /* Depth */
+                                         ctx->cancel_func,
+                                         ctx->cancel_baton,
+                                         pool));
+            }
+        }
+    }
+
+  /* One day we might support committing from multiple working copies, but
+     we don't yet.  This check ensures that we don't silently commit a
+     subset of the targets.
+
+     At the same time, if a non-recursive commit is desired, do not
+     allow a deleted directory as one of the targets. */
+  for (i = 0; i < targets->nelts; ++i)
+    {
+      svn_wc_adm_access_t *adm_access;
+
+      SVN_ERR (svn_path_get_absolute (&target,
+                                      APR_ARRAY_IDX (targets, i, const char *),
+                                      pool));
+      SVN_ERR_W (svn_wc_adm_probe_retrieve (&adm_access, base_dir_access,
+                                            target, pool),
+                 _("Are all the targets part of the same working copy?"));
+
+      if (!recurse)
+        {
+          svn_wc_status2_t *status;
+          svn_node_kind_t kind;
+          
+          SVN_ERR (svn_io_check_path (target, &kind, pool));
+
+          if (kind == svn_node_dir)
+            {
+              SVN_ERR (svn_wc_status2 (&status, target, adm_access, pool));
+              if (status->text_status == svn_wc_status_deleted ||
+                  status->text_status == svn_wc_status_replaced)
+                return svn_error_create (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                                         _("Cannot non-recursively commit a "
+                                           "directory deletion"));
+            }
+        }
+    }
+
+  /* Crawl the working copy for commit items. */
+  if ((cmt_err = svn_client__harvest_committables (&committables,
+                                                   &lock_tokens,
+                                                   base_dir_access,
+                                                   rel_targets, 
+                                                   recurse ? FALSE : TRUE,
+                                                   ! keep_locks,
+                                                   ctx,
+                                                   pool)))
+    goto cleanup;
+
+  /* ### todo: Currently there should be only one hash entry, which
+     has a hacked name until we have the entries files storing
+     canonical repository URLs.  Then, the hacked name can go away
+     and be replaced with a canonical repos URL, and from there we
+     are poised to started handling nested working copies.  See
+     http://subversion.tigris.org/issues/show_bug.cgi?id=960. */
+  if (! ((commit_items = apr_hash_get (committables,
+                                       SVN_CLIENT__SINGLE_REPOS_NAME, 
+                                       APR_HASH_KEY_STRING))))
+    goto cleanup;
+
+  /* If our array of targets contains only locks (and no actual file
+     or prop modifications), then we return here to avoid committing a
+     revision with no changes. */
+  {
+    svn_boolean_t found_changed_path = FALSE;
+
+    for (i = 0; i < commit_items->nelts; ++i)
+      {
+        svn_client_commit_item_t *item;
+        item = APR_ARRAY_IDX (commit_items, i, svn_client_commit_item_t *);
+        
+        if (item->state_flags != SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN) 
+          {
+            found_changed_path = TRUE;
+            break;
+          }
+      }
+
+    if (!found_changed_path)
+      goto cleanup;
+  }
+
+  /* Go get a log message.  If an error occurs, or no log message is
+     specified, abort the operation. */
+  if (ctx->log_msg_func)
+    {
+      const char *tmp_file;
+      cmt_err = (*ctx->log_msg_func)(&log_msg, &tmp_file, commit_items, 
+                                     ctx->log_msg_baton, pool);
+      if (cmt_err || (! log_msg))
+        goto cleanup;
+    }
+  else
+    log_msg = "";
+
+  /* Sort and condense our COMMIT_ITEMS. */
+  if ((cmt_err = svn_client__condense_commit_items (&base_url,
+                                                    commit_items,
+                                                    pool)))
+    goto cleanup;
+
+  /* Collect our lock tokens with paths relative to base_url. */
+  if ((cmt_err = collect_lock_tokens (&lock_tokens, lock_tokens, base_url,
+                                      pool)))
+    goto cleanup;
+
+  if ((cmt_err = get_ra_editor2 (&ra_session, NULL,
+                                 &editor, &edit_baton, ctx,
+                                 base_url, base_dir, base_dir_access,
+                                 log_msg, commit_items, commit_info,
+                                 TRUE, lock_tokens, keep_locks, pool)))
+    goto cleanup;
+
+  /* Make a note that we have a commit-in-progress. */
+  commit_in_progress = TRUE;
+
+  /* Determine prefix to strip from the commit notify messages */
+  if ((cmt_err = svn_path_get_absolute (&display_dir,
+                                        display_dir, pool)))
+    goto cleanup;
+  display_dir = svn_path_get_longest_ancestor (display_dir, base_dir, pool);
+
+  /* Perform the commit. */
+  cmt_err = svn_client__do_commit (base_url, commit_items, base_dir_access,
+                                   editor, edit_baton, 
+                                   display_dir,
+                                   &tempfiles, ctx, pool);
+
+  /* Handle a successful commit. */
+  if ((! cmt_err)
+      || (cmt_err->apr_err == SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED))
+    {
+      apr_pool_t *subpool = svn_pool_create (pool);
+
+      /* Make a note that our commit is finished. */
+      commit_in_progress = FALSE;
+
+      for (i = 0; i < commit_items->nelts; i++)
+        {
+          svn_client_commit_item_t *item
+            = ((svn_client_commit_item_t **) commit_items->elts)[i];
+          svn_boolean_t loop_recurse = FALSE;
+          const char *adm_access_path;
+          svn_wc_adm_access_t *adm_access;
+          const svn_wc_entry_t *entry;
+          svn_boolean_t remove_lock;
+
+          /* Clear the subpool here because there are some 'continue'
+             statements in this loop. */
+          svn_pool_clear (subpool);
+
+          if (item->kind == svn_node_dir)
+            adm_access_path = item->path;
+          else
+            svn_path_split (item->path, &adm_access_path, NULL, subpool);
+
+          bump_err = svn_wc_adm_retrieve (&adm_access, base_dir_access,
+                                          adm_access_path, subpool);
+          if (bump_err)
+            {
+              if (bump_err->apr_err == SVN_ERR_WC_NOT_LOCKED)
+                {
+                  if (have_processed_parent (commit_items, i,
+                                             item->path, subpool))
+                    {
+                      /* This happens when the item is a directory that is
+                         deleted, and it has been processed as a child of an
+                         earlier item. */
+                      svn_error_clear (bump_err);
+                      bump_err = SVN_NO_ERROR;
+                      continue;
+                    }
+
+                  /* Is it a directory that was deleted in the commit? */
+                  if (item->kind == svn_node_dir
+                      && item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
+                    {
+                      /* It better be missing then.  Assuming it is,
+                         mark as deleted in parent.  If not, then
+                         something is way bogus. */
+                      svn_error_clear (bump_err);
+                      bump_err = svn_wc_mark_missing_deleted (item->path,
+                                                              base_dir_access,
+                                                              subpool);
+                      if (bump_err)
+                        goto cleanup;
+                      continue;                      
+                    }                  
+                }
+              goto cleanup;              
+            }
+          if ((bump_err = svn_wc_entry (&entry, item->path, adm_access, TRUE,
+                                        subpool)))
+            goto cleanup;
+
+          if (! entry
+              && have_processed_parent (commit_items, i, item->path, subpool))
+            /* This happens when the item is a file that is deleted, and it
+               has been processed as a child of an earlier item. */
+            continue;
+
+          if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD) 
+              && (item->kind == svn_node_dir)
+              && (item->copyfrom_url))
+            loop_recurse = TRUE;
+
+          remove_lock = (! keep_locks && (item->state_flags
+                                          & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN));
+          assert (*commit_info);
+          if ((bump_err = svn_wc_process_committed2 (item->path, adm_access,
+                                                     loop_recurse,
+                                                     (*commit_info)->revision,
+                                                     (*commit_info)->date,
+                                                     (*commit_info)->author,
+                                                     item->wcprop_changes,
+                                                     remove_lock,
+                                                     subpool)))
+            break;
+
+        }
+
+      /* Destroy the subpool. */
+      svn_pool_destroy (subpool);
+    }
+
+  /* Sleep to ensure timestamp integrity. */
+  svn_sleep_for_timestamps ();
+
+ cleanup:
+  /* Abort the commit if it is still in progress. */
+  if (commit_in_progress)
+    svn_error_clear (editor->abort_edit (edit_baton, pool));
+
+  /* A bump error is likely to occur while running a working copy log file,
+     explicitly unlocking and removing temporary files would be wrong in
+     that case.  A commit error (cmt_err) should only occur before any
+     attempt to modify the working copy, so it doesn't prevent explicit
+     clean-up. */
+  if (! bump_err)
+    {
+      unlock_err = svn_wc_adm_close (base_dir_access);
+
+      if (! unlock_err)
+        cleanup_err = remove_tmpfiles (tempfiles, pool);
+    }
+
+  return reconcile_errors (cmt_err, unlock_err, bump_err, cleanup_err, pool);
+}
+
+svn_error_t *
 svn_client_commit (svn_client_commit_info_t **commit_info,
                    const apr_array_header_t *targets,
                    svn_boolean_t nonrecursive,
Index: subversion/libsvn_client/add.c
===================================================================
--- subversion/libsvn_client/add.c	(revision 14704)
+++ subversion/libsvn_client/add.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_client/add.c
     (mkdir_urls2): New version of mkdir_urls. Here, the commit_info 
     parameter is of type svn_client_commit_info2_t and calls the 
     svn_client__commit_get_baton2 and svn_ra_get_commit_editor2, thus
     making this aware of the post-commit hook's stderr.
     (mkdir_urls): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -601,8 +601,174 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+mkdir_urls2 (svn_client_commit_info2_t **commit_info,
+             const apr_array_header_t *paths,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *pool)
+{
+  svn_ra_session_t *ra_session;
+  const svn_delta_editor_t *editor;
+  void *edit_baton;
+  void *commit_baton;
+  const char *log_msg;
+  apr_array_header_t *targets;
+  svn_error_t *err;
+  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)
+    {
+      const char *bname;
+      svn_path_split (common, &common, &bname, pool);
+      APR_ARRAY_PUSH (targets, const char *) = bname;
+    }
+  else
+    {
+      svn_boolean_t resplit = FALSE;
+
+      /* 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++)
+        {
+          const char *path = APR_ARRAY_IDX (targets, i, const char *);
+          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;
+            }
+        }
+    }
+
+  /* Create new commit items and add them 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, targets->nelts, sizeof (item));
+          
+      for (i = 0; i < targets->nelts; i++)
+        {
+          const char *path = APR_ARRAY_IDX (targets, i, const char *);
+          item = apr_pcalloc (pool, sizeof (*item));
+          item->url = svn_path_join (common, path, pool);
+          item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
+          APR_ARRAY_PUSH (commit_items, svn_client_commit_item_t *) = item;
+        }
+      SVN_ERR ((*ctx->log_msg_func) (&log_msg, &tmp_file, commit_items, 
+                                     ctx->log_msg_baton, pool));
+      if (! log_msg)
+        return SVN_NO_ERROR;
+    }
+  else
+    log_msg = "";
+
+  /* Open an RA session for the URL. Note that we don't have a local
+     directory, nor a place to put temp files. */
+  SVN_ERR (svn_client__open_ra_session (&ra_session, common, NULL,
+                                        NULL, NULL, FALSE, TRUE,
+                                        ctx, pool));
+
+  /* URI-decode each target. */
+  for (i = 0; i < targets->nelts; i++)
+    {
+      const char *path = APR_ARRAY_IDX (targets, i, const char *);
+      path = svn_path_uri_decode (path, pool);
+      APR_ARRAY_IDX (targets, i, const char *) = path;
+    }
+
+  /* Fetch RA commit editor */
+  SVN_ERR (svn_client__commit_get_baton2 (&commit_baton, commit_info, pool));
+  SVN_ERR (svn_ra_get_commit_editor2 (ra_session, &editor, &edit_baton,
+                                      log_msg, svn_client__commit_callback2,
+                                      commit_baton, 
+                                      NULL, TRUE, /* No lock tokens */
+                                      pool));
+  
+  /* Call the path-based editor driver. */
+  err = svn_delta_path_driver (editor, edit_baton, SVN_INVALID_REVNUM, 
+                               targets, path_driver_cb_func, 
+                               (void *)editor, 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;
+    }
+
+  /* Close the edit. */
+  SVN_ERR (editor->close_edit (edit_baton, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_client_mkdir2): New version of svn_client_mkdir
     using svn_client_commit_info2_t for the commit_info parameter
     (svn_client_mkdir): Deprecated
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 svn_error_t *
+svn_client_mkdir2 (svn_client_commit_info2_t **commit_info,
+                   const apr_array_header_t *paths,
+                   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_urls2 (commit_info, paths, 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_add (path, FALSE, 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_destroy (subpool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client_mkdir (svn_client_commit_info_t **commit_info,
                   const apr_array_header_t *paths,
                   svn_client_ctx_t *ctx,
Index: subversion/mod_dav_svn/merge.c
===================================================================
--- subversion/mod_dav_svn/merge.c	(revision 14704)
+++ subversion/mod_dav_svn/merge.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/mod_dav_svn/merge.c
     (svn_xml.h): New header #included.
     (dav_svn__merge_response2): Takes the @a post_commit_err parameter
     and forms necessary xml content, if this parameter is NOT NULL.
     (dav_svn__merge_response): Deprecated, modified to call
     dav_svn__merge_response2, with the @a post_commit_err as NULL.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -29,6 +29,7 @@
 #include "svn_props.h"
 
 #include "dav_svn.h"
+#include "svn_xml.h"
 
 
 /* #################################################################
@@ -197,18 +198,32 @@
    PUBLIC FUNCTIONS
 */
 
-dav_error * dav_svn__merge_response(ap_filter_t *output,
+dav_error * dav_svn__merge_response (ap_filter_t *output,
                                     const dav_svn_repos *repos,
                                     svn_revnum_t new_rev,
                                     apr_xml_elem *prop_elem,
                                     svn_boolean_t disable_merge_response,
                                     apr_pool_t *pool)
 {
+  return dav_svn__merge_response2 (output, repos, new_rev, NULL,
+                                   prop_elem, disable_merge_response,
+                                   pool);
+}
+
+dav_error * dav_svn__merge_response2 (ap_filter_t *output,
+                                     const dav_svn_repos *repos,
+                                     svn_revnum_t new_rev,
+                                     char *post_commit_err,
+                                     apr_xml_elem *prop_elem,
+                                     svn_boolean_t disable_merge_response,
+                                     apr_pool_t *pool)
+{
   apr_bucket_brigade *bb;
   svn_fs_root_t *root;
   svn_error_t *serr;
   const char *vcc;
   const char *rev;
+  const char *post_commit_err_elem, *post_commit_header_info;
   svn_string_t *creationdate, *creator_displayname;
 
   serr = svn_fs_revision_root(&root, repos->fs, new_rev, pool);
@@ -231,6 +246,23 @@
   /* the version-name of the baseline is the revision number */
   rev = apr_psprintf(pool, "%ld", new_rev);
 
+  /* get the post-commit hook stderr, if any */
+  if (post_commit_err)
+    {
+      post_commit_header_info = apr_psprintf (pool,
+                                              " xmlns:S=\"%s\"",
+                                              SVN_XML_NAMESPACE);
+      post_commit_err_elem = apr_psprintf (pool,
+                                           "<S:post-commit-err>%s"
+                                           "</S:post-commit-err>",
+                                           post_commit_err);
+    }
+  else
+    {
+      post_commit_header_info = "" ;
+      post_commit_err_elem = "" ;
+    }
+
   /* get the creationdate and creator-displayname of the new revision, too. */
   serr = svn_fs_revision_prop(&creationdate, repos->fs, new_rev,
                               SVN_PROP_REVISION_DATE, pool);
@@ -252,7 +284,9 @@
 
   (void) ap_fputstrs(output, bb,
                      DAV_XML_HEADER DEBUG_CR
-                     "<D:merge-response xmlns:D=\"DAV:\">" DEBUG_CR
+                     "<D:merge-response xmlns:D=\"DAV:\"",
+                     post_commit_header_info,
+                     ">" DEBUG_CR
                      "<D:updated-set>" DEBUG_CR
 
                      /* generate a response for the new baseline */
@@ -264,7 +298,8 @@
                      /* ### this is wrong. it's a VCC, not a baseline. but
                         ### we need to tell the client to look at *this*
                         ### resource for the version-name. */
-                     "<D:resourcetype><D:baseline/></D:resourcetype>" DEBUG_CR
+                     "<D:resourcetype><D:baseline/></D:resourcetype>" DEBUG_CR,
+                     post_commit_err_elem, DEBUG_CR
                      "<D:version-name>", rev, "</D:version-name>" DEBUG_CR,
                      NULL);
   if (creationdate)
Index: subversion/mod_dav_svn/dav_svn.h
===================================================================
--- subversion/mod_dav_svn/dav_svn.h	(revision 14704)
+++ subversion/mod_dav_svn/dav_svn.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/mod_dav_svn/dav_svn.h
     (dav_svn__merge_response2): New version of dav_svn__merge_response
     that takes the post_commit_err parameter
     (dav_svn__merge_response): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -503,6 +503,16 @@
                                     apr_xml_elem *prop_elem,
                                     svn_boolean_t disable_merge_response,
                                     apr_pool_t *pool);
+/** @since New in 1.3.
+ * v2. To accomodate post-commit hook's stderr
+ */
+dav_error * dav_svn__merge_response2(ap_filter_t *output,
+                                     const dav_svn_repos *repos,
+                                     svn_revnum_t new_rev,
+                                     char *post_commit_err,
+                                     apr_xml_elem *prop_elem,
+                                     svn_boolean_t disable_merge_response,
+                                     apr_pool_t *pool);
 
 dav_error * dav_svn__update_report(const dav_resource *resource,
                                    const apr_xml_doc *doc,
Index: subversion/mod_dav_svn/version.c
===================================================================
--- subversion/mod_dav_svn/version.c	(revision 14704)
+++ subversion/mod_dav_svn/version.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/mod_dav_svn/version.c
     (dav_svn_merge): Modified to handle the post-commit hook's stderr,
     if any and call the dav_svn__merge_response2 function to pass it on.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -1619,6 +1619,7 @@
   svn_fs_txn_t *txn;
   const char *conflict;
   svn_error_t *serr;
+  char *post_commit_err = NULL ;
   svn_revnum_t new_rev;
   apr_hash_t *locks;
   svn_boolean_t disable_merge_response = FALSE;
@@ -1699,7 +1700,11 @@
       return dav_svn_convert_err(serr, HTTP_CONFLICT, msg, pool);
     }
   else if (serr)
-    svn_error_clear(serr);
+    {
+      if (serr->child->message)
+        post_commit_err = apr_pstrdup (pool, serr->child->message);
+      svn_error_clear(serr);
+    }
 
   /* Commit was successful, so schedule deltification. */
   register_deltification_cleanup(source->info->repos->repos, new_rev,
@@ -1739,8 +1744,9 @@
     }
 
   /* process the response for the new revision. */
-  return dav_svn__merge_response(output, source->info->repos, new_rev,
-                                 prop_elem, disable_merge_response, pool);
+  return dav_svn__merge_response2 (output, source->info->repos, new_rev,
+                                   post_commit_err, prop_elem, 
+                                   disable_merge_response, pool);
 }
 
 const dav_hooks_vsn dav_svn_hooks_vsn = {
Index: subversion/clients/cmdline/cl.h
===================================================================
--- subversion/clients/cmdline/cl.h	(revision 14704)
+++ subversion/clients/cmdline/cl.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/cl.h
     (svn_cl__print_commit_info2): New version of svn_cl__print_commit_info
     which takes svn_client_commit_info2_t for the commit_info parameter.
     (svn_cl__print_commit_info): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -234,7 +234,13 @@
 svn_error_t *svn_cl__print_commit_info (svn_client_commit_info_t *commit_info,
                                         apr_pool_t *pool);
 
+/** since v1.3
+  * using svn_client_commit_info2_t
+  */
+svn_error_t *svn_cl__print_commit_info2 (svn_client_commit_info2_t *commit_info,
+                                         apr_pool_t *pool);
 
+
 /* Print STATUS for PATH to stdout for human consumption.  Prints in
    abbreviated format by default, or DETAILED format if flag is set.
 
Index: subversion/clients/cmdline/mkdir-cmd.c
===================================================================
--- subversion/clients/cmdline/mkdir-cmd.c	(revision 14704)
+++ subversion/clients/cmdline/mkdir-cmd.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/mkdir-cmd.c
     (svn_cl__mkdir): Modified to use post-commit stderr aware
     datatypes and functions.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -43,7 +43,7 @@
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
   apr_pool_t *subpool = svn_pool_create (pool);
-  svn_client_commit_info_t *commit_info = NULL;
+  svn_client_commit_info2_t *commit_info = NULL;
   svn_error_t *err;
 
   SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, 
@@ -72,7 +72,7 @@
                                            NULL, ctx->config, subpool));
     }
 
-  err = svn_client_mkdir (&commit_info, targets, ctx, subpool);
+  err = svn_client_mkdir2 (&commit_info, targets, ctx, subpool);
 
   if (ctx->log_msg_func)
     err = svn_cl__cleanup_log_msg (ctx->log_msg_baton, err);
@@ -87,7 +87,7 @@
     }
 
   if (commit_info && ! opt_state->quiet)
-    SVN_ERR (svn_cl__print_commit_info (commit_info, subpool));
+    SVN_ERR (svn_cl__print_commit_info2 (commit_info, subpool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/move-cmd.c
===================================================================
--- subversion/clients/cmdline/move-cmd.c	(revision 14704)
+++ subversion/clients/cmdline/move-cmd.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/move-cmd.c
     (svn_cl__move): Modified to use post-commit stderr aware
     datatypes and functions.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -42,7 +42,7 @@
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
   const char *src_path, *dst_path;
-  svn_client_commit_info_t *commit_info = NULL;
+  svn_client_commit_info2_t *commit_info = NULL;
   svn_error_t *err;
 
   SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, 
@@ -69,7 +69,7 @@
          _("Cannot specify revisions (except HEAD) with move operations"));
     }
 
-  err = svn_client_move2 (&commit_info, src_path, dst_path,
+  err = svn_client_move3 (&commit_info, src_path, dst_path,
                           opt_state->force, ctx, pool);
 
   if (err)
@@ -77,7 +77,7 @@
   SVN_ERR (svn_cl__cleanup_log_msg (ctx->log_msg_baton, err));
 
   if (commit_info && ! opt_state->quiet)
-    SVN_ERR (svn_cl__print_commit_info (commit_info, pool));
+    SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/copy-cmd.c
===================================================================
--- subversion/clients/cmdline/copy-cmd.c	(revision 14704)
+++ subversion/clients/cmdline/copy-cmd.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/copy-cmd.c
     (svn_cl__copy): Modified to use post-commit stderr aware
     datatypes and functions.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -43,7 +43,7 @@
   apr_array_header_t *targets;
   const char *src_path, *dst_path;
   svn_boolean_t src_is_url, dst_is_url;
-  svn_client_commit_info_t *commit_info = NULL;
+  svn_client_commit_info2_t *commit_info = NULL;
   svn_error_t *err;
 
   SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, 
@@ -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,
-                         &(opt_state->start_revision),
-                         dst_path, ctx, pool);
+  err = svn_client_copy2 (&commit_info, src_path,
+                          &(opt_state->start_revision),
+                          dst_path, ctx, pool);
 
   if (ctx->log_msg_func)
     SVN_ERR (svn_cl__cleanup_log_msg (ctx->log_msg_baton, err));
@@ -120,7 +120,7 @@
     return err;
 
   if (commit_info && ! opt_state->quiet)
-    SVN_ERR (svn_cl__print_commit_info (commit_info, pool));
+    SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/util.c
===================================================================
--- subversion/clients/cmdline/util.c	(revision 14704)
+++ subversion/clients/cmdline/util.c	(working copy)
@@ -60,7 +60,24 @@
   return SVN_NO_ERROR;
 }
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/util.c
     (svn_cl__print_commit_info2): New version of svn_cl__print_commit_info
     that displays the post-commit hook's stderr, if any.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
+svn_error_t *
+svn_cl__print_commit_info2 (svn_client_commit_info2_t *commit_info,
+                            apr_pool_t *pool)
+{
+  if ((commit_info) 
+      && (SVN_IS_VALID_REVNUM (commit_info->revision)))
+    SVN_ERR (svn_cmdline_printf (pool, _("\nCommitted revision %ld.\n"),
+                                 commit_info->revision));
 
+  if ((commit_info) 
+      && (commit_info->post_commit_err))
+    SVN_ERR (svn_cmdline_printf (pool, _("\nWARNING:\n%s\n"),
+                                 commit_info->post_commit_err));
+
+  return SVN_NO_ERROR;
+}
+
+
 svn_error_t *
 svn_cl__edit_externally (svn_string_t **edited_contents /* UTF-8! */,
                          const char **tmpfile_left /* UTF-8! */,
Index: subversion/clients/cmdline/commit-cmd.c
===================================================================
--- subversion/clients/cmdline/commit-cmd.c	(revision 14704)
+++ subversion/clients/cmdline/commit-cmd.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/commit-cmd.c
     (svn_cl__commit): Modified to use post-commit stderr aware
     datatypes and functions.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -46,7 +46,7 @@
   const char *base_dir;
   svn_config_t *cfg;
   svn_boolean_t no_unlock = FALSE;
-  svn_client_commit_info_t *commit_info = NULL;
+  svn_client_commit_info2_t *commit_info = NULL;
 
   SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, 
                                           opt_state->targets, pool));
@@ -92,7 +92,7 @@
 
   /* Commit. */
   SVN_ERR (svn_cl__cleanup_log_msg
-           (ctx->log_msg_baton, svn_client_commit2 (&commit_info,
+           (ctx->log_msg_baton, svn_client_commit3 (&commit_info,
                                                     targets,
                                                     opt_state->nonrecursive
                                                     ? FALSE : TRUE,
@@ -100,7 +100,7 @@
                                                     ctx,
                                                     pool)));
   if (commit_info && ! opt_state->quiet)
-    SVN_ERR (svn_cl__print_commit_info (commit_info, pool));
+    SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/delete-cmd.c
===================================================================
--- subversion/clients/cmdline/delete-cmd.c	(revision 14704)
+++ subversion/clients/cmdline/delete-cmd.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/delete-cmd.c
     (svn_cl__delete): Modified to use post-commit stderr aware
     datatypes and functions.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -41,7 +41,7 @@
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
-  svn_client_commit_info_t *commit_info = NULL;
+  svn_client_commit_info2_t *commit_info = NULL;
   svn_error_t *err;
 
   SVN_ERR (svn_opt_args_to_target_array2 (&targets, os, 
@@ -70,7 +70,7 @@
                                            NULL, ctx->config, pool));
     }
 
-  err = svn_client_delete (&commit_info, targets, opt_state->force, ctx, pool);
+  err = svn_client_delete2 (&commit_info, targets, opt_state->force, ctx, pool);
   if (err)
     err = svn_cl__may_need_force (err);
 
@@ -80,7 +80,7 @@
     return err;
 
   if (commit_info && ! opt_state->quiet)
-    SVN_ERR (svn_cl__print_commit_info (commit_info, pool));
+    SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool));
       
   return SVN_NO_ERROR;
 }
Index: subversion/clients/cmdline/import-cmd.c
===================================================================
--- subversion/clients/cmdline/import-cmd.c	(revision 14704)
+++ subversion/clients/cmdline/import-cmd.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/clients/cmdline/import-cmd.c
     (svn_cl__import): Modified to use post-commit stderr aware
     datatypes and functions.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -43,7 +43,7 @@
   apr_array_header_t *targets;
   const char *path;
   const char *url;
-  svn_client_commit_info_t *commit_info = NULL;
+  svn_client_commit_info2_t *commit_info = NULL;
 
   /* Import takes two arguments, for example
    *
@@ -107,15 +107,15 @@
   SVN_ERR (svn_cl__make_log_msg_baton (&(ctx->log_msg_baton), opt_state, 
                                        NULL, ctx->config, pool));
   SVN_ERR (svn_cl__cleanup_log_msg 
-           (ctx->log_msg_baton, svn_client_import (&commit_info,
-                                                   path,
-                                                   url,
-                                                   opt_state->nonrecursive,
-                                                   ctx,
-                                                   pool)));
+           (ctx->log_msg_baton, svn_client_import2 (&commit_info,
+                                                    path,
+                                                    url,
+                                                    opt_state->nonrecursive,
+                                                    ctx,
+                                                    pool)));
 
   if (commit_info && ! opt_state->quiet)
-    SVN_ERR (svn_cl__print_commit_info (commit_info, pool));
+    SVN_ERR (svn_cl__print_commit_info2 (commit_info, pool));
 
   return SVN_NO_ERROR;
 }
Index: subversion/tests/clients/cmdline/commit_tests.py
===================================================================
--- subversion/tests/clients/cmdline/commit_tests.py	(revision 14704)
+++ subversion/tests/clients/cmdline/commit_tests.py	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/tests/clients/cmdline/commit_tests.py
     (post_commit_hook_test): Added new test for post-commit hook's
     stderr testing.
     (test_list): Added post_commit_hook_test to test list.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -898,6 +898,45 @@
 
 #----------------------------------------------------------------------
 
+def post_commit_hook_test(sbox):
+  "post commit hook failure case testing"
+
+  sbox.build()
+
+  # Get paths to the working copy and repository
+  wc_dir = sbox.wc_dir
+  repo_dir = sbox.repo_dir
+
+  # Setup the hook configs to echo data back
+  post_commit_hook = svntest.main.get_post_commit_hook_path (repo_dir)
+  svntest.main.file_append (post_commit_hook,
+                            """#!/bin/sh
+                            echo "Post-commit Hook says nothing doing on stderr" > /dev/stderr
+                            exit -1
+                            """)
+  os.chmod (post_commit_hook, 0755)
+
+  # Modify iota just so there is something to commit.
+  iota_path = os.path.join (wc_dir, "iota")
+  svntest.main.file_append (iota_path, "lakalakalakalaka")
+
+  # Now, commit and examine the output (we happen to know that the
+  # filesystem will report an absolute path because that's the way the
+  # filesystem is created by this test suite.
+  expected_output = [ "Sending        "+ iota_path + "\n",
+                      "Transmitting file data .\n",
+                      "Committed revision 2.\n",
+                      "\n",
+                      "WARNING:\n",
+                      "'post-commit' hook failed with error output:\n",
+                      "Post-commit Hook says nothing doing on stderr\n",
+                      "\n"]
+
+  svntest.actions.run_and_verify_svn (None, expected_output, None,
+                                      'ci', '-m', 'log msg', iota_path)
+
+#----------------------------------------------------------------------
+
 # Regression test for bug #469, whereby merge() was once reporting
 # erroneous conflicts due to Ancestor < Target < Source, in terms of
 # node-rev-id parentage.
@@ -1994,6 +2033,7 @@
               mods_in_schedule_delete,
               Skip(tab_test, (os.name != 'posix' or sys.platform == 'cygwin')),
               local_mods_are_not_commits,
+              post_commit_hook_test,
              ]
 
 if __name__ == '__main__':
Index: subversion/libsvn_repos/hooks.c
===================================================================
--- subversion/libsvn_repos/hooks.c	(revision 14704)
+++ subversion/libsvn_repos/hooks.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_repos/hooks.c
     (svn_repos__hooks_post_commit): Modified to pass TRUE for the
     read_errstream parameter of the run_hook_cmd function.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -297,7 +297,7 @@
       args[2] = apr_psprintf (pool, "%ld", rev);
       args[3] = NULL;
 
-      SVN_ERR (run_hook_cmd ("post-commit", hook, args, FALSE, NULL, pool));
+      SVN_ERR (run_hook_cmd ("post-commit", hook, args, TRUE, NULL, pool));
     }
 
   return SVN_NO_ERROR;
Index: subversion/libsvn_repos/commit.c
===================================================================
--- subversion/libsvn_repos/commit.c	(revision 14704)
+++ subversion/libsvn_repos/commit.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_repos/commit.c
     (edit_baton2): New version of the edit_baton data structure
     using svn_commit_callback2_t for callback type.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -93,7 +93,64 @@
   const char **committed_author;
 };
 
+struct edit_baton2
+{
+  apr_pool_t *pool;
 
+  /** Supplied when the editor is created: **/
+
+  /* The user doing the commit.  Presumably, some higher layer has
+     already authenticated this user. */
+  const char *user;
+
+  /* Commit message for this commit. */
+  const char *log_msg;
+
+  /* Callback to run when the commit is done. */
+  svn_commit_callback2_t callback;
+  void *callback_baton;
+
+  /* The already-open svn repository to commit to. */
+  svn_repos_t *repos;
+
+  /* URL to the root of the open repository. */
+  const char *repos_url;
+
+  /* The filesystem associated with the REPOS above (here for
+     convenience). */
+  svn_fs_t *fs;
+
+  /* Location in fs where the edit will begin. */
+  const char *base_path;
+
+  /* Does this set of interfaces 'own' the commit transaction? */
+  svn_boolean_t txn_owner;
+
+  /* svn transaction associated with this edit (created in
+     open_root, or supplied by the public API caller). */
+  svn_fs_txn_t *txn;
+
+  /** Filled in during open_root: **/
+
+  /* The name of the transaction. */
+  const char *txn_name;
+
+  /* The object representing the root directory of the svn txn. */
+  svn_fs_root_t *txn_root;
+
+  /** Filled in when the edit is closed: **/
+
+  /* The new revision created by this commit. */
+  svn_revnum_t *new_rev;
+
+  /* The date (according to the repository) of this commit. */
+  const char **committed_date;
+
+  /* The author (also according to the repository) of this commit. */
+  const char **committed_author;
+};
+
+
 struct dir_baton
 {
   struct edit_baton *edit_baton;
@@ -552,10 +609,11 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (close_edit): Checks if the post-commit hook has returned any stderr
     and if so, pass it on the callback function.
     (svn_repos_get_commit_editor3): New version of 
     svn_repos_get_commit_editor2 that takes callback of type
     svn_commit_callback2_t
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 close_edit (void *edit_baton,
             apr_pool_t *pool)
 {
-  struct edit_baton *eb = edit_baton;
+  struct edit_baton2 *eb = edit_baton;
   svn_revnum_t new_revision = SVN_INVALID_REVNUM;
   svn_error_t *err;
   const char *conflict;
+  char *post_commit_err = NULL ;
 
   /* Commit. */
   err = svn_repos_fs_commit_txn (&conflict, eb->repos, 
@@ -587,16 +645,14 @@
     }
   else if (err)
     {
-      /* ### TODO: ra_local is the only RA layer that currently
-         understands SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED.  And as of
-         at least r12960, svn_repos_fs_commit_txn() would never return
-         that anyway.  If someone who knows ra_svn better can add
-         handling for this special case, this whole "else if" block
-         can go away (again).  */ 
+      /* retrieve the post-commit hook stderr */
+      if (err->child->message)
+        post_commit_err = apr_pstrdup (pool, err->child->message) ;
+  
       svn_error_clear(err);
       err = SVN_NO_ERROR;
     }
-  
+
   /* Pass new revision information to the caller's callback. */
   {
     svn_string_t *date, *author;
@@ -618,6 +674,7 @@
       err2 = (*eb->callback) (new_revision, 
                               date ? date->data : NULL, 
                               author ? author->data : NULL,
+                              post_commit_err,
                               eb->callback_baton);
     if (err2)
       {
@@ -692,6 +749,56 @@
 
   *edit_baton = eb;
   *editor = e;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_repos_get_commit_editor3 (const svn_delta_editor_t **editor,
+                              void **edit_baton,
+                              svn_repos_t *repos,
+                              svn_fs_txn_t *txn,
+                              const char *repos_url,
+                              const char *base_path,
+                              const char *user,
+                              const char *log_msg,
+                              svn_commit_callback2_t callback,
+                              void *callback_baton,
+                              apr_pool_t *pool)
+{
+  svn_delta_editor_t *e = svn_delta_default_editor (pool);
+  apr_pool_t *subpool = svn_pool_create (pool);
+  struct edit_baton2 *eb = apr_pcalloc (subpool, sizeof (*eb));
+
+  /* Set up the editor. */
+  e->open_root         = open_root;
+  e->delete_entry      = delete_entry;
+  e->add_directory     = add_directory;
+  e->open_directory    = open_directory;
+  e->change_dir_prop   = change_dir_prop;
+  e->add_file          = add_file;
+  e->open_file         = open_file;
+  e->close_file        = close_file;
+  e->apply_textdelta   = apply_textdelta;
+  e->change_file_prop  = change_file_prop;
+  e->close_edit        = close_edit;
+  e->abort_edit        = abort_edit;
+
+  /* Set up the edit baton. */
+  eb->pool = subpool;
+  eb->user = user ? apr_pstrdup (subpool, user) : NULL;
+  eb->log_msg = apr_pstrdup (subpool, log_msg);
+  eb->callback = callback;
+  eb->callback_baton = callback_baton;
+  eb->base_path = apr_pstrdup (subpool, base_path);
+  eb->repos = repos;
+  eb->repos_url = repos_url;
+  eb->fs = svn_repos_fs (repos);
+  eb->txn = txn;
+  eb->txn_owner = txn ? FALSE : TRUE;
+
+  *edit_baton = eb;
+  *editor = e;
   
   return SVN_NO_ERROR;
 }
Index: subversion/libsvn_ra_svn/client.c
===================================================================
--- subversion/libsvn_ra_svn/client.c	(revision 14704)
+++ subversion/libsvn_ra_svn/client.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra_svn/client.c
     (ra_svn_commit_callback_baton_t): Modified to use 
     svn_commit_callback2_t for callback type
     (ra_svn_end_commit): Modified to accomodate the post-commit hook's
     stderr if available. If available this is passed on to the callback
     function.
     (ra_svn_commit): Modified to use the svn_commit_callback2_t
     type for the callback parameter.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -56,7 +56,7 @@
   ra_svn_session_baton_t *sess_baton;
   apr_pool_t *pool;
   svn_revnum_t *new_rev;
-  svn_commit_callback_t callback;
+  svn_commit_callback2_t callback;
   void *callback_baton;
 } ra_svn_commit_callback_baton_t;
 
@@ -785,15 +785,18 @@
   svn_revnum_t new_rev;
   const char *committed_date;
   const char *committed_author;
+  const char *post_commit_err;
 
   SVN_ERR(handle_auth_request(ccb->sess_baton, ccb->pool));
-  SVN_ERR(svn_ra_svn_read_tuple(ccb->sess_baton->conn, ccb->pool, "r(?c)(?c)",
+  SVN_ERR(svn_ra_svn_read_tuple(ccb->sess_baton->conn, ccb->pool,
+                                "r(?c)(?c)?(?c)",
                                 &new_rev,
                                 &committed_date,
-                                &committed_author));
+                                &committed_author,
+                                &post_commit_err));
 
   return ccb->callback(new_rev, committed_date, committed_author,
-                       ccb->callback_baton);
+                       post_commit_err, ccb->callback_baton);
 
 }
 
@@ -801,7 +804,7 @@
                                   const svn_delta_editor_t **editor,
                                   void **edit_baton,
                                    const char *log_msg,
-                                  svn_commit_callback_t callback,
+                                  svn_commit_callback2_t callback,
                                   void *callback_baton,
                                   apr_hash_t *lock_tokens,
                                   svn_boolean_t keep_locks,
Index: subversion/libsvn_ra_dav/merge.c
===================================================================
--- subversion/libsvn_ra_dav/merge.c	(revision 14704)
+++ subversion/libsvn_ra_dav/merge.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra_dav/merge.c
     (merge_elements): Added new element to represent the post-commit
     status's stderr.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -58,6 +58,8 @@
   { "DAV:", "collection", ELEM_collection, 0 },
   { "DAV:", "baseline", ELEM_baseline, 0 },
   { "DAV:", "version-name", ELEM_version_name, SVN_RA_DAV__XML_CDATA },
+  { SVN_XML_NAMESPACE, "post-commit-err",
+    ELEM_post_commit_err, SVN_RA_DAV__XML_CDATA },
   { "DAV:", "creationdate", ELEM_creationdate, SVN_RA_DAV__XML_CDATA },
   { "DAV:", "creator-displayname", ELEM_creator_displayname,
     SVN_RA_DAV__XML_CDATA },
@@ -104,6 +106,8 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (merge_ctx_t): Added new member to hold the post-commit stderr
     if any.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   svn_stringbuf_t *committed_date; /* DAV:creationdate for this resource */
   svn_stringbuf_t *last_author;    /* DAV:creator-displayname for this
                                       resource */
+  svn_stringbuf_t *post_commit_err;/* SVN_XML_NAMESPACE:post-commit hook's
+                                      stderr */
 
   /* We only invoke set_prop() on targets listed in valid_targets.
      Some entities (such as directories that have had changes
@@ -341,6 +345,7 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (validate_element): Modified to understand the post-commit
     stderr (ELEM_post_commit_err ) as a valid tag.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
           || child == ELEM_version_name
           || child == ELEM_creationdate
           || child == ELEM_creator_displayname
+          || child == ELEM_post_commit_err
           /* other props */)
         return SVN_RA_DAV__XML_VALID;
       else
@@ -524,6 +529,10 @@
       svn_stringbuf_set(mc->vsn_name, cdata);
       break;
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (end_element): Added case to extract post-commit hook's stderr.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+    case ELEM_post_commit_err:
+      svn_stringbuf_set(mc->post_commit_err, cdata);
+      break;
+
     case ELEM_creationdate:
       svn_stringbuf_set(mc->committed_date, cdata);
       break;
@@ -636,11 +645,39 @@
 }
 
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_ra_dav__merge_activity): Modified to call 
     svn_ra_dav__merge_activity2 with post_commit_err as NULL.
     (svn_ra_dav__merge_activity2): Added function to return the
     post-commit hook's stderr if available.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+svn_error_t * svn_ra_dav__merge_activity (
+    svn_revnum_t *new_rev,
+    const char **committed_date,
+    const char **committed_author,
+    svn_ra_dav__session_t *ras,
+    const char *repos_url,
+    const char *activity_url,
+    apr_hash_t *valid_targets,
+    apr_hash_t *lock_tokens,
+    svn_boolean_t keep_locks,
+    svn_boolean_t disable_merge_response,
+    apr_pool_t *pool)
+{
+  return svn_ra_dav__merge_activity2 (new_rev,
+                                      committed_date,
+                                      committed_author,
+                                      NULL,
+                                      ras,
+                                      repos_url,
+                                      activity_url,
+                                      valid_targets,
+                                      lock_tokens,
+                                      keep_locks,
+                                      disable_merge_response,
+                                      pool);
 
-svn_error_t * svn_ra_dav__merge_activity(
+}
+
+svn_error_t * svn_ra_dav__merge_activity2 (
     svn_revnum_t *new_rev,
     const char **committed_date,
     const char **committed_author,
+    const char **post_commit_err,
     svn_ra_dav__session_t *ras,
     const char *repos_url,
     const char *activity_url,
@@ -670,6 +707,8 @@
   mc.vsn_url = MAKE_BUFFER(pool);
   mc.committed_date = MAKE_BUFFER(pool);
   mc.last_author = MAKE_BUFFER(pool);
+  if (post_commit_err)
+    mc.post_commit_err = MAKE_BUFFER(pool);
 
   if (disable_merge_response 
       || (! keep_locks))
@@ -727,6 +766,10 @@
     *committed_author = mc.last_author->len 
                         ? apr_pstrdup(pool, mc.last_author->data) : NULL;
 
+  if (post_commit_err)
+    *post_commit_err = mc.post_commit_err->len 
+                        ? apr_pstrdup(pool, mc.post_commit_err->data) : NULL;
+
   svn_pool_destroy(mc.scratchpool);
 
   return NULL;
Index: subversion/libsvn_ra_dav/ra_dav.h
===================================================================
--- subversion/libsvn_ra_dav/ra_dav.h	(revision 14704)
+++ subversion/libsvn_ra_dav/ra_dav.h	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra_dav/ra_dav.h
     (svn_ra_dav__get_commit_editor2): New version of
     svn_ra_dav__get_commit_editor using svn_commit_callback2_t
     as callback type.
     (svn_ra_dav__get_commit_editor): Deprecated.
     (enum): Added enumeration for ELEM_post_commit_err.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -223,6 +223,19 @@
   svn_boolean_t keep_locks,
   apr_pool_t *pool);
 
+/** since v1.3
+  */
+svn_error_t * svn_ra_dav__get_commit_editor2(
+  svn_ra_session_t *session,
+  const svn_delta_editor_t **editor,
+  void **edit_baton,
+  const char *log_msg,
+  svn_commit_callback2_t callback,
+  void *callback_baton,
+  apr_hash_t *lock_tokens,
+  svn_boolean_t keep_locks,
+  apr_pool_t *pool);
+
 svn_error_t * svn_ra_dav__get_file(
   svn_ra_session_t *session,
   const char *path,
@@ -654,6 +667,7 @@
   ELEM_updated_set,
   ELEM_vcc,
   ELEM_version_name,
+  ELEM_post_commit_err,
   ELEM_error,
 
   /* SVN elements */
@@ -716,6 +730,22 @@
     svn_boolean_t keep_locks,
     svn_boolean_t disable_merge_response,
     apr_pool_t *pool);
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_ra_dav__merge_activity2): New version of 
     svn_ra_dav__merge_activity, taking a new post_commit_err parameter.
     (svn_ra_dav__merge_activity): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+/** since v1.3
+  * parameter added for post-commit hook's stderr
+  */
+svn_error_t * svn_ra_dav__merge_activity2(
+    svn_revnum_t *new_rev,
+    const char **committed_date,
+    const char **committed_author,
+    const char **post_commit_err,
+    svn_ra_dav__session_t *ras,
+    const char *repos_url,
+    const char *activity_url,
+    apr_hash_t *valid_targets,
+    apr_hash_t *lock_tokens,
+    svn_boolean_t keep_locks,
+    svn_boolean_t disable_merge_response,
+    apr_pool_t *pool);
 
 
 /* Make a buffer for repeated use with svn_stringbuf_set().
Index: subversion/libsvn_ra_dav/session.c
===================================================================
--- subversion/libsvn_ra_dav/session.c	(revision 14704)
+++ subversion/libsvn_ra_dav/session.c	(working copy)
@@ -1432,7 +1432,7 @@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra_dav/session.c
     (dav_vtable): Modified to use svn_ra_dav__get_commit_editor2.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   svn_ra_dav__change_rev_prop,
   svn_ra_dav__rev_proplist,
   svn_ra_dav__rev_prop,
-  svn_ra_dav__get_commit_editor,
+  svn_ra_dav__get_commit_editor2,
   svn_ra_dav__get_file,
   svn_ra_dav__get_dir,
   svn_ra_dav__do_update,
Index: subversion/libsvn_ra_dav/commit.c
===================================================================
--- subversion/libsvn_ra_dav/commit.c	(revision 14704)
+++ subversion/libsvn_ra_dav/commit.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/libsvn_ra_dav/commit.c
     (commit_ctx_t): Now uses svn_commit_callback2_t for callback.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -114,7 +114,7 @@
   const char *log_msg;
 
   /* The commit callback and baton */
-  svn_commit_callback_t callback;
+  svn_commit_callback2_t callback;
   void *callback_baton;
 
   /* The hash of lock-tokens owned by the working copy. */
@@ -225,7 +225,6 @@
                         NULL, 204 /* No Content */, 404 /* Not Found */, pool);
 }
 
-
 /* Get the version resource URL for RSRC, storing it in
    RSRC->vsn_url.  Use POOL for all temporary allocations. */
 static svn_error_t * get_version_url(commit_ctx_t *cc,
@@ -1416,6 +1415,37 @@
 }
 
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (commit_close_edit2): New version of commit_close_edit that
     uses svn_ra_dav__merge_activity2 and handles post-commit's
     stderr.
     (commit_close_edit): Deprecated.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+static svn_error_t * commit_close_edit2(void *edit_baton,
+                                        apr_pool_t *pool)
+{
+  commit_ctx_t *cc = edit_baton;
+  svn_revnum_t new_rev;
+  const char *committed_date;
+  const char *committed_author;
+  const char *post_commit_err;
+
+  SVN_ERR( svn_ra_dav__merge_activity2(&new_rev,
+                                       &committed_date,
+                                       &committed_author,
+                                       &post_commit_err,
+                                       cc->ras,
+                                       cc->ras->root.path,
+                                       cc->activity_url,
+                                       cc->valid_targets,
+                                       cc->tokens,
+                                       cc->keep_locks,
+                                       cc->disable_merge_response,
+                                       pool) );
+  SVN_ERR( delete_activity(edit_baton, pool) );
+  SVN_ERR( svn_ra_dav__maybe_store_auth_info(cc->ras) );
+
+  if (new_rev != SVN_INVALID_REVNUM)
+    SVN_ERR( cc->callback (new_rev, committed_date, committed_author,
+                           post_commit_err, cc->callback_baton));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t * commit_close_edit(void *edit_baton,
                                        apr_pool_t *pool)
 {
@@ -1423,24 +1453,26 @@
   svn_revnum_t new_rev;
   const char *committed_date;
   const char *committed_author;
+  const char *post_commit_err;
 
-  SVN_ERR( svn_ra_dav__merge_activity(&new_rev,
-                                      &committed_date,
-                                      &committed_author,
-                                      cc->ras,
-                                      cc->ras->root.path,
-                                      cc->activity_url,
-                                      cc->valid_targets,
-                                      cc->tokens,
-                                      cc->keep_locks,
-                                      cc->disable_merge_response,
-                                      pool) );
+  SVN_ERR( svn_ra_dav__merge_activity2(&new_rev,
+                                       &committed_date,
+                                       &committed_author,
+                                       &post_commit_err,
+                                       cc->ras,
+                                       cc->ras->root.path,
+                                       cc->activity_url,
+                                       cc->valid_targets,
+                                       cc->tokens,
+                                       cc->keep_locks,
+                                       cc->disable_merge_response,
+                                       pool) );
   SVN_ERR( delete_activity(edit_baton, pool) );
   SVN_ERR( svn_ra_dav__maybe_store_auth_info(cc->ras) );
 
   if (new_rev != SVN_INVALID_REVNUM)
     SVN_ERR( cc->callback (new_rev, committed_date, committed_author,
-                           cc->callback_baton));
+                           post_commit_err, cc->callback_baton));
 
   return SVN_NO_ERROR;
 }
@@ -1529,6 +1561,93 @@
   return SVN_NO_ERROR;
 }
 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     (svn_ra_dav__get_commit_editor2): New version of
     svn_ra_dav__get_commit_editor that uses callback of type
     svn_commit_callback2_t.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+svn_error_t * svn_ra_dav__get_commit_editor2(svn_ra_session_t *session,
+                                              const svn_delta_editor_t **editor,
+                                              void **edit_baton,
+                                              const char *log_msg,
+                                              svn_commit_callback2_t callback,
+                                              void *callback_baton,
+                                              apr_hash_t *lock_tokens,
+                                              svn_boolean_t keep_locks,
+                                              apr_pool_t *pool)
+{
+  svn_ra_dav__session_t *ras = session->priv;
+  svn_delta_editor_t *commit_editor;
+  commit_ctx_t *cc;
+  struct copy_baton *cb;
+
+  /* Build a copy_baton for COPY requests. */
+  cb = apr_pcalloc(pool, sizeof(*cb));
+  cb->pool = pool;
+
+  /* Build the main commit editor's baton. */
+  cc = apr_pcalloc(pool, sizeof(*cc));
+  cc->ras = ras;
+  cc->valid_targets = apr_hash_make(pool);
+  cc->get_func = ras->callbacks->get_wc_prop;
+  cc->push_func = ras->callbacks->push_wc_prop;
+  cc->cb_baton = ras->callback_baton;
+  cc->log_msg = log_msg;
+  cc->callback = callback;
+  cc->callback_baton = callback_baton;
+  cc->tokens = lock_tokens;
+  cc->keep_locks = keep_locks;
+  cc->cb = cb;
+
+  /* If the caller didn't give us any way of storing wcprops, then
+     there's no point in getting back a MERGE response full of VR's. */
+  if (ras->callbacks->push_wc_prop == NULL)
+    cc->disable_merge_response = TRUE;
+
+  /* ### should we perform an OPTIONS to validate the server we're about
+     ### to talk to? */
+
+  /*
+  ** Create an Activity. This corresponds directly to an FS transaction.
+  ** We will check out all further resources within the context of this
+  ** activity.
+  */
+  SVN_ERR( create_activity(cc, pool) );
+
+  /*
+  ** Find the latest baseline resource, check it out, and then apply the
+  ** log message onto the thing.
+  */
+  SVN_ERR( apply_log_message(cc, log_msg, pool) );
+
+  /* Register request hooks in the neon session.  They specifically
+     allow any COPY requests (ne_copy()) to parse <D:error>
+     responses.  They're no-ops for other requests. */
+  ne_hook_create_request(ras->sess, create_request_hook, cb);
+  ne_hook_pre_send(ras->sess, pre_send_hook, cb);
+
+  /*
+  ** Set up the editor.
+  **
+  ** This structure is used during the commit process. An external caller
+  ** uses these callbacks to describe all the changes in the working copy
+  ** that must be committed to the server.
+  */
+  commit_editor = svn_delta_default_editor(pool);
+  commit_editor->open_root = commit_open_root;
+  commit_editor->delete_entry = commit_delete_entry;
+  commit_editor->add_directory = commit_add_dir;
+  commit_editor->open_directory = commit_open_dir;
+  commit_editor->change_dir_prop = commit_change_dir_prop;
+  commit_editor->close_directory = commit_close_dir;
+  commit_editor->add_file = commit_add_file;
+  commit_editor->open_file = commit_open_file;
+  commit_editor->apply_textdelta = commit_apply_txdelta;
+  commit_editor->change_file_prop = commit_change_file_prop;
+  commit_editor->close_file = commit_close_file;
+  commit_editor->close_edit = commit_close_edit2;
+  commit_editor->abort_edit = commit_abort_edit;
+
+  *editor = commit_editor;
+  *edit_baton = cc;
+  return SVN_NO_ERROR;
+}
+
 svn_error_t * svn_ra_dav__get_commit_editor(svn_ra_session_t *session,
                                             const svn_delta_editor_t **editor,
                                             void **edit_baton,
Index: subversion/svnserve/serve.c
===================================================================
--- subversion/svnserve/serve.c	(revision 14704)
+++ subversion/svnserve/serve.c	(working copy)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
   * subversion/svnserve/serve.c
     (commit_callback_baton_t): Added post_commit_err member.
     (commit_done): Added post_commit_err parameter and handling.
     (commit): Extract post-commit's stderr and writes back to the client.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -62,6 +62,7 @@
   svn_revnum_t *new_rev;
   const char **date;
   const char **author;
+  const char **post_commit_err;
 } commit_callback_baton_t;
 
 typedef struct {
@@ -622,13 +623,15 @@
 }
 
 static svn_error_t *commit_done(svn_revnum_t new_rev, const char *date,
-                                const char *author, void *baton)
+                                const char *author, const char *post_commit_err,
+                                void *baton)
 {
   commit_callback_baton_t *ccb = baton;
 
   *ccb->new_rev = new_rev;
   *ccb->date = date;
   *ccb->author = author;
+  *ccb->post_commit_err = post_commit_err;
   return SVN_NO_ERROR;
 }
 
@@ -722,7 +725,7 @@
                            apr_array_header_t *params, void *baton)
 {
   server_baton_t *b = baton;
-  const char *log_msg, *date, *author;
+  const char *log_msg, *date, *author, *post_commit_err;
   apr_array_header_t *lock_tokens;
   svn_boolean_t keep_locks;
   const svn_delta_editor_t *editor;
@@ -751,8 +754,9 @@
   ccb.new_rev = &new_rev;
   ccb.date = &date;
   ccb.author = &author;
+  ccb.post_commit_err = &post_commit_err;
   /* ### Note that svn_repos_get_commit_editor actually wants a decoded URL. */
-  SVN_CMD_ERR(svn_repos_get_commit_editor2
+  SVN_CMD_ERR(svn_repos_get_commit_editor3
               (&editor, &edit_baton, b->repos, NULL,
                svn_path_uri_decode(b->repos_url, pool),
                b->fs_path, b->user,
@@ -775,8 +779,8 @@
       if (! keep_locks && lock_tokens)
         SVN_ERR(unlock_paths(lock_tokens, b, pool));
 
-      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "r(?c)(?c)",
-                                     new_rev, date, author));
+      SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "r(?c)(?c)(?c)",
+                                     new_rev, date, author, post_commit_err));
 
       if (! b->tunnel)
         SVN_ERR(svn_fs_deltify_revision(b->fs, new_rev, pool));


