New function, svn_client__wc_node_get_base(), in a continuing attempt to
harmonize the semantics of calls to groups of functions such as

  svn_wc__node_get_repos_info(wc_abspath) -> root_url, uuid
  svn_wc__node_get_base_rev(  wc_abspath) -> rev
  svn_wc__node_get_url(       wc_abspath) -> url

Problem: those three functions have differing semantics.  The first gets the
working (not base) node's repository; the second gets the base node's rev,
and the third one appears to get the working/actual node's URL (and "if
added, the URL it will have").

This would indicate that the calling code is flawed.  What semantics do we
want really?

This patch assumes the calling code wants the base location, an assumption
that may well be wrong.

* subversion/include/private/svn_client_private.h,
  subversion/libsvn_client/util.c
  (svn_client__wc_node_get_base): New function.

* subversion/include/private/svn_wc_private.h,
  subversion/libsvn_wc/node.c
  (svn_wc__node_get_base): New function.

* subversion/libsvn_client/merge.c
  (filter_self_referential_mergeinfo, calculate_remaining_ranges): Use it.

* subversion/libsvn_client/switch.c
  (switch_internal): Use it.
--This line, and those below, will be ignored--

Index: subversion/include/private/svn_client_private.h
===================================================================
--- subversion/include/private/svn_client_private.h	(revision 1327006)
+++ subversion/include/private/svn_client_private.h	(working copy)
@@ -154,6 +154,16 @@ svn_client__wc_node_get_origin(svn_clien
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
+/* Set *PATHREV_P to the repository coordinates of the WC base node at
+ * WC_ABSPATH.  If WC_ABSPATH is a working copy path but it has no base
+ * node, set *PATHREV_P to NULL. */
+svn_error_t *
+svn_client__wc_node_get_base(svn_client__pathrev_t **pathrev_p,
+                             const char *wc_abspath,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
+
 /* A macro to mark sections of code that belong to the 'symmetric merge'
  * feature while it's still new. */
 #ifdef SVN_DEBUG
Index: subversion/include/private/svn_wc_private.h
===================================================================
--- subversion/include/private/svn_wc_private.h	(revision 1327006)
+++ subversion/include/private/svn_wc_private.h	(working copy)
@@ -476,6 +476,24 @@ svn_wc__node_get_url(const char **url,
                      apr_pool_t *scratch_pool);
 
 /**
+ * Retrieve the repository coordinates of the base node at @a local_abspath.
+ * If there is no base node, return an error.
+ *
+ * All output arguments may be NULL.
+ *
+ * Allocate the result in @a result_pool. Perform temporary allocations in
+ * @a scratch_pool */
+svn_error_t *
+svn_wc__node_get_base(svn_revnum_t *revision,
+                      const char **repos_relpath,
+                      const char **repos_root_url,
+                      const char **repos_uuid,
+                      svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool);
+
+/**
  * Retrieves the origin of the node as it is known in the repository. For
  * a copied node this retrieves where the node is copied from, for an added
  * node this returns NULL/INVALID outputs, and for any other node this
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1327006)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -865,7 +865,7 @@ filter_self_referential_mergeinfo(apr_ar
   int i;
   apr_pool_t *iterpool;
   svn_boolean_t is_added;
-  svn_client__pathrev_t target_base;
+  svn_client__pathrev_t *target_base, *target_origin;
 
   /* Issue #3383: We don't want mergeinfo from a foreign repos.
 
@@ -893,13 +893,14 @@ filter_self_referential_mergeinfo(apr_ar
   if (is_added)
     return SVN_NO_ERROR;
 
-  SVN_ERR(svn_wc__node_get_url(&target_base.url, ctx->wc_ctx, target_abspath,
-                               pool, pool));
-  SVN_ERR(svn_wc__node_get_base_rev(&target_base.rev, ctx->wc_ctx,
-                                    target_abspath, pool));
-  SVN_ERR(svn_wc__node_get_repos_info(&target_base.repos_root_url,
-                                      &target_base.repos_uuid,
-                                      ctx->wc_ctx, target_abspath, pool, pool));
+  /* ### This probably shouldn't be looking at the base at all, it should be
+   * looking at the 'origin' or 'pristine' version of the target node. */
+  SVN_ERR(svn_client__wc_node_get_base(&target_base, target_abspath,
+                                       ctx, pool, pool));
+  SVN_ERR(svn_client__wc_node_get_origin(&target_origin, target_abspath,
+                                       ctx, pool, pool));
+  SVN_ERR_ASSERT(target_base->rev == target_origin->rev);
+  SVN_ERR_ASSERT(strcmp(target_base->url, target_origin->url) == 0);
 
   adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
   iterpool = svn_pool_create(pool);
@@ -969,7 +970,7 @@ filter_self_referential_mergeinfo(apr_ar
          the cost of a roundtrip communication with the repository. */
       SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo,
                                           &mergeinfo,
-                                          target_base.rev,
+                                          target_base->rev,
                                           iterpool));
 
       /* Filter self-referential mergeinfo from younger_mergeinfo. */
@@ -1011,7 +1012,7 @@ filter_self_referential_mergeinfo(apr_ar
                      RANGE->START on the same line of history.
                      (start+1 because RANGE->start is not inclusive.) */
                   err2 = svn_client__repos_location(&start_loc, ra_session,
-                                                    &target_base,
+                                                    target_base,
                                                     range->start + 1,
                                                     ctx, iterpool, iterpool);
                   if (err2)
@@ -1088,7 +1089,7 @@ filter_self_referential_mergeinfo(apr_ar
 
           SVN_ERR(svn_client__get_history_as_mergeinfo(
             &implicit_mergeinfo, NULL,
-            &target_base, target_base.rev, SVN_INVALID_REVNUM,
+            target_base, target_base->rev, SVN_INVALID_REVNUM,
             ra_session, ctx, iterpool));
 
           /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */
@@ -3992,7 +3993,7 @@ calculate_remaining_ranges(svn_client__m
   const char *primary_url = (source->loc1->rev < source->loc2->rev)
                             ? source->loc2->url : source->loc1->url;
   svn_mergeinfo_t adjusted_target_mergeinfo = NULL;
-  svn_revnum_t child_base_revision;
+  svn_client__pathrev_t *child_base;
 
   /* Determine which of the requested ranges to consider merging... */
   SVN_ERR(svn_ra__get_fspath_relative_to_root(ra_session, &mergeinfo_path,
@@ -4061,14 +4062,14 @@ calculate_remaining_ranges(svn_client__m
      So in the name of user friendliness, return an error suggesting a helpful
      course of action.
   */
-  SVN_ERR(svn_wc__node_get_base_rev(&child_base_revision, ctx->wc_ctx,
-                                     child->abspath, scratch_pool));
-  /* If CHILD has no base revision then it hasn't been committed yet, so it
+  SVN_ERR(svn_client__wc_node_get_base(&child_base, child->abspath,
+                                       ctx, scratch_pool, scratch_pool));
+  /* If CHILD has no base then it hasn't been committed yet, so it
      can't have any "future" history. */
-  if (SVN_IS_VALID_REVNUM(child_base_revision)
+  if (child_base
       && ((child->remaining_ranges)->nelts == 0) /* Inoperative merge */
       && (source->loc2->rev < source->loc1->rev)     /* Reverse merge */
-      && (child_base_revision <= source->loc2->rev))  /* From CHILD's future */
+      && (child_base->rev <= source->loc2->rev))  /* From CHILD's future */
     {
       /* Hmmm, an inoperative reverse merge from the "future".  If it is
          from our own future return a helpful error. */
@@ -4078,7 +4079,7 @@ calculate_remaining_ranges(svn_client__m
       err = svn_client__repos_location(&start_loc,
                                        ra_session,
                                        source->loc1,
-                                       child_base_revision,
+                                       child_base->rev,
                                        ctx, scratch_pool, scratch_pool);
       if (err)
         {
@@ -4090,11 +4091,7 @@ calculate_remaining_ranges(svn_client__m
         }
       else
         {
-          const char *url;
-
-          SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child->abspath,
-                                       scratch_pool, scratch_pool));
-          if (strcmp(start_loc->url, url) == 0)
+          if (strcmp(start_loc->url, child_base->url) == 0)
             return svn_error_create(SVN_ERR_CLIENT_MERGE_UPDATE_REQUIRED, NULL,
                                     _("Cannot reverse-merge a range from a "
                                       "path's own future history; try "
Index: subversion/libsvn_client/switch.c
===================================================================
--- subversion/libsvn_client/switch.c	(revision 1327006)
+++ subversion/libsvn_client/switch.c	(working copy)
@@ -197,18 +197,12 @@ switch_internal(svn_revnum_t *result_rev
      ### okay? */
   if (! ignore_ancestry)
     {
-      const char *target_url;
-      svn_revnum_t target_rev;
       svn_client__pathrev_t *switch_loc, *target_loc, *yca;
 
       SVN_ERR(svn_client__pathrev_create_with_session(
                 &switch_loc, ra_session, revnum, switch_rev_url, pool));
-      SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath,
-                                   pool, pool));
-      SVN_ERR(svn_wc__node_get_base_rev(&target_rev, ctx->wc_ctx,
-                                        local_abspath, pool));
-      SVN_ERR(svn_client__pathrev_create_with_session(
-                &target_loc, ra_session, target_rev, target_url, pool));
+      SVN_ERR(svn_client__wc_node_get_base(&target_loc, local_abspath,
+                                           ctx, pool, pool));
       /* ### It would be nice if this function could reuse the existing
              ra session instead of opening two for its own use. */
       SVN_ERR(svn_client__get_youngest_common_ancestor(
Index: subversion/libsvn_client/util.c
===================================================================
--- subversion/libsvn_client/util.c	(revision 1327006)
+++ subversion/libsvn_client/util.c	(working copy)
@@ -263,6 +263,44 @@ svn_client__wc_node_get_origin(svn_clien
 }
 
 svn_error_t *
+svn_client__wc_node_get_base(svn_client__pathrev_t **pathrev_p,
+                             const char *wc_abspath,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  const char *relpath;
+  svn_error_t *err;
+
+  *pathrev_p = apr_palloc(result_pool, sizeof(**pathrev_p));
+
+  err = svn_wc__node_get_base(&(*pathrev_p)->rev,
+                              &relpath,
+                              &(*pathrev_p)->repos_root_url,
+                              &(*pathrev_p)->repos_uuid,
+                              ctx->wc_ctx, wc_abspath,
+                              result_pool, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      *pathrev_p = NULL;
+      return SVN_NO_ERROR;
+    }
+  SVN_ERR(err);
+
+  if ((*pathrev_p)->repos_root_url && relpath)
+    {
+      (*pathrev_p)->url = svn_path_url_add_component2(
+                           (*pathrev_p)->repos_root_url, relpath, result_pool);
+    }
+  else
+    {
+      *pathrev_p = NULL;
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client_get_repos_root(const char **repos_root,
                           const char **repos_uuid,
                           const char *abspath_or_url,
Index: subversion/libsvn_wc/node.c
===================================================================
--- subversion/libsvn_wc/node.c	(revision 1327006)
+++ subversion/libsvn_wc/node.c	(working copy)
@@ -1455,6 +1455,25 @@ svn_wc__internal_get_origin(svn_boolean_
 }
 
 svn_error_t *
+svn_wc__node_get_base(svn_revnum_t *revision,
+                      const char **repos_relpath,
+                      const char **repos_root_url,
+                      const char **repos_uuid,
+                      svn_wc_context_t *wc_ctx,
+                      const char *local_abspath,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, revision, repos_relpath,
+                                   repos_root_url, repos_uuid, NULL,
+                                   NULL, NULL, NULL, NULL, NULL, NULL,
+                                   NULL, NULL,
+                                   wc_ctx->db, local_abspath,
+                                   result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_wc__node_get_origin(svn_boolean_t *is_copy,
                         svn_revnum_t *revision,
                         const char **repos_relpath,
