Modified: subversion/branches/reuse-ra-session/subversion/include/svn_props.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/include/svn_props.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/include/svn_props.h 
(original)
+++ subversion/branches/reuse-ra-session/subversion/include/svn_props.h Wed Feb 
25 08:15:39 2015
@@ -440,13 +440,20 @@ svn_prop_name_is_valid(const char *prop_
  * @verbatim
      /trunk: 1-6,9,37-38
      /trunk/foo: 10 @endverbatim
+ * @since New in 1.5.
  */
 #define SVN_PROP_MERGEINFO SVN_PROP_PREFIX "mergeinfo"
 
-/** Property used to record inheritable configuration auto-props. */
+/** Property used to record inheritable configuration auto-props.
+ *
+ * @since New in 1.8.
+ */
 #define SVN_PROP_INHERITABLE_AUTO_PROPS SVN_PROP_PREFIX "auto-props"
 
-/** Property used to record inheritable configuration ignores. */
+/** Property used to record inheritable configuration ignores.
+ *
+ * @since New in 1.8.
+ */
 #define SVN_PROP_INHERITABLE_IGNORES SVN_PROP_PREFIX "global-ignores"
 
 /** Meta-data properties.

Modified: subversion/branches/reuse-ra-session/subversion/include/svn_ra.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/include/svn_ra.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/include/svn_ra.h (original)
+++ subversion/branches/reuse-ra-session/subversion/include/svn_ra.h Wed Feb 25 
08:15:39 2015
@@ -289,7 +289,7 @@ typedef svn_boolean_t (*svn_ra_check_tun
  * This function will be called when the pool that owns the tunnel
  * connection is cleared or destroyed.
  *
- * @a tunnel_context is the baton as returned from the 
+ * @a tunnel_context is the baton as returned from the
  * svn_ra_open_tunnel_func_t.
  *
  * @a tunnel_baton was returned by the open-tunnel callback.

Modified: subversion/branches/reuse-ra-session/subversion/include/svn_repos.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/include/svn_repos.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/include/svn_repos.h 
(original)
+++ subversion/branches/reuse-ra-session/subversion/include/svn_repos.h Wed Feb 
25 08:15:39 2015
@@ -1522,7 +1522,8 @@ svn_repos_replay(svn_fs_root_t *root,
  * If @a commit_callback is non-NULL, then before @c close_edit returns (but
  * after the commit has succeeded) @c close_edit will invoke
  * @a commit_callback with a filled-in #svn_commit_info_t *, @a commit_baton,
- * and @a pool or some subpool thereof as arguments.  If @a commit_callback
+ * and @a pool or some subpool thereof as arguments.  The @c repos_root field
+ * of the #svn_commit_info_t is null.  If @a commit_callback
  * returns an error, that error will be returned from @c close_edit,
  * otherwise if there was a post-commit hook failure, then that error
  * will be returned with code SVN_ERR_REPOS_POST_COMMIT_HOOK_FAILED.
@@ -1534,7 +1535,7 @@ svn_repos_replay(svn_fs_root_t *root,
  * NULL).  Callers who supply their own transactions are responsible
  * for cleaning them up (either by committing them, or aborting them).
  *
- * @since New in 1.5.
+ * @since New in 1.5. Since 1.6, @a commit_callback can be null.
  *
  * @note Yes, @a repos_url_decoded is a <em>decoded</em> URL.  We realize
  * that's sorta wonky.  Sorry about that.
@@ -3749,7 +3750,7 @@ svn_repos_authz_check_access(svn_authz_t
 typedef enum svn_repos_revision_access_level_t
 {
   /** no access allowed to the revision properties and all changed-paths
-   * information. */ 
+   * information. */
   svn_repos_revision_access_none,
   /** access granted to some (svn:date and svn:author) revision properties and
    * changed-paths information on paths the read has access to. */

Modified: subversion/branches/reuse-ra-session/subversion/include/svn_string.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/include/svn_string.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/include/svn_string.h 
(original)
+++ subversion/branches/reuse-ra-session/subversion/include/svn_string.h Wed 
Feb 25 08:15:39 2015
@@ -443,7 +443,7 @@ svn_string_compare_stringbuf(const svn_s
  */
 
 /** Divide @a input into substrings, interpreting any char from @a sep
- * as a token separator.  
+ * as a token separator.
  *
  * Return an array of copies of those substrings (plain const char*),
  * allocating both the array and the copies in @a pool.

Modified: subversion/branches/reuse-ra-session/subversion/include/svn_version.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/include/svn_version.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/include/svn_version.h 
(original)
+++ subversion/branches/reuse-ra-session/subversion/include/svn_version.h Wed 
Feb 25 08:15:39 2015
@@ -61,7 +61,7 @@ extern "C" {
  * Modify when new functionality is added or new interfaces are
  * defined, but all changes are backward compatible.
  */
-#define SVN_VER_MINOR      9
+#define SVN_VER_MINOR      10
 
 /**
  * Patch number.

Modified: subversion/branches/reuse-ra-session/subversion/include/svn_wc.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/include/svn_wc.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/include/svn_wc.h (original)
+++ subversion/branches/reuse-ra-session/subversion/include/svn_wc.h Wed Feb 25 
08:15:39 2015
@@ -2185,6 +2185,14 @@ typedef struct svn_wc_conflict_result_t
       NULL) in the user's working copy. */
   svn_boolean_t save_merged;
 
+  /** If not NULL, this is the new merged property, used when choosing
+   * #svn_wc_conflict_choose_merged. This value is prefered over using
+   * merged_file.
+   *
+   * @since New in 1.9.
+   */
+  const svn_string_t *merged_value;
+
 } svn_wc_conflict_result_t;
 
 
@@ -2194,7 +2202,8 @@ typedef struct svn_wc_conflict_result_t
  *
  * Set the @c choice field of the structure to @a choice, @c merged_file
  * to @a merged_file, and @c save_merged to false.  Make only a shallow
- * copy of the pointer argument @a merged_file.
+ * copy of the pointer argument @a merged_file. @a merged_file may be
+ * NULL if setting merged_file is not needed.
  *
  * @since New in 1.5.
  */
@@ -3826,6 +3835,13 @@ typedef struct svn_wc_status3_t
    * @since New in 1.8. */
   svn_boolean_t file_external;
 
+
+  /** The actual kind of the node in the working copy. May differ from kind
+   * on obstructions, deletes, etc. svn_node_unknown if unavailable.
+   *
+   * @since New in 1.9 */
+  svn_node_kind_t actual_kind;
+
   /* NOTE! Please update svn_wc_dup_status3() when adding new fields here. */
 } svn_wc_status3_t;
 

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/add.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/add.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/add.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/add.c Wed Feb 
25 08:15:39 2015
@@ -768,59 +768,6 @@ svn_client__get_all_auto_props(apr_hash_
   return SVN_NO_ERROR;
 }
 
-svn_error_t *svn_client__get_inherited_ignores(apr_array_header_t **ignores,
-                                               const char *path_or_url,
-                                               svn_client_ctx_t *ctx,
-                                               apr_pool_t *result_pool,
-                                               apr_pool_t *scratch_pool)
-{
-  svn_opt_revision_t rev;
-  apr_hash_t *explicit_ignores;
-  apr_array_header_t *inherited_ignores;
-  svn_boolean_t target_is_url = svn_path_is_url(path_or_url);
-  svn_string_t *explicit_prop;
-  int i;
-
-  if (target_is_url)
-    rev.kind = svn_opt_revision_head;
-  else
-    rev.kind = svn_opt_revision_working;
-
-  SVN_ERR(svn_client_propget5(&explicit_ignores, &inherited_ignores,
-                              SVN_PROP_INHERITABLE_IGNORES, path_or_url,
-                              &rev, &rev, NULL, svn_depth_empty, NULL, ctx,
-                              scratch_pool, scratch_pool));
-
-  explicit_prop = svn_hash_gets(explicit_ignores, path_or_url);
-
-  if (explicit_prop)
-    {
-      svn_prop_inherited_item_t *new_iprop =
-        apr_palloc(scratch_pool, sizeof(*new_iprop));
-      new_iprop->path_or_url = path_or_url;
-      new_iprop->prop_hash = apr_hash_make(scratch_pool);
-      svn_hash_sets(new_iprop->prop_hash, SVN_PROP_INHERITABLE_IGNORES,
-                    explicit_prop);
-      APR_ARRAY_PUSH(inherited_ignores,
-                     svn_prop_inherited_item_t *) = new_iprop;
-    }
-
-  *ignores = apr_array_make(result_pool, 16, sizeof(const char *));
-
-  for (i = 0; i < inherited_ignores->nelts; i++)
-    {
-      svn_prop_inherited_item_t *elt = APR_ARRAY_IDX(
-        inherited_ignores, i, svn_prop_inherited_item_t *);
-      svn_string_t *ignore_val = svn_hash_gets(elt->prop_hash,
-                                               SVN_PROP_INHERITABLE_IGNORES);
-      if (ignore_val)
-        svn_cstring_split_append(*ignores, ignore_val->data, "\n\r\t\v ",
-                                 FALSE, result_pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* The main logic of the public svn_client_add5.
  *
  * EXISTING_PARENT_ABSPATH is the absolute path to the first existing

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/blame.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/blame.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/blame.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/blame.c Wed 
Feb 25 08:15:39 2015
@@ -34,6 +34,7 @@
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "svn_props.h"
+#include "svn_hash.h"
 #include "svn_sorts.h"
 
 #include "private/svn_wc_private.h"
@@ -76,6 +77,7 @@ struct diff_baton {
 /* The baton used for a file revision. Lives the entire operation */
 struct file_rev_baton {
   svn_revnum_t start_rev, end_rev;
+  svn_boolean_t backwards;
   const char *target;
   svn_client_ctx_t *ctx;
   const svn_diff_file_options_t *diff_options;
@@ -96,6 +98,14 @@ struct file_rev_baton {
   /* pools for files which may need to persist for more than one rev. */
   apr_pool_t *filepool;
   apr_pool_t *prevfilepool;
+
+  svn_boolean_t check_mime_type;
+
+  /* When blaming backwards we have to use the changes
+     on the *next* revision, as the interesting change
+     happens when we move to the previous revision */
+  svn_revnum_t last_revnum;
+  apr_hash_t *last_props;
 };
 
 /* The baton used by the txdelta window handler. Allocated per revision */
@@ -431,6 +441,26 @@ file_rev_handler(void *baton, const char
   /* Clear the current pool. */
   svn_pool_clear(frb->currpool);
 
+  if (frb->check_mime_type)
+    {
+      apr_hash_t *props = svn_prop_array_to_hash(prop_diffs, frb->currpool);
+      const char *value;
+
+      frb->check_mime_type = FALSE; /* Only check first */
+
+      value = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
+
+      if (value && svn_mime_type_is_binary(value))
+        {
+          return svn_error_createf(
+              SVN_ERR_CLIENT_IS_BINARY_FILE, NULL,
+              _("Cannot calculate blame information for binary file '%s'"),
+               (svn_path_is_url(frb->target)
+                      ? frb->target 
+                      : svn_dirent_local_style(frb->target, pool)));
+        }
+    }
+
   if (frb->ctx->notify_func2)
     {
       svn_wc_notify_t *notify
@@ -489,18 +519,24 @@ file_rev_handler(void *baton, const char
   /* Create the rev structure. */
   delta_baton->rev = apr_pcalloc(frb->mainpool, sizeof(struct rev));
 
-  if (revnum < MIN(frb->start_rev, frb->end_rev))
+  if (frb->backwards)
     {
-      /* We shouldn't get more than one revision before the starting
-         revision (unless of including merged revisions). */
-      SVN_ERR_ASSERT((frb->last_filename == NULL)
-                     || frb->include_merged_revisions);
+      /* Use from last round...
+         SVN_INVALID_REVNUM on first, which is exactly
+         what we want */
+      delta_baton->rev->revision = frb->last_revnum;
+      delta_baton->rev->rev_props = frb->last_props;
 
-      /* The file existed before start_rev; generate no blame info for
-         lines from this revision (or before). */
-      delta_baton->rev->revision = SVN_INVALID_REVNUM;
+      /* Store for next delta */
+      if (revnum >= MIN(frb->start_rev, frb->end_rev))
+        {
+          frb->last_revnum = revnum;
+          frb->last_props = svn_prop_hash_dup(rev_props, frb->mainpool);
+        }
+      /* Else: Not needed on last rev */
     }
-  else
+  else if (merged_revision
+           || (revnum >= MIN(frb->start_rev, frb->end_rev)))
     {
       /* 1+ for the "youngest to oldest" blame */
       SVN_ERR_ASSERT(revnum <= 1 + MAX(frb->end_rev, frb->start_rev));
@@ -509,6 +545,20 @@ file_rev_handler(void *baton, const char
       delta_baton->rev->revision = revnum;
       delta_baton->rev->rev_props = svn_prop_hash_dup(rev_props, 
frb->mainpool);
     }
+  else
+    {
+      /* We shouldn't get more than one revision outside the
+         specified range (unless we alsoe receive merged revisions) */
+      SVN_ERR_ASSERT((frb->last_filename == NULL)
+                     || frb->include_merged_revisions);
+
+      /* The file existed before start_rev; generate no blame info for
+         lines from this revision (or before). 
+
+         This revision specifies the state as it was at the start revision */
+
+      delta_baton->rev->revision = SVN_INVALID_REVNUM;
+    }
 
   if (frb->include_merged_revisions)
     delta_baton->rev->path = apr_pstrdup(frb->mainpool, path);
@@ -626,7 +676,6 @@ svn_client_blame5(const char *target,
   svn_stream_t *last_stream;
   svn_stream_t *stream;
   const char *target_abspath_or_url;
-  svn_revnum_t youngest;
 
   if (start->kind == svn_opt_revision_unspecified
       || end->kind == svn_opt_revision_unspecified)
@@ -662,35 +711,54 @@ svn_client_blame5(const char *target,
                                             target, peg_revision,
                                             &younger_end,
                                             ctx, pool));
-  
+
     /* Make the session point to the real URL. */
     SVN_ERR(svn_ra_reparent(ra_session, loc->url, pool));
   }
 
   /* We check the mime-type of the yougest revision before getting all
      the older revisions. */
-  if (!ignore_mime_type)
+  if (!ignore_mime_type
+      && start_revnum < end_revnum)
     {
       apr_hash_t *props;
-      apr_hash_index_t *hi;
+      const char *mime_type = NULL;
+
+      if (svn_path_is_url(target)
+          || start_revnum > end_revnum
+          || (end->kind != svn_opt_revision_working
+              && end->kind != svn_opt_revision_base))
+        {
+          SVN_ERR(svn_ra_get_file(ra_session, "", end_revnum, NULL, NULL,
+                                  &props, pool));
 
-      SVN_ERR(svn_client_propget5(&props, NULL, SVN_PROP_MIME_TYPE,
-                                  target_abspath_or_url,  peg_revision,
-                                  end, NULL, svn_depth_empty, NULL, ctx,
-                                  pool, pool));
-
-      /* props could be keyed on URLs or paths depending on the
-         peg_revision and end values so avoid using the key. */
-      hi = apr_hash_first(pool, props);
-      if (hi)
+          mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
+        }
+      else 
         {
-          svn_string_t *value;
+          const svn_string_t *value;
+
+          if (end->kind == svn_opt_revision_working)
+            SVN_ERR(svn_wc_prop_get2(&value, ctx->wc_ctx,
+                                     target_abspath_or_url,
+                                     SVN_PROP_MIME_TYPE,
+                                     pool, pool));
+          else
+            {
+              SVN_ERR(svn_wc_get_pristine_props(&props, ctx->wc_ctx,
+                                                target_abspath_or_url,
+                                                pool, pool));
+
+              value = props ? svn_hash_gets(props, SVN_PROP_MIME_TYPE)
+                            : NULL;
+            }
 
-          /* Should only be one value */
-          SVN_ERR_ASSERT(apr_hash_count(props) == 1);
+          mime_type = value ? value->data : NULL;
+        }
 
-          value = apr_hash_this_val(hi);
-          if (value && svn_mime_type_is_binary(value->data))
+      if (mime_type)
+        {
+          if (svn_mime_type_is_binary(mime_type))
             return svn_error_createf
               (SVN_ERR_CLIENT_IS_BINARY_FILE, 0,
                _("Cannot calculate blame information for binary file '%s'"),
@@ -719,6 +787,10 @@ svn_client_blame5(const char *target,
       frb.merged_chain->avail = NULL;
       frb.merged_chain->pool = pool;
     }
+  frb.backwards = (frb.start_rev > frb.end_rev);
+  frb.last_revnum = SVN_INVALID_REVNUM;
+  frb.last_props = NULL;
+  frb.check_mime_type = (frb.backwards && !ignore_mime_type);
 
   SVN_ERR(svn_ra_get_repos_root2(ra_session, &frb.repos_root_url, pool));
 
@@ -738,12 +810,11 @@ svn_client_blame5(const char *target,
      We need to ensure that we get one revision before the start_rev,
      if available so that we can know what was actually changed in the start
      revision. */
-  SVN_ERR(svn_ra_get_latest_revnum(ra_session, &youngest, frb.currpool));
   SVN_ERR(svn_ra_get_file_revs2(ra_session, "",
-                                start_revnum 
-                                - (0 < start_revnum && start_revnum <= 
end_revnum ? 1 : 0)
-                                + (youngest > start_revnum && start_revnum > 
end_revnum ? 1 : 0),
-                                end_revnum, include_merged_revisions,
+                                frb.backwards ? start_revnum
+                                              : MAX(0, start_revnum-1),
+                                end_revnum,
+                                include_merged_revisions,
                                 file_rev_handler, &frb, pool));
 
   if (end->kind == svn_opt_revision_working)

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/client.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/client.h?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/client.h 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/client.h Wed 
Feb 25 08:15:39 2015
@@ -462,17 +462,6 @@ svn_error_t *svn_client__get_all_auto_pr
                                             apr_pool_t *result_pool,
                                             apr_pool_t *scratch_pool);
 
-/* Get a list of ignore patterns defined by the svn:global-ignores
-   properties set on, or inherited by, PATH_OR_URL.  Store the collected
-   patterns as const char * elements in the array *IGNORES.  Allocate
-   *IGNORES and its contents in RESULT_POOL.  Use  SCRATCH_POOL for
-   temporary allocations. */
-svn_error_t *svn_client__get_inherited_ignores(apr_array_header_t **ignores,
-                                               const char *path_or_url,
-                                               svn_client_ctx_t *ctx,
-                                               apr_pool_t *result_pool,
-                                               apr_pool_t *scratch_pool);
-
 /* The main logic for client deletion from a working copy. Deletes PATH
    from CTX->WC_CTX.  If PATH (or any item below a directory PATH) is
    modified the delete will fail and return an error unless FORCE or KEEP_LOCAL
@@ -966,11 +955,6 @@ svn_client__get_copy_committables(svn_cl
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool);
 
-/* A qsort()-compatible sort routine for sorting an array of
-   svn_client_commit_item_t *'s by their URL member. */
-int svn_client__sort_commit_item_urls(const void *a, const void *b);
-
-
 /* Rewrite the COMMIT_ITEMS array to be sorted by URL.  Also, discover
    a common *BASE_URL for the items in the array, and rewrite those
    items' URLs to be relative to that *BASE_URL.
@@ -1215,6 +1199,41 @@ svn_client__arbitrary_nodes_diff(const c
                                  apr_pool_t *scratch_pool);
 
 
+/* Helper for the remote case of svn_client_propget.
+ *
+ * If PROPS is not null, then get the value of property PROPNAME in
+ * REVNUM, using RA_SESSION.  Store the value ('svn_string_t *') in
+ * PROPS, under the path key "TARGET_PREFIX/TARGET_RELATIVE"
+ * ('const char *').
+ *
+ * If INHERITED_PROPS is not null, then set *INHERITED_PROPS to a
+ * depth-first ordered array of svn_prop_inherited_item_t * structures
+ * representing the PROPNAME properties inherited by the target.  If
+ * INHERITABLE_PROPS in not null and no inheritable properties are found,
+ * then set *INHERITED_PROPS to an empty array.
+ *
+ * Recurse according to DEPTH, similarly to svn_client_propget3().
+ *
+ * KIND is the kind of the node at "TARGET_PREFIX/TARGET_RELATIVE".
+ * Yes, caller passes this; it makes the recursion more efficient :-).
+ *
+ * Allocate PROPS and *INHERITED_PROPS in RESULT_POOL, but do all temporary
+ * work in SCRATCH_POOL.  The two pools can be the same; recursive
+ * calls may use a different SCRATCH_POOL, however.
+ */
+svn_error_t *
+svn_client__remote_propget(apr_hash_t *props,
+                           apr_array_header_t **inherited_props,
+                           const char *propname,
+                           const char *target_prefix,
+                           const char *target_relative,
+                           svn_node_kind_t kind,
+                           svn_revnum_t revnum,
+                           svn_ra_session_t *ra_session,
+                           svn_depth_t depth,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/commit.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/commit.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/commit.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/commit.c Wed 
Feb 25 08:15:39 2015
@@ -240,10 +240,12 @@ post_process_commit_item(svn_wc_committe
     loop_recurse = TRUE;
 
   remove_lock = (! keep_locks && (item->state_flags
-                                       & SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN));
+                                       & (SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN
+                                          | SVN_CLIENT_COMMIT_ITEM_ADD
+                                          | SVN_CLIENT_COMMIT_ITEM_DELETE)));
 
-  /* When the node was deleted (or replaced), we need to always remove the 
-     locks, as they're invalidated on the server. We cannot honor the 
+  /* When the node was deleted (or replaced), we need to always remove the
+     locks, as they're invalidated on the server. We cannot honor the
      SVN_CLIENT_COMMIT_ITEM_LOCK_TOKEN flag here because it does not tell
      us whether we have locked children. */
   if (item->state_flags & SVN_CLIENT_COMMIT_ITEM_DELETE)
@@ -252,7 +254,7 @@ post_process_commit_item(svn_wc_committe
   return svn_error_trace(
          svn_wc_queue_committed4(queue, wc_ctx, item->path,
                                  loop_recurse,
-                                 0 != (item->state_flags & 
+                                 0 != (item->state_flags &
                                        (SVN_CLIENT_COMMIT_ITEM_ADD
                                         | SVN_CLIENT_COMMIT_ITEM_DELETE
                                         | SVN_CLIENT_COMMIT_ITEM_TEXT_MODS
@@ -532,6 +534,7 @@ svn_client_commit6(const apr_array_heade
   const char *current_abspath;
   const char *notify_prefix;
   int depth_empty_after = -1;
+  apr_hash_t *move_youngest = NULL;
   int i;
 
   SVN_ERR_ASSERT(depth != svn_depth_unknown && depth != svn_depth_exclude);
@@ -699,62 +702,12 @@ svn_client_commit6(const apr_array_heade
           if (cmt_err)
             goto cleanup;
 
-          if (moved_from_abspath && delete_op_root_abspath &&
-              strcmp(moved_from_abspath, delete_op_root_abspath) == 0)
-
+          if (moved_from_abspath && delete_op_root_abspath)
             {
-              svn_boolean_t found_delete_half =
-                (svn_hash_gets(committables->by_path, delete_op_root_abspath)
-                 != NULL);
+              svn_client_commit_item3_t *delete_half =
+                svn_hash_gets(committables->by_path, delete_op_root_abspath);
 
-              if (!found_delete_half)
-                {
-                  const char *delete_half_parent_abspath;
-
-                  /* The delete-half isn't in the commit target list.
-                   * However, it might itself be the child of a deleted node,
-                   * either because of another move or a deletion.
-                   *
-                   * For example, consider: mv A/B B; mv B/C C; commit;
-                   * C's moved-from A/B/C is a child of the deleted A/B.
-                   * A/B/C does not appear in the commit target list, but
-                   * A/B does appear.
-                   * (Note that moved-from information is always stored
-                   * relative to the BASE tree, so we have 'C moved-from
-                   * A/B/C', not 'C moved-from B/C'.)
-                   *
-                   * An example involving a move and a delete would be:
-                   * mv A/B C; rm A; commit;
-                   * Now C is moved-from A/B which does not appear in the
-                   * commit target list, but A does appear.
-                   */
-
-                  /* Scan upwards for a deletion op-root from the
-                   * delete-half's parent directory. */
-                  delete_half_parent_abspath =
-                    svn_dirent_dirname(delete_op_root_abspath, iterpool);
-                  if (strcmp(delete_op_root_abspath,
-                             delete_half_parent_abspath) != 0)
-                    {
-                      const char *parent_delete_op_root_abspath;
-
-                      cmt_err = svn_error_trace(
-                                  svn_wc__node_get_deleted_ancestor(
-                                    &parent_delete_op_root_abspath,
-                                    ctx->wc_ctx, delete_half_parent_abspath,
-                                    iterpool, iterpool));
-                      if (cmt_err)
-                        goto cleanup;
-
-                      if (parent_delete_op_root_abspath)
-                        found_delete_half =
-                          (svn_hash_gets(committables->by_path,
-                                         parent_delete_op_root_abspath)
-                           != NULL);
-                    }
-                }
-
-              if (!found_delete_half)
+              if (!delete_half)
                 {
                   cmt_err = svn_error_createf(
                               SVN_ERR_ILLEGAL_TARGET, NULL,
@@ -779,6 +732,17 @@ svn_client_commit6(const apr_array_heade
 
                   goto cleanup;
                 }
+              else if (delete_half->revision == item->copyfrom_rev)
+                {
+                  /* Ok, now we know that we perform an out-of-date check
+                     on the copyfrom location. Remember this for a fixup
+                     round right before committing. */
+
+                  if (!move_youngest)
+                    move_youngest = apr_hash_make(pool);
+
+                  svn_hash_sets(move_youngest, item->path, item);
+                }
             }
         }
 
@@ -877,6 +841,37 @@ svn_client_commit6(const apr_array_heade
   if (cmt_err)
     goto cleanup;
 
+  if (move_youngest != NULL)
+    {
+      apr_hash_index_t *hi;
+      svn_revnum_t youngest;
+
+      SVN_ERR(svn_ra_get_latest_revnum(ra_session, &youngest, pool));
+
+      for (hi = apr_hash_first(iterpool, move_youngest);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          svn_client_commit_item3_t *item = apr_hash_this_val(hi);
+
+          /* We delete the original side with its original revision and will
+             receive an out-of-date error if that node changed since that
+             revision.
+
+             The copy is of that same revision and we know that this revision
+             didn't change between this revision and youngest. So we can just
+             as well commit a copy from youngest.
+
+            Note that it is still possible to see gaps between the delete and
+            copy revisions as the repository might handle multiple commits
+            at the same time (or when an out of date proxy is involved), but
+            in general it should decrease the number of gaps. */
+
+          if (item->copyfrom_rev < youngest)
+            item->copyfrom_rev = youngest;
+        }
+    }
+
   cmt_err = svn_error_trace(
               get_ra_editor(&editor, &edit_baton, ra_session, ctx,
                             log_msg, commit_items, revprop_table,

Modified: 
subversion/branches/reuse-ra-session/subversion/libsvn_client/commit_util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/commit_util.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/commit_util.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/commit_util.c 
Wed Feb 25 08:15:39 2015
@@ -467,10 +467,12 @@ harvest_not_present_for_copy(svn_wc_cont
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
 
+  SVN_ERR_ASSERT(commit_relpath != NULL);
+
   /* A function to retrieve not present children would be nice to have */
-  SVN_ERR(svn_wc__node_get_children_of_working_node(
-                                    &children, wc_ctx, local_abspath, TRUE,
-                                    scratch_pool, iterpool));
+  SVN_ERR(svn_wc__node_get_not_present_children(&children, wc_ctx,
+                                                local_abspath,
+                                                scratch_pool, iterpool));
 
   for (i = 0; i < children->nelts; i++)
     {
@@ -486,13 +488,10 @@ harvest_not_present_for_copy(svn_wc_cont
                                           this_abspath, FALSE, scratch_pool));
 
       if (!not_present)
-        continue;
+        continue; /* Node is replaced */
 
-      if (commit_relpath == NULL)
-        this_commit_relpath = NULL;
-      else
-        this_commit_relpath = svn_relpath_join(commit_relpath, name,
-                                              iterpool);
+      this_commit_relpath = svn_relpath_join(commit_relpath, name,
+                                             iterpool);
 
       /* We should check if we should really add a delete operation */
       if (check_url_func)
@@ -1380,7 +1379,10 @@ svn_client__get_copy_committables(svn_cl
 }
 
 
-int svn_client__sort_commit_item_urls(const void *a, const void *b)
+/* A svn_sort__array()/qsort()-compatible sort routine for sorting
+   an array of svn_client_commit_item_t *'s by their URL member. */
+static int
+sort_commit_item_urls(const void *a, const void *b)
 {
   const svn_client_commit_item3_t *item1
     = *((const svn_client_commit_item3_t * const *) a);
@@ -1404,7 +1406,7 @@ svn_client__condense_commit_items(const
   SVN_ERR_ASSERT(ci && ci->nelts);
 
   /* Sort our commit items by their URLs. */
-  svn_sort__array(ci, svn_client__sort_commit_item_urls);
+  svn_sort__array(ci, sort_commit_item_urls);
 
   /* Loop through the URLs, finding the longest usable ancestor common
      to all of them, and making sure there are no duplicate URLs.  */
@@ -1559,7 +1561,7 @@ do_item_commit(void **dir_baton,
     file_pool = pool;
 
   /* Subpools are cheap, but memory isn't */
-  file_pool = svn_pool_create(file_pool); 
+  file_pool = svn_pool_create(file_pool);
 
   /* Call the cancellation function. */
   if (ctx->cancel_func)

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/copy.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/copy.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/copy.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/copy.c Wed 
Feb 25 08:15:39 2015
@@ -177,12 +177,487 @@ get_copy_pair_ancestors(const apr_array_
   return SVN_NO_ERROR;
 }
 
+/* Quote a string if it would be handled as multiple or different tokens
+   during externals parsing */
+static const char *
+maybe_quote(const char *value,
+            apr_pool_t *result_pool)
+{
+  apr_status_t status;
+  char **argv;
+
+  status = apr_tokenize_to_argv(value, &argv, result_pool);
+
+  if (!status && argv[0] && !argv[1] && strcmp(argv[0], value) == 0)
+    return apr_pstrdup(result_pool, value);
+
+  {
+    svn_stringbuf_t *sb = svn_stringbuf_create_empty(result_pool);
+    const char *c;
+
+    svn_stringbuf_appendbyte(sb, '\"');
+
+    for (c = value; *c; c++)
+      {
+        if (*c == '\\' || *c == '\"' || *c == '\'')
+          svn_stringbuf_appendbyte(sb, '\\');
+
+        svn_stringbuf_appendbyte(sb, *c);
+      }
+
+    svn_stringbuf_appendbyte(sb, '\"');
+
+#ifdef SVN_DEBUG
+    status = apr_tokenize_to_argv(sb->data, &argv, result_pool);
+
+    SVN_ERR_ASSERT_NO_RETURN(!status && argv[0] && !argv[1]
+                             && !strcmp(argv[0], value));
+#endif
+
+    return sb->data;
+  }
+}
+
+/* In *NEW_EXTERNALS_DESCRIPTION, return a new external description for
+ * use as a line in an svn:externals property, based on the external item
+ * ITEM and the additional parser information in INFO. Pin the external
+ * to EXTERNAL_PEGREV. Use POOL for all allocations. */
+static svn_error_t *
+make_external_description(const char **new_external_description,
+                          const char *local_abspath_or_url,
+                          svn_wc_external_item2_t *item,
+                          svn_wc__externals_parser_info_t *info,
+                          svn_opt_revision_t external_pegrev,
+                          apr_pool_t *pool)
+{
+  const char *rev_str;
+  const char *peg_rev_str;
+
+  switch (info->format)
+    {
+      case svn_wc__external_description_format_1:
+        if (external_pegrev.kind == svn_opt_revision_unspecified)
+          {
+            /* If info->rev_str is NULL, this yields an empty string. */
+            rev_str = apr_pstrcat(pool, info->rev_str, " ", SVN_VA_NULL);
+          }
+        else if (info->rev_str && item->revision.kind != svn_opt_revision_head)
+          rev_str = apr_psprintf(pool, "%s ", info->rev_str);
+        else
+          {
+            /* ### can't handle svn_opt_revision_date without info->rev_str */
+            SVN_ERR_ASSERT(external_pegrev.kind == svn_opt_revision_number);
+            rev_str = apr_psprintf(pool, "-r%ld ",
+                                   external_pegrev.value.number);
+          }
+
+        *new_external_description =
+          apr_psprintf(pool, "%s %s%s\n", maybe_quote(item->target_dir, pool),
+                                          rev_str,
+                                          maybe_quote(item->url, pool));
+        break;
+
+      case svn_wc__external_description_format_2:
+        if (external_pegrev.kind == svn_opt_revision_unspecified)
+          {
+            /* If info->rev_str is NULL, this yields an empty string. */
+            rev_str = apr_pstrcat(pool, info->rev_str, " ", SVN_VA_NULL);
+          }
+        else if (info->rev_str && item->revision.kind != svn_opt_revision_head)
+          rev_str = apr_psprintf(pool, "%s ", info->rev_str);
+        else
+          rev_str = "";
+
+        if (external_pegrev.kind == svn_opt_revision_unspecified)
+          peg_rev_str = info->peg_rev_str ? info->peg_rev_str : "";
+        else if (info->peg_rev_str &&
+                 item->peg_revision.kind != svn_opt_revision_head)
+          peg_rev_str = info->peg_rev_str;
+        else
+          {
+            /* ### can't handle svn_opt_revision_date without info->rev_str */
+            SVN_ERR_ASSERT(external_pegrev.kind == svn_opt_revision_number);
+            peg_rev_str = apr_psprintf(pool, "@%ld",
+                                       external_pegrev.value.number);
+          }
+
+        *new_external_description =
+          apr_psprintf(pool, "%s%s %s\n", rev_str,
+                       maybe_quote(apr_psprintf(pool, "%s%s", item->url,
+                                                peg_rev_str),
+                                   pool),
+                       maybe_quote(item->target_dir, pool));
+        break;
+
+      default:
+        return svn_error_createf(
+                 SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
+                 _("%s property defined at '%s' is using an unsupported "
+                   "syntax"), SVN_PROP_EXTERNALS,
+                 svn_dirent_local_style(local_abspath_or_url, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Pin all externals listed in EXTERNALS_PROP_VAL to their last-changed
+ * revision. Return a new property value in *PINNED_EXTERNALS allocated
+ * in RESULT_POOL. LOCAL_ABSPATH_OR_URL is the path or URL defining the
+ * svn:externals property. Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+pin_externals_prop(svn_string_t **pinned_externals,
+                   svn_string_t *externals_prop_val,
+                   const apr_hash_t *externals_to_pin,
+                   const char *repos_root_url,
+                   const char *local_abspath_or_url,
+                   svn_client_ctx_t *ctx,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  svn_stringbuf_t *buf;
+  apr_array_header_t *external_items;
+  apr_array_header_t *parser_infos;
+  apr_array_header_t *items_to_pin;
+  int i;
+  apr_pool_t *iterpool;
+
+  SVN_ERR(svn_wc__parse_externals_description(&external_items,
+                                              &parser_infos,
+                                              local_abspath_or_url,
+                                              externals_prop_val->data,
+                                              FALSE /* canonicalize_url */,
+                                              scratch_pool));
+
+  if (externals_to_pin)
+    items_to_pin = svn_hash_gets((apr_hash_t *)externals_to_pin,
+                                 local_abspath_or_url);
+  else
+    items_to_pin = NULL;
+
+  buf = svn_stringbuf_create_empty(scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < external_items->nelts; i++)
+    {
+      svn_wc_external_item2_t *item;
+      svn_wc__externals_parser_info_t *info;
+      svn_opt_revision_t external_pegrev;
+      const char *pinned_desc;
+
+      svn_pool_clear(iterpool);
+
+      item = APR_ARRAY_IDX(external_items, i, svn_wc_external_item2_t *);
+      info = APR_ARRAY_IDX(parser_infos, i, svn_wc__externals_parser_info_t *);
+
+      if (items_to_pin)
+        {
+          int j;
+          svn_wc_external_item2_t *item_to_pin = NULL;
+
+          for (j = 0; j < items_to_pin->nelts; j++)
+            {
+              svn_wc_external_item2_t *const current =
+                APR_ARRAY_IDX(items_to_pin, j, svn_wc_external_item2_t *);
+
+
+              if (current
+                  && 0 == strcmp(item->url, current->url)
+                  && 0 == strcmp(item->target_dir, current->target_dir))
+                {
+                  item_to_pin = current;
+                  break;
+                }
+            }
+
+          /* If this item is not in our list of external items to pin then
+           * simply keep the external at its original value. */
+          if (!item_to_pin)
+            {
+              const char *desc;
+
+              external_pegrev.kind = svn_opt_revision_unspecified;
+              SVN_ERR(make_external_description(&desc, local_abspath_or_url,
+                                                item, info, external_pegrev,
+                                                iterpool));
+              svn_stringbuf_appendcstr(buf, desc);
+              continue;
+            }
+        }
+
+      if (item->peg_revision.kind == svn_opt_revision_date)
+        {
+          external_pegrev.kind = svn_opt_revision_date;
+          external_pegrev.value.date = item->peg_revision.value.date;
+        }
+      else if (item->peg_revision.kind == svn_opt_revision_number)
+        {
+          external_pegrev.kind = svn_opt_revision_number;
+          external_pegrev.value.number = item->peg_revision.value.number;
+        }
+      else
+        {
+          SVN_ERR_ASSERT(
+            item->peg_revision.kind == svn_opt_revision_head ||
+            item->peg_revision.kind == svn_opt_revision_unspecified);
+
+          if (svn_path_is_url(local_abspath_or_url))
+            {
+              const char *resolved_url;
+              svn_ra_session_t *external_ra_session;
+              svn_revnum_t latest_revnum;
+
+              SVN_ERR(svn_wc__resolve_relative_external_url(
+                        &resolved_url, item, repos_root_url,
+                        local_abspath_or_url, iterpool, iterpool));
+              
SVN_ERR(svn_client__open_ra_session_internal(&external_ra_session,
+                                                           NULL, resolved_url,
+                                                           NULL, NULL, FALSE,
+                                                           FALSE, ctx,
+                                                           iterpool,
+                                                           iterpool));
+              SVN_ERR(svn_ra_get_latest_revnum(external_ra_session,
+                                               &latest_revnum,
+                                               iterpool));
+
+              external_pegrev.kind = svn_opt_revision_number;
+              external_pegrev.value.number = latest_revnum;
+            }
+          else
+            {
+              const char *external_abspath;
+              svn_node_kind_t external_kind;
+              svn_revnum_t external_checked_out_rev;
+
+              external_abspath = svn_dirent_join(local_abspath_or_url,
+                                                 item->target_dir,
+                                                 iterpool);
+              SVN_ERR(svn_wc__read_external_info(&external_kind, NULL, NULL,
+                                                 NULL, NULL, ctx->wc_ctx,
+                                                 local_abspath_or_url,
+                                                 external_abspath, TRUE,
+                                                 iterpool,
+                                                 iterpool));
+              if (external_kind == svn_node_none)
+                return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+                                         NULL,
+                                         _("Cannot pin external '%s' defined "
+                                           "in %s at '%s' because it is not "
+                                           "checked out in the working copy "
+                                           "at '%s'"),
+                                           item->url, SVN_PROP_EXTERNALS,
+                                           svn_dirent_local_style(
+                                             local_abspath_or_url, iterpool),
+                                           svn_dirent_local_style(
+                                             external_abspath, iterpool));
+              else if (external_kind == svn_node_dir)
+                {
+                  svn_boolean_t is_switched;
+                  svn_boolean_t is_modified;
+                  svn_revnum_t min_rev;
+                  svn_revnum_t max_rev;
+
+                  /* Perform some sanity checks on the checked-out external. */
+
+                  SVN_ERR(svn_wc__has_switched_subtrees(&is_switched,
+                                                        ctx->wc_ctx,
+                                                        external_abspath, NULL,
+                                                        iterpool));
+                  if (is_switched)
+                    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+                                             NULL,
+                                             _("Cannot pin external '%s' 
defined "
+                                               "in %s at '%s' because '%s' has 
"
+                                               "switched subtrees (switches "
+                                               "cannot be represented in %s)"),
+                                             item->url, SVN_PROP_EXTERNALS,
+                                             svn_dirent_local_style(
+                                               local_abspath_or_url, iterpool),
+                                             svn_dirent_local_style(
+                                               external_abspath, iterpool),
+                                             SVN_PROP_EXTERNALS);
+
+                  SVN_ERR(svn_wc__has_local_mods(&is_modified, ctx->wc_ctx,
+                                                 external_abspath, TRUE,
+                                                 ctx->cancel_func,
+                                                 ctx->cancel_baton,
+                                                 iterpool));
+                  if (is_modified)
+                    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+                                             NULL,
+                                             _("Cannot pin external '%s' 
defined "
+                                               "in %s at '%s' because '%s' has 
"
+                                               "local modifications (local "
+                                               "modifications cannot be "
+                                               "represented in %s)"),
+                                             item->url, SVN_PROP_EXTERNALS,
+                                             svn_dirent_local_style(
+                                               local_abspath_or_url, iterpool),
+                                             svn_dirent_local_style(
+                                               external_abspath, iterpool),
+                                             SVN_PROP_EXTERNALS);
+
+                  SVN_ERR(svn_wc__min_max_revisions(&min_rev, &max_rev, 
ctx->wc_ctx,
+                                                    external_abspath, FALSE,
+                                                    iterpool));
+                  if (min_rev != max_rev)
+                    return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+                                             NULL,
+                                             _("Cannot pin external '%s' 
defined "
+                                               "in %s at '%s' because '%s' is 
a "
+                                               "mixed-revision working copy "
+                                               "(mixed-revisions cannot be "
+                                               "represented in %s)"),
+                                             item->url, SVN_PROP_EXTERNALS,
+                                             svn_dirent_local_style(
+                                               local_abspath_or_url, iterpool),
+                                             svn_dirent_local_style(
+                                               external_abspath, iterpool),
+                                             SVN_PROP_EXTERNALS);
+                  external_checked_out_rev = min_rev;
+                }
+              else
+                {
+                  SVN_ERR_ASSERT(external_kind == svn_node_file);
+                  
SVN_ERR(svn_wc__node_get_repos_info(&external_checked_out_rev,
+                                                      NULL, NULL, NULL,
+                                                      ctx->wc_ctx, 
external_abspath,
+                                                      iterpool, iterpool));
+                }
+
+              external_pegrev.kind = svn_opt_revision_number;
+              external_pegrev.value.number = external_checked_out_rev;
+            }
+        }
+
+      SVN_ERR_ASSERT(external_pegrev.kind == svn_opt_revision_date ||
+                     external_pegrev.kind == svn_opt_revision_number);
+
+      SVN_ERR(make_external_description(&pinned_desc, local_abspath_or_url,
+                                        item, info, external_pegrev, 
iterpool));
+
+      svn_stringbuf_appendcstr(buf, pinned_desc);
+    }
+  svn_pool_destroy(iterpool);
+
+  *pinned_externals = svn_string_create_from_buf(buf, result_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Return, in *NEW_EXTERNALS, a new hash of externals definitions, some or
+ * which all of which are pinned. If EXTERNALS_TO_PIN is NULL, pin all
+ * externals, else pin the externals mentioned in EXTERNALS_TO_PIN.
+ * The pinning operation takes place as part of the copy operation for
+ * the source/destination pair PAIR. Use RA_SESSION and REPOS_ROOT_URL
+ * to contact the repository containing the externals definition, if neccesary.
+ * Use CX to fopen additional RA sessions to external repositories, if
+ * neccessary. Allocate *NEW_EXTERNALS in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+resolve_pinned_externals(apr_hash_t **new_externals,
+                         const apr_hash_t *externals_to_pin,
+                         svn_client__copy_pair_t *pair,
+                         svn_ra_session_t *ra_session,
+                         const char *repos_root_url,
+                         svn_client_ctx_t *ctx,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
+{
+  const char *old_url = NULL;
+  apr_hash_t *externals_props;
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
+
+  *new_externals = apr_hash_make(result_pool);
+
+  if (svn_path_is_url(pair->src_abspath_or_url))
+    {
+      SVN_ERR(svn_client__ensure_ra_session_url(&old_url, ra_session,
+                                                pair->src_abspath_or_url,
+                                                scratch_pool));
+      externals_props = apr_hash_make(scratch_pool);
+      SVN_ERR(svn_client__remote_propget(externals_props, NULL,
+                                         SVN_PROP_EXTERNALS,
+                                         pair->src_abspath_or_url, "",
+                                         svn_node_dir,
+                                         pair->src_revnum,
+                                         ra_session,
+                                         svn_depth_infinity,
+                                         scratch_pool,
+                                         scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(svn_wc__externals_gather_definitions(&externals_props, NULL,
+                                                   ctx->wc_ctx,
+                                                   pair->src_abspath_or_url,
+                                                   svn_depth_infinity,
+                                                   scratch_pool, 
scratch_pool));
+
+      /* ### gather_definitions returns propvals as const char * */
+      for (hi = apr_hash_first(scratch_pool, externals_props);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *local_abspath_or_url = apr_hash_this_key(hi);
+          const char *propval = apr_hash_this_val(hi);
+          svn_string_t *new_propval = svn_string_create(propval, scratch_pool);
+
+          svn_hash_sets(externals_props, local_abspath_or_url, new_propval);
+        }
+    }
+
+  if (apr_hash_count(externals_props) == 0)
+    {
+      if (old_url)
+        SVN_ERR(svn_ra_reparent(ra_session, old_url, scratch_pool));
+      return SVN_NO_ERROR;
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (hi = apr_hash_first(scratch_pool, externals_props);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *local_abspath_or_url = apr_hash_this_key(hi);
+      svn_string_t *externals_propval = apr_hash_this_val(hi);
+      const char *relpath;
+      svn_string_t *new_propval;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(pin_externals_prop(&new_propval, externals_propval,
+                                 externals_to_pin,
+                                 repos_root_url, local_abspath_or_url, ctx,
+                                 result_pool, iterpool));
+      if (svn_path_is_url(pair->src_abspath_or_url))
+        relpath = svn_uri_skip_ancestor(pair->src_abspath_or_url,
+                                        local_abspath_or_url,
+                                        result_pool);
+      else
+        relpath = svn_dirent_skip_ancestor(pair->src_abspath_or_url,
+                                           local_abspath_or_url);
+      SVN_ERR_ASSERT(relpath);
+      svn_hash_sets(*new_externals, relpath, new_propval);
+    }
+  svn_pool_destroy(iterpool);
+
+  if (old_url)
+    SVN_ERR(svn_ra_reparent(ra_session, old_url, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+
 
 /* The guts of do_wc_to_wc_copies */
 static svn_error_t *
 do_wc_to_wc_copies_with_write_lock(svn_boolean_t *timestamp_sleep,
                                    const apr_array_header_t *copy_pairs,
                                    const char *dst_parent,
+                                   svn_boolean_t metadata_only,
+                                   svn_boolean_t pin_externals,
+                                   const apr_hash_t *externals_to_pin,
                                    svn_client_ctx_t *ctx,
                                    apr_pool_t *scratch_pool)
 {
@@ -195,22 +670,63 @@ do_wc_to_wc_copies_with_write_lock(svn_b
       const char *dst_abspath;
       svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
                                                     svn_client__copy_pair_t *);
+      apr_hash_t *pinned_externals = NULL;
+
       svn_pool_clear(iterpool);
 
       /* Check for cancellation */
       if (ctx->cancel_func)
         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
+      if (pin_externals)
+        {
+          const char *repos_root_url;
+
+          SVN_ERR(svn_wc__node_get_origin(NULL, NULL, NULL, &repos_root_url,
+                                          NULL, NULL, NULL, ctx->wc_ctx,
+                                          pair->src_abspath_or_url, FALSE,
+                                          scratch_pool, iterpool));
+          SVN_ERR(resolve_pinned_externals(&pinned_externals,
+                                           externals_to_pin, pair, NULL,
+                                           repos_root_url, ctx,
+                                           iterpool, iterpool));
+        }
+
       /* Perform the copy */
       dst_abspath = svn_dirent_join(pair->dst_parent_abspath, pair->base_name,
                                     iterpool);
       *timestamp_sleep = TRUE;
       err = svn_wc_copy3(ctx->wc_ctx, pair->src_abspath_or_url, dst_abspath,
-                         FALSE /* metadata_only */,
+                         metadata_only,
                          ctx->cancel_func, ctx->cancel_baton,
                          ctx->notify_func2, ctx->notify_baton2, iterpool);
       if (err)
         break;
+
+      if (pinned_externals)
+        {
+          apr_hash_index_t *hi;
+
+          for (hi = apr_hash_first(iterpool, pinned_externals);
+               hi;
+               hi = apr_hash_next(hi))
+            {
+              const char *dst_relpath = apr_hash_this_key(hi);
+              svn_string_t *externals_propval = apr_hash_this_val(hi);
+              const char *local_abspath;
+
+              local_abspath = svn_dirent_join(pair->dst_abspath_or_url,
+                                              dst_relpath, iterpool);
+              /* ### use a work queue? */
+              SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath,
+                                       SVN_PROP_EXTERNALS, externals_propval,
+                                       svn_depth_empty, TRUE /* skip_checks */,
+                                       NULL  /* changelist_filter */,
+                                       ctx->cancel_func, ctx->cancel_baton,
+                                       NULL, NULL, /* no extra notification */
+                                       iterpool));
+            }
+        }
     }
   svn_pool_destroy(iterpool);
 
@@ -223,6 +739,9 @@ do_wc_to_wc_copies_with_write_lock(svn_b
 static svn_error_t *
 do_wc_to_wc_copies(svn_boolean_t *timestamp_sleep,
                    const apr_array_header_t *copy_pairs,
+                   svn_boolean_t metadata_only,
+                   svn_boolean_t pin_externals,
+                   const apr_hash_t *externals_to_pin,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
 {
@@ -236,7 +755,8 @@ do_wc_to_wc_copies(svn_boolean_t *timest
 
   SVN_WC__CALL_WITH_WRITE_LOCK(
     do_wc_to_wc_copies_with_write_lock(timestamp_sleep, copy_pairs, dst_parent,
-                                       ctx, pool),
+                                       metadata_only, pin_externals,
+                                       externals_to_pin, ctx, pool),
     ctx->wc_ctx, dst_parent_abspath, FALSE, pool);
 
   return SVN_NO_ERROR;
@@ -594,6 +1114,8 @@ typedef struct path_driver_info_t
   svn_boolean_t resurrection;
   svn_boolean_t dir_add;
   svn_string_t *mergeinfo;  /* the new mergeinfo for the target */
+  svn_string_t *externals; /* new externals definitions for the target */
+  svn_boolean_t only_pin_externals;
 } path_driver_info_t;
 
 
@@ -631,7 +1153,7 @@ path_driver_cb_func(void **dir_baton,
      with such, the code is just plain wrong. */
   SVN_ERR_ASSERT(! svn_path_is_empty(path));
 
-  /* Check to see if we need to add the path as a directory. */
+  /* Check to see if we need to add the path as a parent directory. */
   if (path_info->dir_add)
     {
       return cb_baton->editor->add_directory(path, parent_baton, NULL,
@@ -662,7 +1184,7 @@ path_driver_cb_func(void **dir_baton,
       /* Not a move?  This must just be the copy addition. */
       else
         {
-          do_add = TRUE;
+          do_add = !path_info->only_pin_externals;
         }
     }
 
@@ -702,6 +1224,18 @@ path_driver_cb_func(void **dir_baton,
                                                       pool));
         }
     }
+
+  if (path_info->externals)
+    {
+      if (*dir_baton == NULL)
+        SVN_ERR(cb_baton->editor->open_directory(path, parent_baton,
+                                                 SVN_INVALID_REVNUM,
+                                                 pool, dir_baton));
+
+      SVN_ERR(cb_baton->editor->change_dir_prop(*dir_baton, SVN_PROP_EXTERNALS,
+                                                path_info->externals, pool));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -786,6 +1320,79 @@ find_absent_parents2(svn_ra_session_t *r
   return SVN_NO_ERROR;
 }
 
+/* Queue property changes for pinning svn:externals properties set on
+ * descendants of the path corresponding to PARENT_INFO. PINNED_EXTERNALS
+ * is keyed by the relative path of each descendant which should have some
+ * or all of its externals pinned, with the corresponding pinned svn:externals
+ * properties as values. Property changes are queued in a new list of path
+ * infos *NEW_PATH_INFOS, or in an existing item of the PATH_INFOS list if an
+ * existing item is found for the descendant. Allocate results in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+queue_externals_change_path_infos(apr_array_header_t *new_path_infos,
+                                  apr_array_header_t *path_infos,
+                                  apr_hash_t *pinned_externals,
+                                  path_driver_info_t *parent_info,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, pinned_externals);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *dst_relpath = apr_hash_this_key(hi);
+      svn_string_t *externals_prop = apr_hash_this_val(hi);
+      const char *src_url;
+      path_driver_info_t *info;
+      int i;
+
+      svn_pool_clear(iterpool);
+
+      src_url = svn_path_url_add_component2(parent_info->src_url,
+                                            dst_relpath, iterpool);
+
+      /* Try to find a path info the external change can be applied to. */
+      info = NULL;
+      for (i = 0; i < path_infos->nelts; i++)
+        {
+          path_driver_info_t *existing_info;
+
+          existing_info = APR_ARRAY_IDX(path_infos, i, path_driver_info_t *);
+          if (strcmp(src_url, existing_info->src_url) == 0)
+            {
+              info = existing_info;
+              break;
+            }
+        }
+
+      if (info == NULL)
+        {
+          /* A copied-along child needs its externals pinned.
+             Create a new path info for this property change. */
+          info = apr_pcalloc(result_pool, sizeof(*info));
+          info->src_url = svn_path_url_add_component2(
+                                parent_info->src_url, dst_relpath,
+                                result_pool);
+          info->src_path = NULL; /* Only needed on copied dirs */
+          info->dst_path = svn_relpath_join(parent_info->dst_path,
+                                            dst_relpath,
+                                            result_pool);
+          info->src_kind = svn_node_dir;
+          info->only_pin_externals = TRUE;
+          APR_ARRAY_PUSH(new_path_infos, path_driver_info_t *) = info;
+        }
+
+      info->externals = externals_prop;
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 repos_to_repos_copy(const apr_array_header_t *copy_pairs,
                     svn_boolean_t make_parents,
@@ -794,6 +1401,8 @@ repos_to_repos_copy(const apr_array_head
                     void *commit_baton,
                     svn_client_ctx_t *ctx,
                     svn_boolean_t is_move,
+                    svn_boolean_t pin_externals,
+                    const apr_hash_t *externals_to_pin,
                     apr_pool_t *pool)
 {
   svn_error_t *err;
@@ -809,6 +1418,7 @@ repos_to_repos_copy(const apr_array_head
   struct path_driver_cb_baton cb_baton;
   apr_array_header_t *new_dirs = NULL;
   apr_hash_t *commit_revprops;
+  apr_array_header_t *pin_externals_only_infos = NULL;
   int i;
   svn_client__copy_pair_t *first_pair =
     APR_ARRAY_IDX(copy_pairs, 0, svn_client__copy_pair_t *);
@@ -1067,12 +1677,31 @@ repos_to_repos_copy(const apr_array_head
         }
 
       /* More info for our INFO structure.  */
-      info->src_path = src_rel;
+      info->src_path = src_rel; /* May be NULL, if outside RA session scope */
       info->dst_path = dst_rel;
 
       svn_hash_sets(action_hash, info->dst_path, info);
       if (is_move && (! info->resurrection))
         svn_hash_sets(action_hash, info->src_path, info);
+
+      if (pin_externals)
+        {
+          apr_hash_t *pinned_externals;
+
+          SVN_ERR(resolve_pinned_externals(&pinned_externals,
+                                           externals_to_pin, pair,
+                                           ra_session, repos_root,
+                                           ctx, pool, pool));
+          if (pin_externals_only_infos == NULL)
+            {
+              pin_externals_only_infos =
+                apr_array_make(pool, 0, sizeof(path_driver_info_t *));
+            }
+          SVN_ERR(queue_externals_change_path_infos(pin_externals_only_infos,
+                                                    path_infos,
+                                                    pinned_externals,
+                                                    info, pool, pool));
+        }
     }
 
   if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
@@ -1164,6 +1793,19 @@ repos_to_repos_copy(const apr_array_head
         APR_ARRAY_PUSH(paths, const char *) = info->src_path;
     }
 
+  /* Add any items which only need their externals pinned. */
+  if (pin_externals_only_infos)
+    {
+      for (i = 0; i < pin_externals_only_infos->nelts; i++)
+        {
+          path_driver_info_t *info;
+
+          info = APR_ARRAY_IDX(pin_externals_only_infos, i, path_driver_info_t 
*);
+          APR_ARRAY_PUSH(paths, const char *) = info->dst_path;
+          svn_hash_sets(action_hash, info->dst_path, info);
+        }
+    }
+
   SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
                                            message, ctx, pool));
 
@@ -1244,6 +1886,62 @@ check_url_kind(void *baton,
   return SVN_NO_ERROR;
 }
 
+/* Queue a property change on a copy of LOCAL_ABSPATH to COMMIT_URL
+ * in the COMMIT_ITEMS list.
+ * If the list does not already have a commit item for COMMIT_URL
+ * add a new commit item for the property change.
+ * Allocate results in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+queue_prop_change_commit_items(const char *local_abspath,
+                               const char *commit_url,
+                               apr_array_header_t *commit_items,
+                               const char *propname,
+                               svn_string_t *propval,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  svn_client_commit_item3_t *item = NULL;
+  svn_prop_t *prop;
+  int i;
+
+  for (i = 0; i < commit_items->nelts; i++)
+    {
+      svn_client_commit_item3_t *existing_item;
+
+      existing_item = APR_ARRAY_IDX(commit_items, i,
+                                    svn_client_commit_item3_t *);
+      if (strcmp(existing_item->url, commit_url) == 0)
+        {
+          item = existing_item;
+          break;
+        }
+    }
+
+  if (item == NULL)
+    {
+      item = svn_client_commit_item3_create(result_pool);
+      item->path = local_abspath;
+      item->url = commit_url;
+      item->kind = svn_node_dir;
+      item->state_flags = SVN_CLIENT_COMMIT_ITEM_PROP_MODS;
+      APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
+    }
+  else
+    item->state_flags |= SVN_CLIENT_COMMIT_ITEM_PROP_MODS;
+
+  if (item->outgoing_prop_changes == NULL)
+    item->outgoing_prop_changes = apr_array_make(result_pool, 1,
+                                                 sizeof(svn_prop_t *));
+
+  prop = apr_palloc(result_pool, sizeof(*prop));
+  prop->name = propname;
+  prop->value = propval;
+  APR_ARRAY_PUSH(item->outgoing_prop_changes, svn_prop_t *) = prop;
+
+  return SVN_NO_ERROR;
+}
+
 /* ### Copy ...
  * COMMIT_INFO_P is ...
  * COPY_PAIRS is ... such that each 'src_abspath_or_url' is a local abspath
@@ -1257,6 +1955,8 @@ wc_to_repos_copy(const apr_array_header_
                  const apr_hash_t *revprop_table,
                  svn_commit_callback2_t commit_callback,
                  void *commit_baton,
+                 svn_boolean_t pin_externals,
+                 const apr_hash_t *externals_to_pin,
                  svn_client_ctx_t *ctx,
                  apr_pool_t *scratch_pool)
 {
@@ -1453,6 +2153,43 @@ wc_to_repos_copy(const apr_array_header_
           APR_ARRAY_PUSH(item->outgoing_prop_changes, svn_prop_t *)
             = mergeinfo_prop;
         }
+
+      if (pin_externals)
+        {
+          apr_hash_t *pinned_externals;
+          apr_hash_index_t *hi;
+
+          SVN_ERR(resolve_pinned_externals(&pinned_externals,
+                                           externals_to_pin, pair,
+                                           ra_session, cukb.repos_root_url,
+                                           ctx, scratch_pool, iterpool));
+          for (hi = apr_hash_first(scratch_pool, pinned_externals);
+               hi;
+               hi = apr_hash_next(hi))
+            {
+              const char *dst_relpath = apr_hash_this_key(hi);
+              svn_string_t *externals_propval = apr_hash_this_val(hi);
+              const char *dst_url;
+              const char *commit_url;
+              const char *src_abspath;
+
+              if (svn_path_is_url(pair->dst_abspath_or_url))
+                dst_url = pair->dst_abspath_or_url;
+              else
+                SVN_ERR(svn_wc__node_get_url(&dst_url, ctx->wc_ctx,
+                                             pair->dst_abspath_or_url,
+                                             scratch_pool, iterpool));
+              commit_url = svn_path_url_add_component2(dst_url, dst_relpath,
+                                                       scratch_pool);
+              src_abspath = svn_dirent_join(pair->src_abspath_or_url,
+                                            dst_relpath, iterpool);
+              SVN_ERR(queue_prop_change_commit_items(src_abspath,
+                                                     commit_url, commit_items,
+                                                     SVN_PROP_EXTERNALS,
+                                                     externals_propval,
+                                                     scratch_pool, iterpool));
+            }
+        }
     }
 
   if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
@@ -1574,6 +2311,8 @@ repos_to_wc_copy_single(svn_boolean_t *t
                         svn_client__copy_pair_t *pair,
                         svn_boolean_t same_repositories,
                         svn_boolean_t ignore_externals,
+                        svn_boolean_t pin_externals,
+                        const apr_hash_t *externals_to_pin,
                         svn_ra_session_t *ra_session,
                         svn_client_ctx_t *ctx,
                         apr_pool_t *pool)
@@ -1630,6 +2369,14 @@ repos_to_wc_copy_single(svn_boolean_t *t
             ctx->notify_func2 = notification_adjust_func;
             ctx->notify_baton2 = &nb;
 
+            /* Avoid a chicken-and-egg problem:
+             * If pinning externals we'll need to adjust externals
+             * properties before checking out any externals.
+             * But copy needs to happen before pinning because else there
+             * are no svn:externals properties to pin. */
+            if (pin_externals)
+              ignore_externals = TRUE;
+
             err = svn_client__checkout_internal(&pair->src_revnum, 
timestamp_sleep,
                                                 pair->src_original,
                                                 tmp_abspath,
@@ -1682,6 +2429,61 @@ repos_to_wc_copy_single(svn_boolean_t *t
 
           return SVN_NO_ERROR;
         }
+
+      if (pin_externals)
+        {
+          apr_hash_t *pinned_externals;
+          apr_hash_index_t *hi;
+          apr_pool_t *iterpool;
+          const char *repos_root_url;
+          apr_hash_t *new_externals;
+          apr_hash_t *new_depths;
+
+          SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root_url, pool));
+          SVN_ERR(resolve_pinned_externals(&pinned_externals,
+                                           externals_to_pin, pair,
+                                           ra_session, repos_root_url,
+                                           ctx, pool, pool));
+
+          iterpool = svn_pool_create(pool);
+          for (hi = apr_hash_first(pool, pinned_externals);
+               hi;
+               hi = apr_hash_next(hi))
+            {
+              const char *dst_relpath = apr_hash_this_key(hi);
+              svn_string_t *externals_propval = apr_hash_this_val(hi);
+              const char *local_abspath;
+
+              svn_pool_clear(iterpool);
+
+              local_abspath = svn_dirent_join(pair->dst_abspath_or_url,
+                                              dst_relpath, iterpool);
+              /* ### use a work queue? */
+              SVN_ERR(svn_wc_prop_set4(ctx->wc_ctx, local_abspath,
+                                       SVN_PROP_EXTERNALS, externals_propval,
+                                       svn_depth_empty, TRUE /* skip_checks */,
+                                       NULL  /* changelist_filter */,
+                                       ctx->cancel_func, ctx->cancel_baton,
+                                       NULL, NULL, /* no extra notification */
+                                       iterpool));
+            }
+
+          /* Now update all externals in the newly created copy. */
+          SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
+                                                       &new_depths,
+                                                       ctx->wc_ctx,
+                                                       dst_abspath,
+                                                       svn_depth_infinity,
+                                                       iterpool, iterpool));
+          SVN_ERR(svn_client__handle_externals(new_externals,
+                                               new_depths,
+                                               repos_root_url, dst_abspath,
+                                               svn_depth_infinity,
+                                               timestamp_sleep,
+                                               ra_session,
+                                               ctx, iterpool));
+          svn_pool_destroy(iterpool);
+        }
     } /* end directory case */
 
   else if (pair->src_kind == svn_node_file)
@@ -1741,6 +2543,8 @@ repos_to_wc_copy_locked(svn_boolean_t *t
                         const apr_array_header_t *copy_pairs,
                         const char *top_dst_path,
                         svn_boolean_t ignore_externals,
+                        svn_boolean_t pin_externals,
+                        const apr_hash_t *externals_to_pin,
                         svn_ra_session_t *ra_session,
                         svn_client_ctx_t *ctx,
                         apr_pool_t *scratch_pool)
@@ -1806,6 +2610,7 @@ repos_to_wc_copy_locked(svn_boolean_t *t
                                                     svn_client__copy_pair_t *),
                                       same_repositories,
                                       ignore_externals,
+                                      pin_externals, externals_to_pin,
                                       ra_session, ctx, iterpool));
     }
   svn_pool_destroy(iterpool);
@@ -1818,6 +2623,8 @@ repos_to_wc_copy(svn_boolean_t *timestam
                  const apr_array_header_t *copy_pairs,
                  svn_boolean_t make_parents,
                  svn_boolean_t ignore_externals,
+                 svn_boolean_t pin_externals,
+                 const apr_hash_t *externals_to_pin,
                  svn_client_ctx_t *ctx,
                  apr_pool_t *pool)
 {
@@ -1926,6 +2733,7 @@ repos_to_wc_copy(svn_boolean_t *timestam
   SVN_WC__CALL_WITH_WRITE_LOCK(
     repos_to_wc_copy_locked(timestamp_sleep,
                             copy_pairs, top_dst_path, ignore_externals,
+                            pin_externals, externals_to_pin,
                             ra_session, ctx, pool),
     ctx->wc_ctx, lock_abspath, FALSE, pool);
 
@@ -1954,6 +2762,8 @@ try_copy(svn_boolean_t *timestamp_sleep,
          svn_boolean_t metadata_only,
          svn_boolean_t make_parents,
          svn_boolean_t ignore_externals,
+         svn_boolean_t pin_externals,
+         const apr_hash_t *externals_to_pin,
          const apr_hash_t *revprop_table,
          svn_commit_callback2_t commit_callback,
          void *commit_baton,
@@ -2254,30 +3064,35 @@ try_copy(svn_boolean_t *timestamp_sleep,
       else
         {
           /* We ignore these values, so assert the default value */
-          SVN_ERR_ASSERT(allow_mixed_revisions && !metadata_only);
+          SVN_ERR_ASSERT(allow_mixed_revisions);
           return svn_error_trace(do_wc_to_wc_copies(timestamp_sleep,
-                                                    copy_pairs, ctx, pool));
+                                                    copy_pairs,
+                                                    metadata_only,
+                                                    pin_externals,
+                                                    externals_to_pin,
+                                                    ctx, pool));
         }
     }
   else if ((! srcs_are_urls) && (dst_is_url))
     {
       return svn_error_trace(
         wc_to_repos_copy(copy_pairs, make_parents, revprop_table,
-                         commit_callback, commit_baton, ctx, pool));
+                         commit_callback, commit_baton,
+                         pin_externals, externals_to_pin, ctx, pool));
     }
   else if ((srcs_are_urls) && (! dst_is_url))
     {
       return svn_error_trace(
         repos_to_wc_copy(timestamp_sleep,
                          copy_pairs, make_parents, ignore_externals,
-                         ctx, pool));
+                         pin_externals, externals_to_pin, ctx, pool));
     }
   else
     {
       return svn_error_trace(
         repos_to_repos_copy(copy_pairs, make_parents, revprop_table,
                             commit_callback, commit_baton, ctx, is_move,
-                            pool));
+                            pin_externals, externals_to_pin, pool));
     }
 }
 
@@ -2285,11 +3100,14 @@ try_copy(svn_boolean_t *timestamp_sleep,
 
 /* Public Interfaces */
 svn_error_t *
-svn_client_copy6(const apr_array_header_t *sources,
+svn_client_copy7(const apr_array_header_t *sources,
                  const char *dst_path,
                  svn_boolean_t copy_as_child,
                  svn_boolean_t make_parents,
                  svn_boolean_t ignore_externals,
+                 svn_boolean_t metadata_only,
+                 svn_boolean_t pin_externals,
+                 const apr_hash_t *externals_to_pin,
                  const apr_hash_t *revprop_table,
                  svn_commit_callback2_t commit_callback,
                  void *commit_baton,
@@ -2308,9 +3126,11 @@ svn_client_copy6(const apr_array_header_
                  sources, dst_path,
                  FALSE /* is_move */,
                  TRUE /* allow_mixed_revisions */,
-                 FALSE /* metadata_only */,
+                 metadata_only,
                  make_parents,
                  ignore_externals,
+                 pin_externals,
+                 externals_to_pin,
                  revprop_table,
                  commit_callback, commit_baton,
                  ctx,
@@ -2342,9 +3162,11 @@ svn_client_copy6(const apr_array_header_
                      sources, dst_path,
                      FALSE /* is_move */,
                      TRUE /* allow_mixed_revisions */,
-                     FALSE /* metadata_only */,
+                     metadata_only,
                      make_parents,
                      ignore_externals,
+                     pin_externals,
+                     externals_to_pin,
                      revprop_table,
                      commit_callback, commit_baton,
                      ctx,
@@ -2406,6 +3228,8 @@ svn_client_move7(const apr_array_header_
                  metadata_only,
                  make_parents,
                  FALSE /* ignore_externals */,
+                 FALSE /* pin_externals */,
+                 NULL /* externals_to_pin */,
                  revprop_table,
                  commit_callback, commit_baton,
                  ctx,
@@ -2439,6 +3263,8 @@ svn_client_move7(const apr_array_header_
                      metadata_only,
                      make_parents,
                      FALSE /* ignore_externals */,
+                     FALSE /* pin_externals */,
+                     NULL /* externals_to_pin */,
                      revprop_table,
                      commit_callback, commit_baton,
                      ctx,

Modified: 
subversion/branches/reuse-ra-session/subversion/libsvn_client/deprecated.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/deprecated.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/deprecated.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/deprecated.c 
Wed Feb 25 08:15:39 2015
@@ -627,6 +627,28 @@ svn_client_commit(svn_client_commit_info
 
 /*** From copy.c ***/
 svn_error_t *
+svn_client_copy6(const apr_array_header_t *sources,
+                 const char *dst_path,
+                 svn_boolean_t copy_as_child,
+                 svn_boolean_t make_parents,
+                 svn_boolean_t ignore_externals,
+                 const apr_hash_t *revprop_table,
+                 svn_commit_callback2_t commit_callback,
+                 void *commit_baton,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool)
+{
+  return svn_error_trace(svn_client_copy7(sources, dst_path, copy_as_child,
+                                          make_parents, ignore_externals,
+                                          FALSE /* metadata_only */,
+                                          FALSE /* pin_externals */,
+                                          NULL /* externals_to_pin */,
+                                          revprop_table,
+                                          commit_callback, commit_baton,
+                                          ctx, pool));
+}
+
+svn_error_t *
 svn_client_copy5(svn_commit_info_t **commit_info_p,
                  const apr_array_header_t *sources,
                  const char *dst_path,

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/diff.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/diff.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/diff.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/diff.c Wed 
Feb 25 08:15:39 2015
@@ -2209,7 +2209,7 @@ do_diff(const char **root_relpath,
 
               SVN_ERR(svn_dirent_get_absolute(&abspath1, path_or_url1,
                                               scratch_pool));
-              SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2, 
+              SVN_ERR(svn_dirent_get_absolute(&abspath2, path_or_url2,
                                               scratch_pool));
 
               /* ### What about ddi? */

Modified: 
subversion/branches/reuse-ra-session/subversion/libsvn_client/externals.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/externals.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/externals.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/externals.c 
Wed Feb 25 08:15:39 2015
@@ -171,7 +171,7 @@ switch_dir_external(const char *local_ab
   if (revision->kind == svn_opt_revision_number)
     external_rev = revision->value.number;
 
-  /* 
+  /*
    * The code below assumes existing versioned paths are *not* part of
    * the external's defining working copy.
    * The working copy library does not support registering externals
@@ -242,6 +242,20 @@ switch_dir_external(const char *local_ab
                                                   FALSE, FALSE, FALSE, TRUE,
                                                   FALSE, TRUE,
                                                   ra_session, ctx, subpool));
+
+              /* We just decided that this existing directory is an external,
+                 so update the external registry with this information, like
+                 when checking out an external */
+              SVN_ERR(svn_wc__external_register(ctx->wc_ctx,
+                                    defining_abspath,
+                                    local_abspath, svn_node_dir,
+                                    repos_root_url, repos_uuid,
+                                    svn_uri_skip_ancestor(repos_root_url,
+                                                          url, pool),
+                                    external_peg_rev,
+                                    external_rev,
+                                    pool));
+
               svn_pool_destroy(subpool);
               goto cleanup;
             }

Modified: subversion/branches/reuse-ra-session/subversion/libsvn_client/log.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_client/log.c?rev=1662177&r1=1662176&r2=1662177&view=diff
==============================================================================
--- subversion/branches/reuse-ra-session/subversion/libsvn_client/log.c 
(original)
+++ subversion/branches/reuse-ra-session/subversion/libsvn_client/log.c Wed Feb 
25 08:15:39 2015
@@ -307,7 +307,7 @@ limit_receiver(void *baton, svn_log_entr
 
    The limitations on TARGETS specified by svn_client_log5 are enforced here.
    So TARGETS can only contain a single WC path or a URL and zero or more
-   relative paths -- anything else will raise an error. 
+   relative paths -- anything else will raise an error.
 
    PEG_REVISION, TARGETS, and CTX are as per svn_client_log5.
 
@@ -646,7 +646,7 @@ run_ra_get_log(apr_array_header_t *revis
                apr_array_header_t *log_segments,
                svn_client__pathrev_t *actual_loc,
                svn_ra_session_t *ra_session,
-               /* The following are as per svn_client_log5. */ 
+               /* The following are as per svn_client_log5. */
                const apr_array_header_t *targets,
                int limit,
                svn_boolean_t discover_changed_paths,
@@ -765,7 +765,7 @@ run_ra_get_log(apr_array_header_t *revis
          So to be safe we handle that case. */
       if (matching_segment == NULL)
         continue;
-      
+
       /* A segment with a NULL path means there is gap in the history.
          We'll just proceed and let svn_ra_get_log2 fail with a useful
          error...*/


Reply via email to