On the 'pristines-on-demand-on-mwf' branch: update fetches minimal pristines.

This is a proof-of-concept patch, enabling "update" to fetch minimal
pristines, using a deeper callback to fetch them at the point of use.

Currently, "restore" functionality of the update is disabled. A similar
approach could enable it to fetch at point of use as well. Currently it
being disabled leads to the following test suite failures:

  FAIL:  basic_tests.py 1: basic checkout of a wc
  FAIL:  copy_tests.py 20: copy over a missing file
  FAIL:  relocate_tests.py 1: relocate with deleted, missing and copied entries
  FAIL:  stat_tests.py 13: timestamp behaviour
  FAIL:  update_tests.py 6: delete files and update to resolve text conflicts
  FAIL:  update_tests.py 9: update missing items (by name) in working copy
  FAIL:  update_tests.py 14: update missing dir to rev in which it is absent
  FAIL:  update_tests.py 15: another "hudson" problem: updates that delete
  FAIL:  upgrade_tests.py 24: test upgrading a working copy with missing subdir
  FAIL:  upgrade_tests.py 27: upgrade with missing replaced dir

* subversion/include/private/svn_wc_private.h
  (svn_wc__textbase_hydrate_cb_t): Moved to earlier.
  (svn_wc__get_update_editor): Add a hydrate callback.
  (svn_wc__crawl_revisions6): New, bumped... ### see below.

* subversion/libsvn_client/client.h,
  subversion/libsvn_client/textbase.c
  (svn_client__textbase_get_hydrator): New.

* subversion/libsvn_client/switch.c
  (svn_client__switch_internal): ### hydrate before conflicts resolver

* subversion/libsvn_client/update.c
  (update_internal): 
  (svn_client__update_internal): Don't hydrate everything at the start.
    Pass a hydrate callback down to the WC update operation. 
    ### TODO/TO-CHECK: Also hydrate before conflicts resolver.

* subversion/libsvn_wc/adm_crawler.c
  (maybe_restore_node): ### TEMPORARY: don't restore.
  (svn_wc_crawl_revisions5): Bump to ...6(), adding a hydrate callback.
    ### TODO: use the callback for "restore".

* subversion/libsvn_wc/deprecated.c
  (svn_wc_get_update_editor4): Pass null for hydrate callback.

* subversion/libsvn_wc/update_editor.c
  (lazy_open_source): Use a hydrate callback to hydrate if pristine is
    missing.
  (edit_baton,
   make_editor,
   svn_wc__get_update_editor,
   svn_wc__get_switch_editor): Pass a hydrate callback through.

* subversion/libsvn_wc/wc_db.h,
  subversion/libsvn_wc/wc_db_textbase.c
  (svn_wc__db_textbase_hydrate): Newly public; renamed ...
  (textbase_hydrate): ... from this.
  (svn_wc__db_textbase_sync): Track the rename.
--This line, and those below, will be ignored--

Index: subversion/include/private/svn_wc_private.h
===================================================================
--- subversion/include/private/svn_wc_private.h	(revision 1898849)
+++ subversion/include/private/svn_wc_private.h	(working copy)
@@ -44,12 +44,24 @@
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
 
+/* The callback invoked by svn_wc__textbase_sync() to fetch the text-base
+   contents identified by REPOS_ROOT_URL, REPOS_RELPATH and REVISION. */
+typedef svn_error_t *(*svn_wc__textbase_hydrate_cb_t)(
+  void *baton,
+  const char *repos_root_url,
+  const char *repos_relpath,
+  svn_revnum_t revision,
+  svn_stream_t *contents,
+  svn_cancel_func_t cancel_func,
+  void *cancel_baton,
+  apr_pool_t *scratch_pool);
+
 /* Return TRUE iff CLHASH (a hash whose keys are const char *
    changelist names) is NULL or if LOCAL_ABSPATH is part of a changelist in
    CLHASH. */
 svn_boolean_t
 svn_wc__changelist_match(svn_wc_context_t *wc_ctx,
                          const char *local_abspath,
@@ -1520,12 +1532,14 @@ svn_wc__get_update_editor(const svn_delt
                           svn_boolean_t allow_unver_obstructions,
                           svn_boolean_t adds_as_modification,
                           svn_boolean_t server_performs_filtering,
                           svn_boolean_t clean_checkout,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
+                          svn_wc__textbase_hydrate_cb_t hydrate_func,
+                          void *hydrate_baton,
                           svn_wc_dirents_func_t fetch_dirents_func,
                           void *fetch_dirents_baton,
                           svn_wc_conflict_resolver_func2_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
                           void *external_baton,
@@ -2311,24 +2325,12 @@ svn_wc__upgrade(svn_wc_context_t *wc_ctx
                 svn_cancel_func_t cancel_func,
                 void *cancel_baton,
                 svn_wc_notify_func2_t notify_func,
                 void *notify_baton,
                 apr_pool_t *scratch_pool);
 
-/* The callback invoked by svn_wc__textbase_sync() to fetch the text-base
-   contents identified by REPOS_ROOT_URL, REPOS_RELPATH and REVISION. */
-typedef svn_error_t *(*svn_wc__textbase_hydrate_cb_t)(
-  void *baton,
-  const char *repos_root_url,
-  const char *repos_relpath,
-  svn_revnum_t revision,
-  svn_stream_t *contents,
-  svn_cancel_func_t cancel_func,
-  void *cancel_baton,
-  apr_pool_t *scratch_pool);
-
 /* Synchronize the state of the text-base contents for the LOCAL_ABSPATH tree.
    If ALLOW_HYDRATE is true, fetch the required but missing text-base contents
    using the provided HYDRATE_CALLBACK and HYDRATE_BATON.  If ALLOW_DEHYDRATE
    is true, remove the on disk text-base contents that is not required. */
 svn_error_t *
 svn_wc__textbase_sync(svn_wc_context_t *wc_ctx,
@@ -2338,11 +2340,32 @@ svn_wc__textbase_sync(svn_wc_context_t *
                       svn_wc__textbase_hydrate_cb_t hydrate_callback,
                       void *hydrate_baton,
                       svn_cancel_func_t cancel_func,
                       void *cancel_baton,
                       apr_pool_t *scratch_pool);
 
+/**
+ * @since New in 1.15.
+ */
+svn_error_t *
+svn_wc__crawl_revisions6(svn_wc_context_t *wc_ctx,
+                         const char *local_abspath,
+                         const svn_ra_reporter3_t *reporter,
+                         void *report_baton,
+                         svn_boolean_t restore_files,
+                         svn_depth_t depth,
+                         svn_boolean_t honor_depth_exclude,
+                         svn_boolean_t depth_compatibility_trick,
+                         svn_boolean_t use_commit_times,
+                         svn_wc__textbase_hydrate_cb_t hydrate_func,
+                         void *hydrate_baton,
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
+                         svn_wc_notify_func2_t notify_func,
+                         void *notify_baton,
+                         apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
 #endif /* SVN_WC_PRIVATE_H */
Index: subversion/libsvn_client/client.h
===================================================================
--- subversion/libsvn_client/client.h	(revision 1898849)
+++ subversion/libsvn_client/client.h	(working copy)
@@ -37,12 +37,13 @@
 #include "svn_client.h"
 
 #include "private/svn_magic.h"
 #include "private/svn_client_private.h"
 #include "private/svn_diff_tree.h"
 #include "private/svn_editor.h"
+#include "private/svn_wc_private.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
 
@@ -1248,11 +1249,22 @@ svn_error_t *
 svn_client__textbase_sync(const char *local_abspath,
                           svn_boolean_t allow_hydrate,
                           svn_boolean_t allow_dehydrate,
                           svn_client_ctx_t *ctx,
                           apr_pool_t *scratch_pool);
 
+/* ...
+ *
+ * RA_SESSION may be null; in that case, it will open a new session upon
+ * first use. */
+svn_error_t *
+svn_client__textbase_get_hydrator(svn_wc__textbase_hydrate_cb_t *hydrate_func,
+                                  void **hydrate_baton,
+                                  svn_ra_session_t *ra_session,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *result_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 
 #endif /* SVN_LIBSVN_CLIENT_H */
Index: subversion/libsvn_client/switch.c
===================================================================
--- subversion/libsvn_client/switch.c	(revision 1898849)
+++ subversion/libsvn_client/switch.c	(working copy)
@@ -439,12 +439,15 @@ svn_client__switch_internal(svn_revnum_t
                          timestamp_sleep, ctx, pool);
 
   /* Give the conflict resolver callback the opportunity to
    * resolve any conflicts that were raised. */
   if (! err1 && ctx->conflict_func2)
     {
+      SVN_ERR(svn_client__textbase_sync(local_abspath, TRUE, TRUE,
+                                        ctx, pool));
+
       err1 = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool);
     }
 
   if (acquired_lock)
     err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool);
   else
Index: subversion/libsvn_client/textbase.c
===================================================================
--- subversion/libsvn_client/textbase.c	(revision 1898849)
+++ subversion/libsvn_client/textbase.c	(working copy)
@@ -82,12 +82,30 @@ textbase_hydrate_cb(void *baton,
   err = svn_error_compose_create(err, svn_stream_close(contents));
 
   return svn_error_trace(err);
 }
 
 svn_error_t *
+svn_client__textbase_get_hydrator(svn_wc__textbase_hydrate_cb_t *hydrate_func,
+                                  void **hydrate_baton,
+                                  svn_ra_session_t *ra_session,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *result_pool)
+{
+  textbase_hydrate_baton_t *baton = apr_pcalloc(result_pool, sizeof(*baton));
+
+  baton->pool = result_pool;
+  baton->ctx = ctx;
+  baton->ra_session = ra_session;
+
+  *hydrate_func = textbase_hydrate_cb;
+  *hydrate_baton = baton;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client__textbase_sync(const char *local_abspath,
                           svn_boolean_t allow_hydrate,
                           svn_boolean_t allow_dehydrate,
                           svn_client_ctx_t *ctx,
                           apr_pool_t *scratch_pool)
 {
@@ -96,12 +114,13 @@ svn_client__textbase_sync(const char *lo
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   baton.pool = scratch_pool;
   baton.ctx = ctx;
   baton.ra_session = NULL;
 
+  SVN_DBG(("svn_client__textbase_sync(%d,%d)", allow_hydrate, allow_dehydrate));
   SVN_ERR(svn_wc__textbase_sync(ctx->wc_ctx, local_abspath,
                                 allow_hydrate, allow_dehydrate,
                                 textbase_hydrate_cb, &baton,
                                 ctx->cancel_func, ctx->cancel_baton,
                                 scratch_pool));
 
Index: subversion/libsvn_client/update.c
===================================================================
--- subversion/libsvn_client/update.c	(revision 1898849)
+++ subversion/libsvn_client/update.c	(working copy)
@@ -324,12 +324,14 @@ update_internal(svn_revnum_t *result_rev
   svn_boolean_t server_supports_depth;
   svn_boolean_t cropping_target;
   svn_boolean_t target_conflicted = FALSE;
   svn_config_t *cfg = ctx->config
                       ? svn_hash_gets(ctx->config, SVN_CONFIG_CATEGORY_CONFIG)
                       : NULL;
+  svn_wc__textbase_hydrate_cb_t hydrate_func;
+  void *hydrate_baton;
 
   if (result_rev)
     *result_rev = SVN_INVALID_REVNUM;
 
   /* An unknown depth can't be sticky. */
   if (depth == svn_depth_unknown)
@@ -464,13 +466,13 @@ update_internal(svn_revnum_t *result_rev
       notify->content_state = notify->prop_state
         = svn_wc_notify_state_inapplicable;
       notify->lock_state = svn_wc_notify_lock_state_inapplicable;
       ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
     }
 
-  SVN_ERR(svn_client__textbase_sync(local_abspath, TRUE, TRUE,
+  SVN_ERR(svn_client__textbase_sync(local_abspath, FALSE, TRUE,
                                     ctx, scratch_pool));
 
   SVN_ERR(reuse_ra_session(ra_session_p, &corrected_url, anchor_url,
                            anchor_abspath, ctx, result_pool, scratch_pool));
   ra_session = *ra_session_p;
 
@@ -494,12 +496,16 @@ update_internal(svn_revnum_t *result_rev
       repos_root_url = new_repos_root_url;
       /* ### We should update anchor_loc->repos_uuid too, although currently
        * we don't use it. */
       anchor_url = corrected_url;
     }
 
+  SVN_ERR(svn_client__textbase_get_hydrator(&hydrate_func, &hydrate_baton,
+                                            NULL /*hydrate_ra_session*/,
+                                            ctx, scratch_pool));
+
   /* Resolve unspecified REVISION now, because we need to retrieve the
      correct inherited props prior to the editor drive and we need to
      use the same value of HEAD for both. */
   opt_rev.kind = revision->kind;
   opt_rev.value = revision->value;
   if (opt_rev.kind == svn_opt_revision_unspecified)
@@ -530,12 +536,13 @@ update_internal(svn_revnum_t *result_rev
                                     depth, depth_is_sticky,
                                     allow_unver_obstructions,
                                     adds_as_modification,
                                     server_supports_depth,
                                     clean_checkout,
                                     diff3_cmd, preserved_exts,
+                                    hydrate_func, hydrate_baton,
                                     svn_client__dirent_fetcher, &dfb,
                                     conflicted_paths ? record_conflict : NULL,
                                     conflicted_paths,
                                     NULL, NULL,
                                     ctx->cancel_func, ctx->cancel_baton,
                                     ctx->notify_func2, ctx->notify_baton2,
@@ -557,20 +564,21 @@ update_internal(svn_revnum_t *result_rev
    * need to sleep for timestamps. */
   *timestamp_sleep = TRUE;
 
   /* Drive the reporter structure, describing the revisions within
      LOCAL_ABSPATH.  When this calls reporter->finish_report, the
      reporter will drive the update_editor. */
-  SVN_ERR(svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
-                                  report_baton, TRUE,
-                                  depth, (! depth_is_sticky),
-                                  (! server_supports_depth),
-                                  use_commit_times,
-                                  ctx->cancel_func, ctx->cancel_baton,
-                                  ctx->notify_func2, ctx->notify_baton2,
-                                  scratch_pool));
+  SVN_ERR(svn_wc__crawl_revisions6(ctx->wc_ctx, local_abspath, reporter,
+                                   report_baton, TRUE,
+                                   depth, (! depth_is_sticky),
+                                   (! server_supports_depth),
+                                   use_commit_times,
+                                   hydrate_func, hydrate_baton,
+                                   ctx->cancel_func, ctx->cancel_baton,
+                                   ctx->notify_func2, ctx->notify_baton2,
+                                   scratch_pool));
 
   /* We handle externals after the update is complete, so that
      handling external items (and any errors therefrom) doesn't delay
      the primary operation.  */
   if ((SVN_DEPTH_IS_RECURSIVE(depth) || cropping_target)
       && (! ignore_externals))
@@ -708,12 +716,15 @@ svn_client__update_internal(svn_revnum_t
                         TRUE, ctx, pool, pool);
 
   /* Give the conflict resolver callback the opportunity to
    * resolve any conflicts that were raised. */
   if (! err && ctx->conflict_func2 && apr_hash_count(conflicted_paths))
     {
+      SVN_ERR(svn_client__textbase_sync(local_abspath, TRUE, TRUE,
+                                        ctx, pool));
+
       err = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool);
     }
 
  cleanup:
   err = svn_error_compose_create(
             err,
Index: subversion/libsvn_wc/adm_crawler.c
===================================================================
--- subversion/libsvn_wc/adm_crawler.c	(revision 1898850)
+++ subversion/libsvn_wc/adm_crawler.c	(working copy)
@@ -206,17 +206,23 @@ maybe_restore_node(svn_wc__db_t *db,
          In this case we can't overwrite it with the pristine
          version */
       SVN_ERR(svn_io_check_path(local_abspath, &dirent_kind, scratch_pool));
 
       if (dirent_kind == svn_node_none)
         {
-          SVN_ERR(restore_node(db, local_abspath,
+  return SVN_NO_ERROR;
+          err = (restore_node(db, local_abspath,
                                wrk_kind, conflicted, use_commit_times,
                                cancel_func, cancel_baton,
                                notify_func, notify_baton,
                                scratch_pool));
+          if (err)
+            {
+              svn_handle_warning2(stdout, err, "DBG: ");
+              svn_error_clear(err);
+            }
         }
     }
 
   return SVN_NO_ERROR;
 }
 
@@ -672,26 +678,28 @@ report_revisions_and_depths(svn_wc__db_t
 
 /*------------------------------------------------------------------*/
 /*** Public Interfaces ***/
 
 
 svn_error_t *
-svn_wc_crawl_revisions5(svn_wc_context_t *wc_ctx,
-                        const char *local_abspath,
-                        const svn_ra_reporter3_t *reporter,
-                        void *report_baton,
-                        svn_boolean_t restore_files,
-                        svn_depth_t depth,
-                        svn_boolean_t honor_depth_exclude,
-                        svn_boolean_t depth_compatibility_trick,
-                        svn_boolean_t use_commit_times,
-                        svn_cancel_func_t cancel_func,
-                        void *cancel_baton,
-                        svn_wc_notify_func2_t notify_func,
-                        void *notify_baton,
-                        apr_pool_t *scratch_pool)
+svn_wc__crawl_revisions6(svn_wc_context_t *wc_ctx,
+                         const char *local_abspath,
+                         const svn_ra_reporter3_t *reporter,
+                         void *report_baton,
+                         svn_boolean_t restore_files,
+                         svn_depth_t depth,
+                         svn_boolean_t honor_depth_exclude,
+                         svn_boolean_t depth_compatibility_trick,
+                         svn_boolean_t use_commit_times,
+                         svn_wc__textbase_hydrate_cb_t hydrate_func,
+                         void *hydrate_baton,
+                         svn_cancel_func_t cancel_func,
+                         void *cancel_baton,
+                         svn_wc_notify_func2_t notify_func,
+                         void *notify_baton,
+                         apr_pool_t *scratch_pool)
 {
   svn_wc__db_t *db = wc_ctx->db;
   svn_error_t *fserr, *err;
   svn_revnum_t target_rev = SVN_INVALID_REVNUM;
   svn_boolean_t start_empty;
   svn_wc__db_status_t status;
@@ -874,12 +882,42 @@ svn_wc_crawl_revisions5(svn_wc_context_t
       fserr = svn_error_quick_wrap(fserr, _("Error aborting report"));
       svn_error_compose(err, fserr);
     }
   return svn_error_trace(err);
 }
 
+svn_error_t *
+svn_wc_crawl_revisions5(svn_wc_context_t *wc_ctx,
+                        const char *local_abspath,
+                        const svn_ra_reporter3_t *reporter,
+                        void *report_baton,
+                        svn_boolean_t restore_files,
+                        svn_depth_t depth,
+                        svn_boolean_t honor_depth_exclude,
+                        svn_boolean_t depth_compatibility_trick,
+                        svn_boolean_t use_commit_times,
+                        svn_cancel_func_t cancel_func,
+                        void *cancel_baton,
+                        svn_wc_notify_func2_t notify_func,
+                        void *notify_baton,
+                        apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_wc__crawl_revisions6(wc_ctx, local_abspath,
+                                   reporter, report_baton,
+                                   restore_files,
+                                   depth,
+                                   honor_depth_exclude,
+                                   depth_compatibility_trick,
+                                   use_commit_times,
+                                   NULL, NULL,
+                                   cancel_func, cancel_baton,
+                                   notify_func, notify_baton,
+                                   scratch_pool));
+  return SVN_NO_ERROR;
+}
+
 /*** Copying stream ***/
 
 /* A copying stream is a bit like the unix tee utility:
  *
  * It reads the SOURCE when asked for data and while returning it,
  * also writes the same data to TARGET.
Index: subversion/libsvn_wc/deprecated.c
===================================================================
--- subversion/libsvn_wc/deprecated.c	(revision 1898849)
+++ subversion/libsvn_wc/deprecated.c	(working copy)
@@ -3640,12 +3640,13 @@ svn_wc_get_update_editor4(const svn_delt
                               allow_unver_obstructions,
                               adds_as_modification,
                               server_performs_filtering,
                               clean_checkout,
                               diff3_cmd,
                               preserved_exts,
+                              NULL, NULL, /* hydrate func/baton */
                               fetch_dirents_func, fetch_dirents_baton,
                               conflict_func, conflict_baton,
                               external_func, external_baton,
                               cancel_func, cancel_baton,
                               notify_func, notify_baton,
                               result_pool, scratch_pool));
Index: subversion/libsvn_wc/update_editor.c
===================================================================
--- subversion/libsvn_wc/update_editor.c	(revision 1898849)
+++ subversion/libsvn_wc/update_editor.c	(working copy)
@@ -241,12 +241,16 @@ struct edit_baton
 
   /* This editor will invoke a interactive conflict-resolution
      callback, if available. */
   svn_wc_conflict_resolver_func2_t conflict_func;
   void *conflict_baton;
 
+  /* Hydrate callback... */
+  svn_wc__textbase_hydrate_cb_t hydrate_func;
+  void *hydrate_baton;
+
   /* Subtrees that were skipped during the edit, and therefore shouldn't
      have their revision/url info updated at the end.  If a path is a
      directory, its descendants will also be skipped.  The keys are paths
      relative to the working copy root and the values unspecified. */
   apr_hash_t *skipped_trees;
 
@@ -3740,18 +3744,33 @@ static svn_error_t *
 lazy_open_source(svn_stream_t **stream,
                  void *baton,
                  apr_pool_t *result_pool,
                  apr_pool_t *scratch_pool)
 {
   struct file_baton *fb = baton;
+  struct edit_baton *eb = fb->edit_baton;
 
-  SVN_ERR(svn_wc__textbase_get_contents(stream, fb->edit_baton->db,
-                                        fb->local_abspath,
-                                        fb->original_checksum, FALSE,
+  SVN_ERR(svn_wc__textbase_get_contents(stream, eb->db, fb->local_abspath,
+                                        fb->original_checksum, TRUE,
                                         result_pool, scratch_pool));
-
+  /* If the pristine was missing, hydrate it and then try again. */
+  /* (### Alternative: If pristine was missing, try to pull it from the repo
+   * via a callback. But we don't have a repo pull function available.) */
+  if (! *stream)
+    {
+      SVN_ERR(svn_wc__db_textbase_hydrate(eb->db, fb->local_abspath,
+                                          eb->hydrate_func, eb->hydrate_baton,
+                                          eb->cancel_func, eb->cancel_baton,
+                                          fb->original_checksum,
+                                          eb->repos_root, fb->new_repos_relpath,
+                                          fb->old_revision,
+                                          scratch_pool));
+      SVN_ERR(svn_wc__textbase_get_contents(stream, eb->db, fb->local_abspath,
+                                            fb->original_checksum, FALSE,
+                                            result_pool, scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
 
 /* Implements svn_stream_lazyopen_func_t. */
 static svn_error_t *
@@ -5112,12 +5131,14 @@ make_editor(svn_revnum_t *target_revisio
             svn_depth_t depth,
             svn_boolean_t depth_is_sticky,
             svn_boolean_t allow_unver_obstructions,
             svn_boolean_t adds_as_modification,
             svn_boolean_t server_performs_filtering,
             svn_boolean_t clean_checkout,
+            svn_wc__textbase_hydrate_cb_t hydrate_func,
+            void *hydrate_baton,
             svn_wc_notify_func2_t notify_func,
             void *notify_baton,
             svn_cancel_func_t cancel_func,
             void *cancel_baton,
             svn_wc_dirents_func_t fetch_dirents_func,
             void *fetch_dirents_baton,
@@ -5190,12 +5211,14 @@ make_editor(svn_revnum_t *target_revisio
   else
     eb->target_abspath = svn_dirent_join(eb->anchor_abspath, target_basename,
                                          edit_pool);
 
   eb->requested_depth          = depth;
   eb->depth_is_sticky          = depth_is_sticky;
+  eb->hydrate_func             = hydrate_func;
+  eb->hydrate_baton            = hydrate_baton;
   eb->notify_func              = notify_func;
   eb->notify_baton             = notify_baton;
   eb->external_func            = external_func;
   eb->external_baton           = external_baton;
   eb->diff3_cmd                = diff3_cmd;
   eb->cancel_func              = cancel_func;
@@ -5402,12 +5425,14 @@ svn_wc__get_update_editor(const svn_delt
                           svn_boolean_t allow_unver_obstructions,
                           svn_boolean_t adds_as_modification,
                           svn_boolean_t server_performs_filtering,
                           svn_boolean_t clean_checkout,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
+                          svn_wc__textbase_hydrate_cb_t hydrate_func,
+                          void *hydrate_baton,
                           svn_wc_dirents_func_t fetch_dirents_func,
                           void *fetch_dirents_baton,
                           svn_wc_conflict_resolver_func2_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
                           void *external_baton,
@@ -5420,12 +5445,13 @@ svn_wc__get_update_editor(const svn_delt
 {
   return make_editor(target_revision, wc_ctx->db, anchor_abspath,
                      target_basename, wcroot_iprops, use_commit_times,
                      NULL, depth, depth_is_sticky, allow_unver_obstructions,
                      adds_as_modification, server_performs_filtering,
                      clean_checkout,
+                     hydrate_func, hydrate_baton,
                      notify_func, notify_baton,
                      cancel_func, cancel_baton,
                      fetch_dirents_func, fetch_dirents_baton,
                      conflict_func, conflict_baton,
                      external_func, external_baton,
                      diff3_cmd, preserved_exts, editor, edit_baton,
@@ -5467,12 +5493,13 @@ svn_wc__get_switch_editor(const svn_delt
                      target_basename, wcroot_iprops, use_commit_times,
                      switch_url,
                      depth, depth_is_sticky, allow_unver_obstructions,
                      FALSE /* adds_as_modification */,
                      server_performs_filtering,
                      FALSE /* clean_checkout */,
+                     NULL, NULL,  /* hydrate func/baton */
                      notify_func, notify_baton,
                      cancel_func, cancel_baton,
                      fetch_dirents_func, fetch_dirents_baton,
                      conflict_func, conflict_baton,
                      external_func, external_baton,
                      diff3_cmd, preserved_exts,
Index: subversion/libsvn_wc/wc_db.h
===================================================================
--- subversion/libsvn_wc/wc_db.h	(revision 1898849)
+++ subversion/libsvn_wc/wc_db.h	(working copy)
@@ -3178,12 +3178,27 @@ typedef svn_error_t * (*svn_wc__db_textb
   svn_revnum_t revision,
   svn_stream_t *contents,
   svn_cancel_func_t cancel_func,
   void *cancel_baton,
   apr_pool_t *scratch_pool);
 
+/* Hydrate the pristine for one file.
+ */
+svn_error_t *
+svn_wc__db_textbase_hydrate(svn_wc__db_t *db,
+                            const char *wri_abspath,
+                            svn_wc__db_textbase_hydrate_cb_t hydrate_callback,
+                            void *hydrate_baton,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
+                            const svn_checksum_t *checksum,
+                            const char *repos_root_url,
+                            const char *repos_relpath,
+                            svn_revnum_t revision,
+                            apr_pool_t *scratch_pool);
+
 /* Synchronize the state of the text-bases in DB.
 
    If ALLOW_HYDRATE is true, fetch the referenced but missing text-base
    contents using the provided HYDRATE_CALLBACK and HYDRATE_BATON.
    If ALLOW_DEHYDRATE is true, remove the on disk text-base contents
    that is no longer referenced.
Index: subversion/libsvn_wc/wc_db_textbase.c
===================================================================
--- subversion/libsvn_wc/wc_db_textbase.c	(revision 1898849)
+++ subversion/libsvn_wc/wc_db_textbase.c	(working copy)
@@ -165,24 +165,24 @@
 
   SVN_ERR(svn_sqlite__reset(stmt));
 
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-textbase_hydrate(svn_wc__db_t *db,
-                 const char *wri_abspath,
-                 svn_wc__db_textbase_hydrate_cb_t hydrate_callback,
-                 void *hydrate_baton,
-                 svn_cancel_func_t cancel_func,
-                 void *cancel_baton,
-                 const svn_checksum_t *checksum,
-                 const char *repos_root_url,
-                 const char *repos_relpath,
-                 svn_revnum_t revision,
-                 apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_textbase_hydrate(svn_wc__db_t *db,
+                            const char *wri_abspath,
+                            svn_wc__db_textbase_hydrate_cb_t hydrate_callback,
+                            void *hydrate_baton,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
+                            const svn_checksum_t *checksum,
+                            const char *repos_root_url,
+                            const char *repos_relpath,
+                            svn_revnum_t revision,
+                            apr_pool_t *scratch_pool)
 {
   svn_stream_t *install_stream;
   svn_wc__db_install_data_t *install_data;
   svn_checksum_t *sha1_checksum;
   svn_checksum_t *md5_checksum;
   svn_error_t *err;
@@ -323,16 +323,18 @@ svn_wc__db_textbase_sync(svn_wc__db_t *d
                   return svn_error_createf(
                            SVN_ERR_WC_CORRUPT, svn_sqlite__reset(stmt),
                            _("Unexpected entry for '%s'"),
                            svn_checksum_to_cstring_display(checksum, iterpool));
                 }
 
-              err = textbase_hydrate(db, local_abspath, hydrate_callback,
-                                     hydrate_baton, cancel_func, cancel_baton,
-                                     checksum, repos_root_url, repos_relpath,
-                                     revision, iterpool);
+              err = svn_wc__db_textbase_hydrate(db, local_abspath,
+                                                hydrate_callback, hydrate_baton,
+                                                cancel_func, cancel_baton,
+                                                checksum, repos_root_url,
+                                                repos_relpath, revision,
+                                                iterpool);
               /* If read access is unauthorized, for some operations we need
                * to continue even though we failed to fetch the textbase. */
               if (err && err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED)
                 {
                   svn_error_clear(err);
                   err = SVN_NO_ERROR;
