subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cmpil...@apache.org
Subject svn commit: r1309099 [2/6] - in /subversion/branches/master-passphrase: ./ build/ build/generator/ build/generator/templates/ subversion/bindings/swig/perl/native/t/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/l...
Date Tue, 03 Apr 2012 19:17:02 GMT
Modified: subversion/branches/master-passphrase/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_client/merge.c?rev=1309099&r1=1309098&r2=1309099&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_client/merge.c Tue Apr  3 19:16:59 2012
@@ -158,31 +158,14 @@
 
 /*** Repos-Diff Editor Callbacks ***/
 
-/* Repository root and UUID for a repository. */
-typedef struct url_uuid_t
-{
-  const char *url;
-  const char *uuid;
-} url_uuid_t;
-
-/* A location in a repository. */
-typedef struct repo_location_t
-{
-  url_uuid_t *repo;
-  svn_revnum_t rev;
-  const char *url;
-} repo_location_t;
-
 /* */
 typedef struct merge_source_t
 {
   /* "left" side URL and revision (inclusive iff youngest) */
-  /* The "repo" field is not currently initialized or used. */
-  repo_location_t loc1;
+  const svn_client__pathrev_t *loc1;
 
   /* "right" side URL and revision (inclusive iff youngest) */
-  /* The "repo" field is not currently initialized or used. */
-  repo_location_t loc2;
+  const svn_client__pathrev_t *loc2;
 
 } merge_source_t;
 
@@ -196,9 +179,9 @@ typedef struct merge_target_t
   svn_node_kind_t kind;
 
   /* The repository location of the base node of the target WC.  If the node
-   * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM.  REPO
-   * is always valid. */
-  repo_location_t loc;
+   * is locally added, then URL & REV are NULL & SVN_INVALID_REVNUM.
+   * REPOS_ROOT_URL and REPOS_UUID are always valid. */
+  svn_client__pathrev_t loc;
 
 } merge_target_t;
 
@@ -328,6 +311,33 @@ typedef struct merge_cmd_baton_t {
 
 /*** Utilities ***/
 
+/* Return a new merge_source_t structure, allocated in RESULT_POOL,
+ * initialized with deep copies of LOC1 and LOC2. */
+static merge_source_t *
+merge_source_create(const svn_client__pathrev_t *loc1,
+                    const svn_client__pathrev_t *loc2,
+                    apr_pool_t *result_pool)
+{
+  merge_source_t *s
+    = apr_palloc(result_pool, sizeof(*s));
+
+  s->loc1 = svn_client__pathrev_dup(loc1, result_pool);
+  s->loc2 = svn_client__pathrev_dup(loc2, result_pool);
+  return s;
+}
+
+/* Return a deep copy of SOURCE, allocated in RESULT_POOL. */
+static merge_source_t *
+merge_source_dup(const merge_source_t *source,
+                 apr_pool_t *result_pool)
+{
+  merge_source_t *s = apr_palloc(result_pool, sizeof(*s));
+
+  s->loc1 = svn_client__pathrev_dup(source->loc1, result_pool);
+  s->loc2 = svn_client__pathrev_dup(source->loc2, result_pool);
+  return s;
+}
+
 /* Return SVN_ERR_UNSUPPORTED_FEATURE if URL is not inside the repository
    of LOCAL_ABSPATH.  Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
@@ -336,45 +346,45 @@ check_repos_match(merge_cmd_baton_t *mer
                   const char *url,
                   apr_pool_t *scratch_pool)
 {
-  if (!svn_uri__is_ancestor(merge_b->target->loc.repo->url, url))
+  if (!svn_uri__is_ancestor(merge_b->target->loc.repos_root_url, url))
     return svn_error_createf(
         SVN_ERR_UNSUPPORTED_FEATURE, NULL,
          _("Url '%s' of '%s' is not in repository '%s'"),
          url, svn_dirent_local_style(local_abspath, scratch_pool),
-         merge_b->target->loc.repo->url);
+         merge_b->target->loc.repos_root_url);
 
   return SVN_NO_ERROR;
 }
 
-/* Return TRUE iff the repository identified by REPOS_ROOT1 is the same as
- * that identified by REPOS_ROOT2.  If STRICT_URLS is true, the URLs must
+/* Return TRUE iff the repository of LOCATION1 is the same as
+ * that of LOCATION2.  If STRICT_URLS is true, the URLs must
  * match (and the UUIDs, just to be sure), otherwise just the UUIDs must
  * match and the URLs can differ (a common case is http versus https). */
 static svn_boolean_t
-is_same_repos(const url_uuid_t *repos_root1,
-              const url_uuid_t *repos_root2,
+is_same_repos(const svn_client__pathrev_t *location1,
+              const svn_client__pathrev_t *location2,
               svn_boolean_t strict_urls)
 {
   if (strict_urls)
-    return (strcmp(repos_root1->url, repos_root2->url) == 0
-            && strcmp(repos_root1->uuid, repos_root2->uuid) == 0);
+    return (strcmp(location1->repos_root_url, location2->repos_root_url) == 0
+            && strcmp(location1->repos_uuid, location2->repos_uuid) == 0);
   else
-    return (strcmp(repos_root1->uuid, repos_root2->uuid) == 0);
+    return (strcmp(location1->repos_uuid, location2->repos_uuid) == 0);
 }
 
-/* If the repository identified by REPOS_ROOT1 is not the same as that
- * identified by REPOS_ROOT2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES
+/* If the repository identified of LOCATION1 is not the same as that
+ * of LOCATION2, throw a SVN_ERR_CLIENT_UNRELATED_RESOURCES
  * error mentioning PATH1 and PATH2. For STRICT_URLS, see is_same_repos().
  */
 static svn_error_t *
-check_same_repos(const url_uuid_t *repos_root1,
+check_same_repos(const svn_client__pathrev_t *location1,
                  const char *path1,
-                 const url_uuid_t *repos_root2,
+                 const svn_client__pathrev_t *location2,
                  const char *path2,
                  svn_boolean_t strict_urls,
                  apr_pool_t *scratch_pool)
 {
-  if (! is_same_repos(repos_root1, repos_root2, strict_urls))
+  if (! is_same_repos(location1, location2, strict_urls))
     return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                              _("'%s' must be from the same repository as "
                                "'%s'"), path1, path2);
@@ -520,33 +530,25 @@ make_conflict_versions(const svn_wc_conf
                        svn_node_kind_t node_kind,
                        merge_cmd_baton_t *merge_b)
 {
-  const char *src_repos_url;  /* root URL of source repository */
-  const char *left_url;
-  const char *right_url;
+  const char *child = svn_dirent_skip_ancestor(merge_b->target->abspath,
+                                               victim_abspath);
+  const char *left_relpath, *right_relpath;
 
-  SVN_ERR(svn_ra_get_repos_root2(merge_b->ra_session1, &src_repos_url,
-                                 merge_b->pool));
-
-  /* Construct the source URLs of the victim. */
-  {
-    const char *child = svn_dirent_skip_ancestor(merge_b->target->abspath,
-                                                 victim_abspath);
-    SVN_ERR_ASSERT(child != NULL);
-    left_url = svn_path_url_add_component2(merge_b->merge_source.loc1.url,
-                                           child, merge_b->pool);
-    right_url = svn_path_url_add_component2(merge_b->merge_source.loc2.url,
-                                            child, merge_b->pool);
-  }
+  SVN_ERR_ASSERT(child != NULL);
+  left_relpath = svn_client__pathrev_relpath(merge_b->merge_source.loc1,
+                                             merge_b->pool);
+  right_relpath = svn_client__pathrev_relpath(merge_b->merge_source.loc2,
+                                              merge_b->pool);
 
   *left = svn_wc_conflict_version_create(
-            src_repos_url,
-            svn_uri_skip_ancestor(src_repos_url, left_url, merge_b->pool),
-            merge_b->merge_source.loc1.rev, node_kind, merge_b->pool);
+            merge_b->merge_source.loc1->repos_root_url,
+            svn_relpath_join(left_relpath, child, merge_b->pool),
+            merge_b->merge_source.loc1->rev, node_kind, merge_b->pool);
 
   *right = svn_wc_conflict_version_create(
-             src_repos_url,
-             svn_uri_skip_ancestor(src_repos_url, right_url, merge_b->pool),
-             merge_b->merge_source.loc2.rev, node_kind, merge_b->pool);
+             merge_b->merge_source.loc2->repos_root_url,
+             svn_relpath_join(right_relpath, child, merge_b->pool),
+             merge_b->merge_source.loc2->rev, node_kind, merge_b->pool);
 
   return SVN_NO_ERROR;
 }
@@ -863,8 +865,7 @@ filter_self_referential_mergeinfo(apr_ar
   int i;
   apr_pool_t *iterpool;
   svn_boolean_t is_added;
-  const char *target_base_url;
-  svn_revnum_t target_base_rev;
+  svn_client__pathrev_t target_base;
 
   /* Issue #3383: We don't want mergeinfo from a foreign repos.
 
@@ -892,10 +893,13 @@ filter_self_referential_mergeinfo(apr_ar
   if (is_added)
     return SVN_NO_ERROR;
 
-  SVN_ERR(svn_client_url_from_path2(&target_base_url, target_abspath,
+  SVN_ERR(svn_client_url_from_path2(&target_base.url, target_abspath,
                                     ctx, pool, pool));
-  SVN_ERR(svn_wc__node_get_base_rev(&target_base_rev, ctx->wc_ctx,
+  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));
 
   adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
   iterpool = svn_pool_create(pool);
@@ -965,7 +969,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. */
@@ -994,7 +998,7 @@ filter_self_referential_mergeinfo(apr_ar
               for (j = 0; j < rangelist->nelts; j++)
                 {
                   svn_error_t *err2;
-                  const char *start_url;
+                  svn_client__pathrev_t *start_loc;
                   svn_merge_range_t *range =
                     APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *);
 
@@ -1006,8 +1010,8 @@ filter_self_referential_mergeinfo(apr_ar
                   /* Check if PATH@BASE_REVISION exists at
                      RANGE->START on the same line of history.
                      (start+1 because RANGE->start is not inclusive.) */
-                  err2 = svn_client__repos_location(&start_url, ra_session,
-                                                    target_base_url, target_base_rev,
+                  err2 = svn_client__repos_location(&start_loc, ra_session,
+                                                    &target_base,
                                                     range->start + 1,
                                                     ctx, iterpool, iterpool);
                   if (err2)
@@ -1054,7 +1058,7 @@ filter_self_referential_mergeinfo(apr_ar
                          PATH@RANGE->END actually belong to some other
                          line of history and we want to record this
                          mergeinfo, not filter it. */
-                      if (strcmp(start_url, merge_source_url) != 0)
+                      if (strcmp(start_loc->url, merge_source_url) != 0)
                         {
                           APR_ARRAY_PUSH(adjusted_rangelist,
                                          svn_merge_range_t *) = range;
@@ -1083,8 +1087,8 @@ filter_self_referential_mergeinfo(apr_ar
           svn_mergeinfo_t implicit_mergeinfo;
 
           SVN_ERR(svn_client__get_history_as_mergeinfo(
-            &implicit_mergeinfo, NULL, target_base_url,
-            target_base_rev, target_base_rev, SVN_INVALID_REVNUM,
+            &implicit_mergeinfo, NULL, target_base.url,
+            target_base.rev, target_base.rev, SVN_INVALID_REVNUM,
             ra_session, ctx, iterpool));
 
           /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */
@@ -1176,7 +1180,7 @@ merge_props_changed(svn_wc_notify_state_
          http://svn.haxx.se/dev/archive-2008-09/0006.shtml.  If the
          merge sources are not ancestral then there is no concept of a
          'forward' or 'reverse' merge and we filter unconditionally. */
-      if (merge_b->merge_source.loc1.rev < merge_b->merge_source.loc2.rev
+      if (merge_b->merge_source.loc1->rev < merge_b->merge_source.loc2->rev
           || !merge_b->sources_ancestral)
         SVN_ERR(filter_self_referential_mergeinfo(&props,
                                                   local_abspath,
@@ -1804,7 +1808,7 @@ merge_file_added(svn_wc_notify_state_t *
                                            mine_abspath);
                 SVN_ERR_ASSERT(child != NULL);
                 copyfrom_url = svn_path_url_add_component2(
-                                             merge_b->merge_source.loc2.url,
+                                             merge_b->merge_source.loc2->url,
                                              child, scratch_pool);
                 copyfrom_rev = rev2;
                 SVN_ERR(check_repos_match(merge_b, mine_abspath, copyfrom_url,
@@ -2199,7 +2203,7 @@ merge_dir_added(svn_wc_notify_state_t *s
      add. */
   if (merge_b->same_repos)
     {
-      copyfrom_url = svn_path_url_add_component2(merge_b->merge_source.loc2.url,
+      copyfrom_url = svn_path_url_add_component2(merge_b->merge_source.loc2->url,
                                                  child, scratch_pool);
       copyfrom_rev = rev;
 
@@ -3361,7 +3365,7 @@ fix_deleted_subtree_ranges(const merge_s
 {
   int i;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  svn_boolean_t is_rollback = source->loc2.rev < source->loc1.rev;
+  svn_boolean_t is_rollback = source->loc2->rev < source->loc1->rev;
 
   /* CHILDREN_WITH_MERGEINFO is sorted in depth-first order, so
      start at index 1 to examine only subtrees. */
@@ -3435,13 +3439,13 @@ fix_deleted_subtree_ranges(const merge_s
           SVN_ERR_ASSERT(child_repos_src_path);
 
           child_primary_source_url =
-            svn_path_url_add_component2((source->loc1.rev < source->loc2.rev)
-                                        ? source->loc2.url : source->loc1.url,
+            svn_path_url_add_component2((source->loc1->rev < source->loc2->rev)
+                                        ? source->loc2->url : source->loc1->url,
                                         child_repos_src_path, iterpool);
 
           SVN_ERR(adjust_deleted_subtree_ranges(child, parent,
-                                                source->loc1.rev,
-                                                source->loc2.rev,
+                                                source->loc1->rev,
+                                                source->loc2->rev,
                                                 child_primary_source_url,
                                                 ra_session,
                                                 merge_b->ctx, result_pool,
@@ -3989,8 +3993,8 @@ calculate_remaining_ranges(svn_client__m
                            apr_pool_t *scratch_pool)
 {
   const char *mergeinfo_path;
-  const char *primary_url = (source->loc1.rev < source->loc2.rev)
-                            ? source->loc2.url : source->loc1.url;
+  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;
 
@@ -4030,7 +4034,7 @@ calculate_remaining_ranges(svn_client__m
      merged (or, in the case of reverse merges, ranges not yet merged). */
   SVN_ERR(filter_merged_revisions(parent, child, mergeinfo_path,
                                   adjusted_target_mergeinfo,
-                                  source->loc1.rev, source->loc2.rev,
+                                  source->loc1->rev, source->loc2->rev,
                                   child_inherits_implicit,
                                   ra_session, ctx, result_pool,
                                   scratch_pool));
@@ -4067,18 +4071,17 @@ calculate_remaining_ranges(svn_client__m
      can't have any "future" history. */
   if (SVN_IS_VALID_REVNUM(child_base_revision)
       && ((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 */
+      && (source->loc2->rev < source->loc1->rev)     /* Reverse merge */
+      && (child_base_revision <= 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. */
       svn_error_t *err;
-      const char *start_url;
+      svn_client__pathrev_t *start_loc;
 
-      err = svn_client__repos_location(&start_url,
+      err = svn_client__repos_location(&start_loc,
                                        ra_session,
-                                       source->loc1.url,
-                                       source->loc1.rev,
+                                       source->loc1,
                                        child_base_revision,
                                        ctx, scratch_pool, scratch_pool);
       if (err)
@@ -4095,7 +4098,7 @@ calculate_remaining_ranges(svn_client__m
 
           SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child->abspath,
                                        scratch_pool, scratch_pool));
-          if (strcmp(start_url, url) == 0)
+          if (strcmp(start_loc->url, 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 "
@@ -4141,10 +4144,10 @@ find_gaps_in_merge_source_history(svn_re
                                   apr_pool_t *scratch_pool)
 {
   svn_mergeinfo_t implicit_src_mergeinfo;
-  svn_revnum_t young_rev = MAX(source->loc1.rev, source->loc2.rev);
-  svn_revnum_t old_rev = MIN(source->loc1.rev, source->loc2.rev);
-  const char *primary_url = (source->loc1.rev < source->loc2.rev)
-                            ? source->loc2.url : source->loc1.url;
+  svn_revnum_t young_rev = MAX(source->loc1->rev, source->loc2->rev);
+  svn_revnum_t old_rev = MIN(source->loc1->rev, source->loc2->rev);
+  const char *primary_url = (source->loc1->rev < source->loc2->rev)
+                            ? source->loc2->url : source->loc1->url;
   const char *merge_src_fspath;
   apr_array_header_t *rangelist;
 
@@ -4193,7 +4196,7 @@ find_gaps_in_merge_source_history(svn_re
       /* As mentioned above, multiple gaps *shouldn't* be possible. */
       SVN_ERR_ASSERT(apr_hash_count(implicit_src_mergeinfo) == 1);
 
-      *gap_start = MIN(source->loc1.rev, source->loc2.rev);
+      *gap_start = MIN(source->loc1->rev, source->loc2->rev);
       *gap_end = (APR_ARRAY_IDX(rangelist,
                                 rangelist->nelts - 1,
                                 svn_merge_range_t *))->start;
@@ -4201,8 +4204,8 @@ find_gaps_in_merge_source_history(svn_re
   else if (apr_hash_count(implicit_src_mergeinfo) > 1) /* Rename */
     {
       apr_array_header_t *requested_rangelist =
-        svn_rangelist__initialize(MIN(source->loc1.rev, source->loc2.rev),
-                                  MAX(source->loc1.rev, source->loc2.rev),
+        svn_rangelist__initialize(MIN(source->loc1->rev, source->loc2->rev),
+                                  MAX(source->loc1->rev, source->loc2->rev),
                                   TRUE, scratch_pool);
       apr_array_header_t *implicit_rangelist =
         apr_array_make(scratch_pool, 2, sizeof(svn_merge_range_t *));
@@ -4291,10 +4294,10 @@ populate_remaining_ranges(apr_array_head
                                          NULL, /* child->inherited_mergeinfo */
                                          svn_mergeinfo_inherited, ra_session,
                                          child->abspath,
-                                         MAX(source->loc1.rev,
-                                             source->loc2.rev),
-                                         MIN(source->loc1.rev,
-                                             source->loc2.rev),
+                                         MAX(source->loc1->rev,
+                                             source->loc2->rev),
+                                         MIN(source->loc1->rev,
+                                             source->loc2->rev),
                                          merge_b->ctx, result_pool,
                                          iterpool));
             }
@@ -4315,14 +4318,14 @@ populate_remaining_ranges(apr_array_head
               child_inherits_implicit = (parent && !child->switched);
               SVN_ERR(ensure_implicit_mergeinfo(parent, child,
                                                 child_inherits_implicit,
-                                                source->loc1.rev,
-                                                source->loc2.rev,
+                                                source->loc1->rev,
+                                                source->loc2->rev,
                                                 ra_session, merge_b->ctx,
                                                 result_pool, iterpool));
             }
 
-          child->remaining_ranges = svn_rangelist__initialize(source->loc1.rev,
-                                                              source->loc2.rev,
+          child->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
+                                                              source->loc2->rev,
                                                               TRUE,
                                                               result_pool);
         }
@@ -4356,7 +4359,9 @@ populate_remaining_ranges(apr_array_head
   for (i = 0; i < children_with_mergeinfo->nelts; i++)
     {
       const char *child_repos_path;
-      merge_source_t child_source = *source;
+      svn_client__pathrev_t loc1 = *source->loc1;
+      svn_client__pathrev_t loc2 = *source->loc2;
+      merge_source_t child_source = { &loc1, &loc2 };
       svn_client__merge_path_t *child =
         APR_ARRAY_IDX(children_with_mergeinfo, i, svn_client__merge_path_t *);
       svn_client__merge_path_t *parent = NULL;
@@ -4374,10 +4379,10 @@ populate_remaining_ranges(apr_array_head
       child_repos_path = svn_dirent_skip_ancestor(merge_b->target->abspath,
                                                   child->abspath);
       SVN_ERR_ASSERT(child_repos_path != NULL);
-      child_source.loc1.url = svn_path_url_add_component2(
-                                source->loc1.url, child_repos_path, iterpool);
-      child_source.loc2.url = svn_path_url_add_component2(
-                                source->loc2.url, child_repos_path, iterpool);
+      loc1.url = svn_path_url_add_component2(
+                                source->loc1->url, child_repos_path, iterpool);
+      loc2.url = svn_path_url_add_component2(
+                                source->loc2->url, child_repos_path, iterpool);
 
       /* Get the explicit/inherited mergeinfo for CHILD.  If CHILD is the
          merge target then also get its implicit mergeinfo.  Otherwise defer
@@ -4390,8 +4395,8 @@ populate_remaining_ranges(apr_array_head
         &(child->inherited_mergeinfo),
         svn_mergeinfo_inherited, ra_session,
         child->abspath,
-        MAX(source->loc1.rev, source->loc2.rev),
-        MIN(source->loc1.rev, source->loc2.rev),
+        MAX(source->loc1->rev, source->loc2->rev),
+        MIN(source->loc1->rev, source->loc2->rev),
         merge_b->ctx, result_pool, iterpool));
 
       /* If CHILD isn't the merge target find its parent. */
@@ -4442,7 +4447,7 @@ populate_remaining_ranges(apr_array_head
 
           /* If this is a reverse merge reorder CHILD->REMAINING_RANGES
               so it will work with the svn_rangelist_* APIs below. */
-          if (source->loc1.rev > source->loc2.rev)
+          if (source->loc1->rev > source->loc2->rev)
             SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
 
           for (j = 0; j < child->remaining_ranges->nelts; j++)
@@ -4484,7 +4489,7 @@ populate_remaining_ranges(apr_array_head
                                              result_pool));
             }
 
-          if (source->loc1.rev > source->loc2.rev) /* Reverse merge */
+          if (source->loc1->rev > source->loc2->rev) /* Reverse merge */
             SVN_ERR(svn_rangelist_reverse(child->remaining_ranges, iterpool));
         }
     }
@@ -4657,7 +4662,7 @@ update_wc_mergeinfo(svn_mergeinfo_catalo
 
    IS_ROLLBACK is true if the caller is recording a reverse merge and false
    otherwise.  RANGELIST is the set of revisions being merged from
-   MERGEINFO_PATH to MERGE_B->TARGET_ABSPATH. */
+   MERGEINFO_PATH to MERGE_B->target. */
 static svn_error_t *
 record_skips(const char *mergeinfo_path,
              const apr_array_header_t *rangelist,
@@ -4776,7 +4781,7 @@ remove_absent_children(const char *targe
    false then for each path (if any) in MERGE_B->PATHS_WITH_DELETED_MERGEINFO
    remove that path from CHILDREN_WITH_MERGEINFO by setting that
    child to NULL.  The one exception is for the merge target itself,
-   MERGE_B->TARGET_ABSPATH, this must always be present in
+   MERGE_B->target->abspath, this must always be present in
    CHILDREN_WITH_MERGEINFO so this is never removed by this
    function. */
 static void
@@ -4885,11 +4890,11 @@ drive_merge_report_editor(const char *ta
   svn_revnum_t target_start;
   svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
   const char *old_sess1_url, *old_sess2_url;
-  svn_boolean_t is_rollback = source->loc1.rev > source->loc2.rev;
+  svn_boolean_t is_rollback = source->loc1->rev > source->loc2->rev;
 
   /* Start with a safe default starting revision for the editor and the
      merge target. */
-  target_start = source->loc1.rev;
+  target_start = source->loc1->rev;
 
   /* If we are honoring mergeinfo the starting revision for the merge target
      might not be SOURCE->rev1, in fact the merge target might not need *any*
@@ -4915,7 +4920,7 @@ drive_merge_report_editor(const char *ta
       if (child->remaining_ranges->nelts == 0)
         {
           /* The merge target doesn't need anything merged. */
-          target_start = source->loc2.rev;
+          target_start = source->loc2->rev;
         }
       else
         {
@@ -4926,11 +4931,11 @@ drive_merge_report_editor(const char *ta
           svn_merge_range_t *range =
             APR_ARRAY_IDX(child->remaining_ranges, 0,
                           svn_merge_range_t *);
-          if ((!is_rollback && range->start > source->loc2.rev)
-              || (is_rollback && range->start < source->loc2.rev))
+          if ((!is_rollback && range->start > source->loc2->rev)
+              || (is_rollback && range->start < source->loc2->rev))
             {
               /* Merge target's first remaining range doesn't intersect. */
-              target_start = source->loc2.rev;
+              target_start = source->loc2->rev;
             }
           else
             {
@@ -4943,18 +4948,18 @@ drive_merge_report_editor(const char *ta
 
   SVN_ERR(svn_client__ensure_ra_session_url(&old_sess1_url,
                                             merge_b->ra_session1,
-                                            source->loc1.url, scratch_pool));
+                                            source->loc1->url, scratch_pool));
   /* Temporarily point our second RA session to SOURCE->url1, too.  We use
      this to request individual file contents. */
   SVN_ERR(svn_client__ensure_ra_session_url(&old_sess2_url,
                                             merge_b->ra_session2,
-                                            source->loc1.url, scratch_pool));
+                                            source->loc1->url, scratch_pool));
 
   /* Get the diff editor and a reporter with which to, ultimately,
      drive it. */
   SVN_ERR(svn_client__get_diff_editor(&diff_editor, &diff_edit_baton,
                                       depth,
-                                      merge_b->ra_session2, source->loc1.rev,
+                                      merge_b->ra_session2, source->loc1->rev,
                                       FALSE /* walk_deleted_dirs */,
                                       TRUE /* text_deltas */,
                                       &merge_callbacks, merge_b,
@@ -4963,10 +4968,10 @@ drive_merge_report_editor(const char *ta
                                       notification_receiver, notify_b,
                                       scratch_pool));
   SVN_ERR(svn_ra_do_diff3(merge_b->ra_session1,
-                          &reporter, &report_baton, source->loc2.rev,
+                          &reporter, &report_baton, source->loc2->rev,
                           "", depth, merge_b->ignore_ancestry,
                           TRUE,  /* text_deltas */
-                          source->loc2.url, diff_editor, diff_edit_baton,
+                          source->loc2->url, diff_editor, diff_edit_baton,
                           scratch_pool));
 
   /* Drive the reporter. */
@@ -5011,8 +5016,8 @@ drive_merge_report_editor(const char *ta
             {
               range = APR_ARRAY_IDX(child->remaining_ranges, 0,
                                     svn_merge_range_t *);
-              if ((!is_rollback && range->start > source->loc2.rev)
-                  || (is_rollback && range->start < source->loc2.rev))
+              if ((!is_rollback && range->start > source->loc2->rev)
+                  || (is_rollback && range->start < source->loc2->rev))
                 {
                   /* This child's first remaining range comes after the range
                      we are currently merging, so skip it. We expect to get
@@ -5050,14 +5055,14 @@ drive_merge_report_editor(const char *ta
           SVN_ERR_ASSERT(child_repos_path);
 
           if ((child->remaining_ranges->nelts == 0)
-              || (is_rollback && (range->start < source->loc2.rev))
-              || (!is_rollback && (range->start > source->loc2.rev)))
+              || (is_rollback && (range->start < source->loc2->rev))
+              || (!is_rollback && (range->start > source->loc2->rev)))
             {
               /* Nothing to merge to this child.  We'll claim we have
                  it up to date so the server doesn't send us
                  anything. */
               SVN_ERR(reporter->set_path(report_baton, child_repos_path,
-                                         source->loc2.rev, depth, FALSE,
+                                         source->loc2->rev, depth, FALSE,
                                          NULL, iterpool));
             }
           else
@@ -5354,7 +5359,7 @@ insert_child_to_merge(apr_array_header_t
    get_mergeinfo_paths() is iterating over and *CURR_INDEX is index for
    *CHILD.
 
-   If CHILD->ABSPATH is equal to MERGE_CMD_BATON->TARGET_ABSPATH do nothing.
+   If CHILD->ABSPATH is equal to MERGE_CMD_BATON->target->abspath do nothing.
    Else if CHILD->ABSPATH is switched or absent then make sure its immediate
    (as opposed to nearest) parent in CHILDREN_WITH_MERGEINFO is marked as
    missing a child.  If the immediate parent does not exist in
@@ -5621,14 +5626,14 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
 /* Helper for do_directory_merge() when performing merge-tracking aware
    merges.
 
-   Walk of the working copy tree rooted at MERGE_CMD_BATON->TARGET_ABSPATH to
+   Walk of the working copy tree rooted at MERGE_CMD_BATON->target->abspath to
    depth DEPTH.  Create an svn_client__merge_path_t * for any path which meets
    one or more of the following criteria:
 
      1) Path has working svn:mergeinfo.
      2) Path is switched.
      3) Path is a subtree of the merge target (i.e. is not equal to
-        MERGE_CMD_BATON->TARGET_ABSPATH) and has no mergeinfo of its own but
+        MERGE_CMD_BATON->target->abspath) and has no mergeinfo of its own but
         its immediate parent has mergeinfo with non-inheritable ranges.  If
         this isn't a dry-run and the merge is between differences in the same
         repository, then this function will set working mergeinfo on the path
@@ -5640,10 +5645,10 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
         sibling is switched, absent, scheduled for deletion, or missing due to
         a sparse checkout.
      6) Path is absent from disk due to an authz restriction.
-     7) Path is equal to MERGE_CMD_BATON->TARGET_ABSPATH.
+     7) Path is equal to MERGE_CMD_BATON->target->abspath.
      8) Path is an immediate *directory* child of
-        MERGE_CMD_BATON->TARGET_ABSPATH and DEPTH is svn_depth_immediates.
-     9) Path is an immediate *file* child of MERGE_CMD_BATON->TARGET_ABSPATH
+        MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_immediates.
+     9) Path is an immediate *file* child of MERGE_CMD_BATON->target->abspath
         and DEPTH is svn_depth_files.
      10) Path is at a depth of 'empty' or 'files'.
      11) Path is missing from disk (e.g. due to an OS-level deletion).
@@ -5656,7 +5661,7 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
    sorted by svn_path_compare_paths().  Set the remaining_ranges field of each
    element to NULL.
 
-   Note: Since the walk is rooted at MERGE_CMD_BATON->TARGET_ABSPATH, the
+   Note: Since the walk is rooted at MERGE_CMD_BATON->target->abspath, the
    latter is guaranteed to be in *CHILDREN_WITH_MERGEINFO and due to the
    depth-first ordering it is guaranteed to be the first element in
    *CHILDREN_WITH_MERGEINFO.
@@ -5708,8 +5713,9 @@ get_mergeinfo_paths(apr_array_header_t *
             = svn_mergeinfo__is_noninheritable(
                 mergeinfo_child->pre_merge_mergeinfo, iterpool);
 
-          insert_child_to_merge(children_with_mergeinfo, mergeinfo_child,
-                                result_pool);
+          /* Append it.  We'll sort below. */
+          APR_ARRAY_PUSH(children_with_mergeinfo, svn_client__merge_path_t *)
+            = svn_client__merge_path_dup(mergeinfo_child, result_pool);
         }
 
       /* Sort CHILDREN_WITH_MERGEINFO by each child's path (i.e. as per
@@ -5878,7 +5884,7 @@ get_mergeinfo_paths(apr_array_header_t *
         }
     }
 
-  /* Case 7: The merge target MERGE_CMD_BATON->TARGET_ABSPATH is always
+  /* Case 7: The merge target MERGE_CMD_BATON->target->abspath is always
      present. */
   if (!get_child_with_mergeinfo(children_with_mergeinfo,
                                 merge_cmd_baton->target->abspath))
@@ -5891,10 +5897,10 @@ get_mergeinfo_paths(apr_array_header_t *
     }
 
   /* Case 8: Path is an immediate *directory* child of
-     MERGE_CMD_BATON->TARGET_ABSPATH and DEPTH is svn_depth_immediates.
+     MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_immediates.
 
      Case 9: Path is an immediate *file* child of
-     MERGE_CMD_BATON->TARGET_ABSPATH and DEPTH is svn_depth_files. */
+     MERGE_CMD_BATON->target->abspath and DEPTH is svn_depth_files. */
   if (depth == svn_depth_immediates || depth == svn_depth_files)
     {
       int j;
@@ -6201,8 +6207,8 @@ static int
 compare_merge_source_ts(const void *a,
                         const void *b)
 {
-  svn_revnum_t a_rev = ((const merge_source_t *)a)->loc1.rev;
-  svn_revnum_t b_rev = ((const merge_source_t *)b)->loc1.rev;
+  svn_revnum_t a_rev = (*(const merge_source_t *const *)a)->loc1->rev;
+  svn_revnum_t b_rev = (*(const merge_source_t *const *)b)->loc1->rev;
   if (a_rev == b_rev)
     return 0;
   return a_rev < b_rev ? 1 : -1;
@@ -6210,7 +6216,7 @@ compare_merge_source_ts(const void *a,
 
 /* Set *MERGE_SOURCE_TS_P to a list of merge sources generated by
    slicing history location SEGMENTS with a given requested merge
-   RANGE.  Use SOURCE_ROOT_URL for full source URL calculation.
+   RANGE.  Use SOURCE_LOC for full source URL calculation.
 
    Order the merge sources in *MERGE_SOURCE_TS_P from oldest to
    youngest. */
@@ -6218,7 +6224,7 @@ static svn_error_t *
 combine_range_with_segments(apr_array_header_t **merge_source_ts_p,
                             const svn_merge_range_t *range,
                             const apr_array_header_t *segments,
-                            const char *source_root_url,
+                            const svn_client__pathrev_t *source_loc,
                             apr_pool_t *pool)
 {
   apr_array_header_t *merge_source_ts =
@@ -6232,6 +6238,7 @@ combine_range_with_segments(apr_array_he
     {
       svn_location_segment_t *segment =
         APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
+      svn_client__pathrev_t loc1, loc2;
       merge_source_t *merge_source;
       const char *path1 = NULL;
       svn_revnum_t rev1;
@@ -6279,20 +6286,22 @@ combine_range_with_segments(apr_array_he
         continue;
 
       /* Build our merge source structure. */
-      merge_source = apr_pcalloc(pool, sizeof(*merge_source));
-      merge_source->loc1.url = svn_path_url_add_component2(source_root_url,
-                                                           path1,
-                                                           pool);
-      merge_source->loc2.url = svn_path_url_add_component2(source_root_url,
-                                                           segment->path,
-                                                           pool);
-      merge_source->loc1.rev = rev1;
-      merge_source->loc2.rev = MIN(segment->range_end, maxrev);
+      loc1.repos_root_url = source_loc->repos_root_url;
+      loc1.repos_uuid = source_loc->repos_uuid;
+      loc1.rev = rev1;
+      loc1.url = svn_path_url_add_component2(source_loc->repos_root_url,
+                                             path1, pool);
+      loc2.repos_root_url = source_loc->repos_root_url;
+      loc2.repos_uuid = source_loc->repos_uuid;
+      loc2.rev = MIN(segment->range_end, maxrev);
+      loc2.url = svn_path_url_add_component2(source_loc->repos_root_url,
+                                             segment->path, pool);
+      merge_source = merge_source_create(&loc1, &loc2, pool);
 
       /* If this is subtractive, reverse the whole calculation. */
       if (subtractive)
         {
-          repo_location_t tmploc = merge_source->loc1;
+          const svn_client__pathrev_t *tmploc = merge_source->loc1;
           merge_source->loc1 = merge_source->loc2;
           merge_source->loc2 = tmploc;
         }
@@ -6314,22 +6323,21 @@ combine_range_with_segments(apr_array_he
  * no SOURCE_PATH_OR_URL argument;
  * MERGE_RANGE_TS (array of svn_merge_range_t *) instead of RANGES;
  * SOURCE_PEG_REVNUM instead of SOURCE_PEG_REVISION.
- * RA_SESSION is an RA session open to the repository of SOURCE_URL; it may
+ * RA_SESSION is an RA session open to the repository of SOURCE_LOC; it may
  * be temporarily reparented within this function.
  */
 static svn_error_t *
 normalize_merge_sources_internal(apr_array_header_t **merge_sources_p,
-                                 const char *source_url,
-                                 svn_revnum_t source_peg_revnum,
+                                 const svn_client__pathrev_t *source_loc,
                                  const apr_array_header_t *merge_range_ts,
                                  svn_ra_session_t *ra_session,
                                  svn_client_ctx_t *ctx,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
+  svn_revnum_t source_peg_revnum = source_loc->rev;
   svn_revnum_t oldest_requested, youngest_requested;
   svn_revnum_t trim_revision = SVN_INVALID_REVNUM;
-  const char *source_root_url;
   apr_array_header_t *segments;
   int i;
 
@@ -6351,11 +6359,10 @@ normalize_merge_sources_internal(apr_arr
      all the underlying APIs would do in this case right now anyway). */
   if (source_peg_revnum < youngest_requested)
     {
-      const char *start_url;
+      svn_client__pathrev_t *start_loc;
 
-      SVN_ERR(svn_client__repos_location(&start_url,
-                                         ra_session, source_url,
-                                         source_peg_revnum,
+      SVN_ERR(svn_client__repos_location(&start_loc,
+                                         ra_session, source_loc,
                                          youngest_requested,
                                          ctx, scratch_pool, scratch_pool));
       source_peg_revnum = youngest_requested;
@@ -6363,14 +6370,12 @@ normalize_merge_sources_internal(apr_arr
 
   /* Fetch the locations for our merge range span. */
   SVN_ERR(svn_client__repos_location_segments(&segments,
-                                              ra_session, source_url,
+                                              ra_session, source_loc->url,
                                               source_peg_revnum,
                                               youngest_requested,
                                               oldest_requested,
                                               ctx, result_pool));
 
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, &source_root_url, scratch_pool));
-
   /* See if we fetched enough history to do the job.  "Surely we did,"
      you say.  "After all, we covered the entire requested merge
      range."  Yes, that's true, but if our first segment doesn't
@@ -6414,9 +6419,9 @@ normalize_merge_sources_internal(apr_arr
               range_start_rev.kind = svn_opt_revision_number;
               range_start_rev.value.number = segment2->range_start;
 
-              segment_url = svn_path_url_add_component2(source_root_url,
-                                                        segment2->path,
-                                                        scratch_pool);
+              segment_url = svn_path_url_add_component2(
+                              source_loc->repos_root_url, segment2->path,
+                              scratch_pool);
               SVN_ERR(svn_client__get_copy_source(segment_url,
                                                   &range_start_rev,
                                                   &copyfrom_path,
@@ -6467,7 +6472,7 @@ normalize_merge_sources_internal(apr_arr
 
       /* Copy the resulting merge sources into master list thereof. */
       SVN_ERR(combine_range_with_segments(&merge_sources, range,
-                                          segments, source_root_url,
+                                          segments, source_loc,
                                           result_pool));
       apr_array_cat(*merge_sources_p, merge_sources);
     }
@@ -6480,12 +6485,12 @@ normalize_merge_sources_internal(apr_arr
    requested merges; order the objects from oldest to youngest.
 
    Determine the requested merges by examining SOURCE_PATH_OR_URL (and its
-   associated URL and revision, SOURCE_URL and SOURCE_PEG_REVNUM) (which
+   associated URL and revision, SOURCE_LOC) (which
    specifies the line of history from which merges will be pulled) and
    RANGES_TO_MERGE (a list of svn_opt_revision_range_t's which provide
    revision ranges).
 
-   RA_SESSION is an RA session open to the repository of SOURCE_URL; it may
+   RA_SESSION is an RA session open to the repository of SOURCE_LOC; it may
    be temporarily reparented within this function.  Use RA_SESSION to answer
    historical questions.
 
@@ -6500,8 +6505,7 @@ normalize_merge_sources_internal(apr_arr
 static svn_error_t *
 normalize_merge_sources(apr_array_header_t **merge_sources_p,
                         const char *source_path_or_url,
-                        const char *source_url,
-                        svn_revnum_t source_peg_revnum,
+                        const svn_client__pathrev_t *source_loc,
                         const apr_array_header_t *ranges_to_merge,
                         svn_ra_session_t *ra_session,
                         svn_client_ctx_t *ctx,
@@ -6560,7 +6564,7 @@ normalize_merge_sources(apr_array_header
     }
 
   SVN_ERR(normalize_merge_sources_internal(
-            merge_sources_p, source_url, source_peg_revnum,
+            merge_sources_p, source_loc,
             merge_range_ts, ra_session, ctx, result_pool, scratch_pool));
 
   svn_pool_destroy(iterpool);
@@ -6641,26 +6645,25 @@ subrange_source(const merge_source_t *so
                 svn_revnum_t end_rev,
                 apr_pool_t *pool)
 {
-  svn_boolean_t is_rollback = (source->loc1.rev > source->loc2.rev);
-  svn_boolean_t same_urls = (strcmp(source->loc1.url, source->loc2.url) == 0);
-  merge_source_t *real_source = apr_palloc(pool, sizeof(*source));
-
-  real_source->loc1.url = source->loc1.url;
-  real_source->loc1.rev = start_rev;
-  real_source->loc2.url = source->loc2.url;
-  real_source->loc2.rev = end_rev;
+  svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
+  svn_boolean_t same_urls = (strcmp(source->loc1->url, source->loc2->url) == 0);
+  svn_client__pathrev_t loc1 = *source->loc1;
+  svn_client__pathrev_t loc2 = *source->loc2;
+
+  loc1.rev = start_rev;
+  loc2.rev = end_rev;
   if (! same_urls)
     {
-      if (is_rollback && (end_rev != source->loc2.rev))
+      if (is_rollback && (end_rev != source->loc2->rev))
         {
-          real_source->loc2.url = source->loc1.url;
+          loc2.url = source->loc1->url;
         }
-      if ((! is_rollback) && (start_rev != source->loc1.rev))
+      if ((! is_rollback) && (start_rev != source->loc1->rev))
         {
-          real_source->loc1.url = source->loc2.url;
+          loc1.url = source->loc2->url;
         }
     }
-  return real_source;
+  return merge_source_create(&loc1, &loc2, pool);
 }
 
 /* The single-file, simplified version of do_directory_merge(), which see for
@@ -6698,8 +6701,8 @@ do_file_merge(svn_mergeinfo_catalog_t re
   svn_mergeinfo_t target_mergeinfo;
   svn_merge_range_t *conflicted_range = NULL;
   svn_boolean_t inherited = FALSE;
-  svn_boolean_t is_rollback = (source->loc1.rev > source->loc2.rev);
-  const char *primary_url = is_rollback ? source->loc1.url : source->loc2.url;
+  svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
+  const char *primary_url = is_rollback ? source->loc1->url : source->loc2->url;
   svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
   svn_client__merge_path_t *merge_target = NULL;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -6709,8 +6712,8 @@ do_file_merge(svn_mergeinfo_catalog_t re
   /* Note that this is a single-file merge. */
   notify_b->is_single_file_merge = TRUE;
 
-  range.start = source->loc1.rev;
-  range.end = source->loc2.rev;
+  range.start = source->loc1->rev;
+  range.end = source->loc2->rev;
   range.inheritable = TRUE;
   if (honor_mergeinfo)
     {
@@ -6723,8 +6726,8 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                &(merge_target->implicit_mergeinfo),
                                &inherited, svn_mergeinfo_inherited,
                                merge_b->ra_session1, target_abspath,
-                               MAX(source->loc1.rev, source->loc2.rev),
-                               MIN(source->loc1.rev, source->loc2.rev),
+                               MAX(source->loc1->rev, source->loc2->rev),
+                               MIN(source->loc1->rev, source->loc2->rev),
                                ctx, scratch_pool, iterpool);
 
       if (err)
@@ -6745,6 +6748,9 @@ do_file_merge(svn_mergeinfo_catalog_t re
          by SOURCE->rev1:rev2. */
       if (!merge_b->record_only)
         {
+          /* ### Bug?  calculate_remaining_ranges() needs 'source' to adhere
+           *   to the requirements of 'MERGEINFO MERGE SOURCE NORMALIZATION'
+           *   here, but it doesn't appear to be guaranteed so. */
           SVN_ERR(calculate_remaining_ranges(NULL, merge_target,
                                              source,
                                              target_mergeinfo,
@@ -6808,13 +6814,13 @@ do_file_merge(svn_mergeinfo_catalog_t re
           real_source = subrange_source(source, r->start, r->end, iterpool);
           SVN_ERR(single_file_merge_get_file(&tmpfile1, &props1,
                                              merge_b->ra_session1,
-                                             real_source->loc1.url,
-                                             real_source->loc1.rev,
+                                             real_source->loc1->url,
+                                             real_source->loc1->rev,
                                              target_abspath, iterpool));
           SVN_ERR(single_file_merge_get_file(&tmpfile2, &props2,
                                              merge_b->ra_session2,
-                                             real_source->loc2.url,
-                                             real_source->loc2.rev,
+                                             real_source->loc2->url,
+                                             real_source->loc2->rev,
                                              target_abspath, iterpool));
 
           /* Discover any svn:mime-type values in the proplists */
@@ -7163,8 +7169,8 @@ do_mergeinfo_unaware_dir_merge(const mer
   svn_client__merge_path_t *item
     = svn_client__merge_path_create(target_dir_wcpath, pool);
 
-  item->remaining_ranges = svn_rangelist__initialize(source->loc1.rev,
-                                                     source->loc2.rev,
+  item->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
+                                                     source->loc2->rev,
                                                      TRUE, pool);
   APR_ARRAY_PUSH(notify_b->children_with_mergeinfo,
                  svn_client__merge_path_t *) = item;
@@ -7640,7 +7646,7 @@ record_mergeinfo_for_dir_merge(svn_merge
 
   svn_merge_range_t range = *merged_range;
 
-  /* Regardless of what subtrees in MERGE_B->TARGET_ABSPATH might be missing
+  /* Regardless of what subtrees in MERGE_B->target->abspath might be missing
      could this merge have been operative? */
   operative_merge = subtree_touched_by_merge(merge_b->target->abspath,
                                              notify_b, iterpool);
@@ -7651,7 +7657,7 @@ record_mergeinfo_for_dir_merge(svn_merge
   if (!operative_merge)
     range.inheritable = TRUE;
 
-  /* Remove absent children at or under TARGET_WCPATH from
+  /* Remove absent children at or under MERGE_B->target->abspath from
      NOTIFY_B->CHILDREN_WITH_MERGEINFO
      before we calculate the merges performed. */
   remove_absent_children(merge_b->target->abspath,
@@ -7775,7 +7781,7 @@ record_mergeinfo_for_dir_merge(svn_merge
               svn_mergeinfo_t subtree_history_as_mergeinfo;
               apr_array_header_t *child_merge_src_rangelist;
               const char *subtree_mergeinfo_url =
-                svn_path_url_add_component2(merge_b->target->loc.repo->url,
+                svn_path_url_add_component2(merge_b->target->loc.repos_root_url,
                                             child_merge_src_fspath + 1,
                                             iterpool);
 
@@ -7950,7 +7956,7 @@ record_mergeinfo_for_added_subtrees(
                         iterpool);
 
           /* Create the new mergeinfo path for added_path's mergeinfo.
-             (added_abspath had better be a child of target_abspath
+             (added_abspath had better be a child of MERGE_B->target->abspath
              or something is *really* wrong.) */
           rel_added_path = svn_dirent_is_child(merge_b->target->abspath,
                                                added_abspath, iterpool);
@@ -7974,7 +7980,7 @@ record_mergeinfo_for_added_subtrees(
              take the intersection of the naive mergeinfo with
              MERGEINFO_PATH/rel_added_path's history. */
           added_path_mergeinfo_url =
-            svn_path_url_add_component2(merge_b->target->loc.repo->url,
+            svn_path_url_add_component2(merge_b->target->loc.repos_root_url,
                                         added_path_mergeinfo_fspath + 1,
                                         iterpool);
           SVN_ERR(svn_client__get_history_as_mergeinfo(
@@ -8014,7 +8020,7 @@ typedef struct log_noop_baton_t
      of this file.*/
   apr_array_header_t *children_with_mergeinfo;
 
-  /* Absolute repository path of MERGE_B->TARGET_ABSPATH. */
+  /* Absolute repository path of MERGE_B->target->abspath. */
   const char *target_fspath;
 
   /* Absolute repository path of younger of the two merge sources
@@ -8075,7 +8081,7 @@ rangelist_merge_revision(apr_array_heade
    Add LOG_ENTRY->REVISION to BATON->OPERATIVE_RANGES.
 
    If LOG_ENTRY->REVISION has already been fully merged to
-   MERGE_B->TARGET_ABSPATH per the mergeinfo in CHILDREN_WITH_MERGEINFO,
+   MERGE_B->target->abspath per the mergeinfo in CHILDREN_WITH_MERGEINFO,
    then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES.
 
    Use SCRATCH_POOL for temporary allocations.  Allocate additions to
@@ -8108,7 +8114,7 @@ log_noop_revs(void *baton,
 
   /* Examine each path affected by LOG_ENTRY->REVISION.  If the explicit or
      inherited mergeinfo for *all* of the corresponding paths under
-     MERGE_B->TARGET_ABSPATH reflects that LOG_ENTRY->REVISION has been
+     MERGE_B->target->abspath reflects that LOG_ENTRY->REVISION has been
      merged, then add LOG_ENTRY->REVISION to BATON->MERGED_RANGES. */
   for (hi = apr_hash_first(scratch_pool, log_entry->changed_paths2);
        hi;
@@ -8204,7 +8210,7 @@ log_noop_revs(void *baton,
 
    Find all the ranges required by subtrees in
    CHILDREN_WITH_MERGEINFO that are *not* required by
-   MERGE_B->TARGET_ABSPATH (i.e. CHILDREN_WITH_MERGEINFO[0]).  If such
+   MERGE_B->target->abspath (i.e. CHILDREN_WITH_MERGEINFO[0]).  If such
    ranges exist, then find any subset of ranges which, if merged, would be
    inoperative.  Finally, if any inoperative ranges are found then remove
    these ranges from all of the subtree's REMAINING_RANGES.
@@ -8236,7 +8242,7 @@ remove_noop_subtree_ranges(const merge_s
 
 
   /* This function is only intended to work with forward merges. */
-  if (source->loc1.rev > source->loc2.rev)
+  if (source->loc1->rev > source->loc2->rev)
     return SVN_NO_ERROR;
 
   /* Another easy out: There are no subtrees. */
@@ -8249,10 +8255,10 @@ remove_noop_subtree_ranges(const merge_s
 
   /* Given the requested merge of SOURCE->rev1:rev2 might there be any
      part of this range required for subtrees but not for the target? */
-  requested_ranges = svn_rangelist__initialize(MIN(source->loc1.rev,
-                                                   source->loc2.rev),
-                                               MAX(source->loc1.rev,
-                                                   source->loc2.rev),
+  requested_ranges = svn_rangelist__initialize(MIN(source->loc1->rev,
+                                                   source->loc2->rev),
+                                               MAX(source->loc1->rev,
+                                                   source->loc2->rev),
                                                TRUE, scratch_pool);
   SVN_ERR(svn_rangelist_remove(&subtree_gap_ranges,
                                root_child->remaining_ranges,
@@ -8306,12 +8312,12 @@ remove_noop_subtree_ranges(const merge_s
   SVN_ERR(svn_client__path_relative_to_root(
                     &(log_gap_baton.target_fspath), merge_b->ctx->wc_ctx,
                     merge_b->target->abspath,
-                    merge_b->target->loc.repo->url, TRUE, NULL,
+                    merge_b->target->loc.repos_root_url, TRUE, NULL,
                     result_pool, scratch_pool));
   SVN_ERR(svn_client__path_relative_to_root(
                     &(log_gap_baton.source_fspath), merge_b->ctx->wc_ctx,
-                    source->loc2.url,
-                    merge_b->target->loc.repo->url, TRUE, NULL,
+                    source->loc2->url,
+                    merge_b->target->loc.repos_root_url, TRUE, NULL,
                     result_pool, scratch_pool));
   log_gap_baton.merged_ranges = apr_array_make(scratch_pool, 0,
                                                sizeof(svn_revnum_t *));
@@ -8428,8 +8434,8 @@ do_directory_merge(svn_mergeinfo_catalog
 
   svn_ra_session_t *ra_session;
   svn_client__merge_path_t *target_merge_path;
-  svn_boolean_t is_rollback = (source->loc1.rev > source->loc2.rev);
-  const char *primary_url = is_rollback ? source->loc1.url : source->loc2.url;
+  svn_boolean_t is_rollback = (source->loc1->rev > source->loc2->rev);
+  const char *primary_url = is_rollback ? source->loc1->url : source->loc2->url;
   svn_boolean_t honor_mergeinfo = HONOR_MERGEINFO(merge_b);
 
   /* Note that this is not a single-file merge. */
@@ -8479,8 +8485,8 @@ do_directory_merge(svn_mergeinfo_catalog
 
   /* Always start with a range which describes the most inclusive merge
      possible, i.e. SOURCE->rev1:rev2. */
-  range.start = source->loc1.rev;
-  range.end = source->loc2.rev;
+  range.start = source->loc1->rev;
+  range.end = source->loc2->rev;
   range.inheritable = TRUE;
 
   if (honor_mergeinfo && !merge_b->reintegrate_merge)
@@ -8926,14 +8932,14 @@ do_merge(apr_hash_t **modified_subtrees,
 
       /* Sanity check:  if our left- and right-side merge sources are
          the same, there's nothing to here. */
-      if ((strcmp(source->loc1.url, source->loc2.url) == 0)
-          && (source->loc1.rev == source->loc2.rev))
+      if ((strcmp(source->loc1->url, source->loc2->url) == 0)
+          && (source->loc1->rev == source->loc2->rev))
         continue;
 
       /* Establish RA sessions to our URLs, reuse where possible. */
-      SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1.url,
+      SVN_ERR(ensure_ra_session_url(&ra_session1, source->loc1->url,
                                     ctx, scratch_pool));
-      SVN_ERR(ensure_ra_session_url(&ra_session2, source->loc2.url,
+      SVN_ERR(ensure_ra_session_url(&ra_session2, source->loc2->url,
                                     ctx, scratch_pool));
 
       /* Populate the portions of the merge context baton that need to
@@ -9070,14 +9076,14 @@ merge_cousins_and_supplement_mergeinfo(c
   SVN_ERR_ASSERT(svn_dirent_is_absolute(target->abspath));
 
   SVN_ERR(normalize_merge_sources_internal(
-            &remove_sources, source->loc1.url, source->loc1.rev,
-            svn_rangelist__initialize(source->loc1.rev, yc_rev, TRUE,
+            &remove_sources, source->loc1,
+            svn_rangelist__initialize(source->loc1->rev, yc_rev, TRUE,
                                       scratch_pool),
             URL1_ra_session, ctx, scratch_pool, subpool));
 
   SVN_ERR(normalize_merge_sources_internal(
-            &add_sources, source->loc2.url, source->loc2.rev,
-            svn_rangelist__initialize(yc_rev, source->loc2.rev, TRUE,
+            &add_sources, source->loc2,
+            svn_rangelist__initialize(yc_rev, source->loc2->rev, TRUE,
                                       scratch_pool),
             URL2_ra_session, ctx, scratch_pool, subpool));
 
@@ -9294,9 +9300,8 @@ open_target_wc(merge_target_t **target_p
   SVN_ERR(svn_wc_read_kind(&target->kind, ctx->wc_ctx, wc_abspath, FALSE,
                            scratch_pool));
 
-  target->loc.repo = apr_palloc(result_pool, sizeof(*target->loc.repo));
-  SVN_ERR(svn_client__wc_node_get_origin(&target->loc.repo->url,
-                                         &target->loc.repo->uuid,
+  SVN_ERR(svn_client__wc_node_get_origin(&target->loc.repos_root_url,
+                                         &target->loc.repos_uuid,
                                          &target->loc.rev, &target->loc.url,
                                          wc_abspath, ctx,
                                          result_pool, scratch_pool));
@@ -9314,7 +9319,7 @@ open_target_wc(merge_target_t **target_p
  * the session and set *LOCATION_P to the resolved revision, URL and
  * repository root.  Allocate the results in RESULT_POOL.  */
 static svn_error_t *
-open_source_session(repo_location_t **location_p,
+open_source_session(svn_client__pathrev_t **location_p,
                     svn_ra_session_t **ra_session_p,
                     const char *path_or_url,
                     const svn_opt_revision_t *peg_revision,
@@ -9322,20 +9327,10 @@ open_source_session(repo_location_t **lo
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
-  repo_location_t *location = apr_palloc(result_pool, sizeof(*location));
-  svn_ra_session_t *ra_session;
-
-  SVN_ERR(svn_client__ra_session_from_path(
-            &ra_session, &location->rev, &location->url,
+  SVN_ERR(svn_client__ra_session_from_path2(
+            ra_session_p, location_p,
             path_or_url, NULL, peg_revision, peg_revision,
             ctx, result_pool));
-  location->repo = apr_palloc(result_pool, sizeof(*location->repo));
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, &location->repo->url,
-                                 result_pool));
-  SVN_ERR(svn_ra_get_uuid2(ra_session, &location->repo->uuid, result_pool));
-
-  *location_p = location;
-  *ra_session_p = ra_session;
   return SVN_NO_ERROR;
 }
 
@@ -9362,15 +9357,13 @@ merge_locked(const char *source1,
              apr_pool_t *scratch_pool)
 {
   merge_target_t *target;
-  repo_location_t *source1_loc, *source2_loc;
-  merge_source_t source;
+  svn_client__pathrev_t *source1_loc, *source2_loc;
   svn_boolean_t related = FALSE, ancestral = FALSE;
   svn_ra_session_t *ra_session1, *ra_session2;
   apr_array_header_t *merge_sources;
   svn_error_t *err;
   svn_boolean_t use_sleep = FALSE;
-  const char *yc_url = NULL;
-  svn_revnum_t yc_rev = SVN_INVALID_REVNUM;
+  svn_client__pathrev_t *yca = NULL;
   apr_pool_t *sesspool;
   svn_boolean_t same_repos;
 
@@ -9388,32 +9381,25 @@ merge_locked(const char *source1,
   sesspool = svn_pool_create(scratch_pool);
   SVN_ERR(open_source_session(&source1_loc, &ra_session1, source1, revision1,
                               ctx, sesspool, scratch_pool));
-  source.loc1 = *source1_loc;
   SVN_ERR(open_source_session(&source2_loc, &ra_session2, source2, revision2,
                               ctx, sesspool, scratch_pool));
-  source.loc2 = *source2_loc;
 
   /* We can't do a diff between different repositories. */
   /* ### We should also insist that the root URLs of the two sources match,
    *     as we are only carrying around a single source-repos-root from now
    *     on, and URL calculations will go wrong if they differ.
    *     Alternatively, teach the code to cope with differing root URLs. */
-  SVN_ERR(check_same_repos(source1_loc->repo, source.loc1.url,
-                           source2_loc->repo, source.loc2.url,
+  SVN_ERR(check_same_repos(source1_loc, source1_loc->url,
+                           source2_loc, source2_loc->url,
                            FALSE /* strict_urls */, scratch_pool));
 
   /* Do our working copy and sources come from the same repository? */
-  same_repos = is_same_repos(target->loc.repo, source1_loc->repo,
-                             TRUE /* strict_urls */);
+  same_repos = is_same_repos(&target->loc, source1_loc, TRUE /* strict_urls */);
 
   /* Unless we're ignoring ancestry, see if the two sources are related.  */
   if (! ignore_ancestry)
-    SVN_ERR(svn_client__get_youngest_common_ancestor(NULL, &yc_url, &yc_rev,
-                                                     source.loc1.url,
-                                                     source.loc1.rev,
-                                                     source.loc2.url,
-                                                     source.loc2.rev,
-                                                     ctx, scratch_pool));
+    SVN_ERR(svn_client__get_youngest_common_ancestor(
+              &yca, source1_loc, source2_loc, ctx, scratch_pool, scratch_pool));
 
   /* Check for a youngest common ancestor.  If we have one, we'll be
      doing merge tracking.
@@ -9432,32 +9418,32 @@ merge_locked(const char *source1,
                       merge recording, then record-only two merges:
                       from A to C, and from C to B
   */
-  if (yc_url && SVN_IS_VALID_REVNUM(yc_rev))
+  if (yca)
     {
       /* Note that our merge sources are related. */
       related = TRUE;
 
       /* If the common ancestor matches the right side of our merge,
          then we only need to reverse-merge the left side. */
-      if ((strcmp(yc_url, source.loc2.url) == 0)
-          && (yc_rev == source.loc2.rev))
+      if ((strcmp(yca->url, source2_loc->url) == 0)
+          && (yca->rev == source2_loc->rev))
         {
           ancestral = TRUE;
           SVN_ERR(normalize_merge_sources_internal(
-                    &merge_sources, source.loc1.url, source.loc1.rev,
-                    svn_rangelist__initialize(source.loc1.rev, yc_rev, TRUE,
+                    &merge_sources, source1_loc,
+                    svn_rangelist__initialize(source1_loc->rev, yca->rev, TRUE,
                                               scratch_pool),
                     ra_session1, ctx, scratch_pool, scratch_pool));
         }
       /* If the common ancestor matches the left side of our merge,
          then we only need to merge the right side. */
-      else if ((strcmp(yc_url, source.loc1.url) == 0)
-               && (yc_rev == source.loc1.rev))
+      else if ((strcmp(yca->url, source1_loc->url) == 0)
+               && (yca->rev == source1_loc->rev))
         {
           ancestral = TRUE;
           SVN_ERR(normalize_merge_sources_internal(
-                    &merge_sources, source.loc2.url, source.loc2.rev,
-                    svn_rangelist__initialize(yc_rev, source.loc2.rev, TRUE,
+                    &merge_sources, source2_loc,
+                    svn_rangelist__initialize(yca->rev, source2_loc->rev, TRUE,
                                               scratch_pool),
                     ra_session2, ctx, scratch_pool, scratch_pool));
         }
@@ -9465,11 +9451,13 @@ merge_locked(const char *source1,
          side, and merge the right. */
       else
         {
+          merge_source_t source = { source1_loc, source2_loc };
+
           err = merge_cousins_and_supplement_mergeinfo(target,
                                                        ra_session1,
                                                        ra_session2,
                                                        &source,
-                                                       yc_rev,
+                                                       yca->rev,
                                                        same_repos,
                                                        depth,
                                                        ignore_ancestry, force,
@@ -9495,6 +9483,8 @@ merge_locked(const char *source1,
     }
   else
     {
+      merge_source_t source = { source1_loc, source2_loc };
+
       /* Build a single-item merge_source_t array. */
       merge_sources = apr_array_make(scratch_pool, 1, sizeof(merge_source_t *));
       APR_ARRAY_PUSH(merge_sources, merge_source_t *) = &source;
@@ -9793,24 +9783,24 @@ log_find_operative_revs(void *baton,
   return SVN_NO_ERROR;
 }
 
-/* Determine if the mergeinfo on a reintegrate source SOURCE_REPOS_REL_PATH,
+/* Determine if the mergeinfo on a reintegrate source SOURCE_LOC,
    reflects that the source is fully synced with the reintegrate target
-   TARGET_REPOS_REL_PATH, even if a naive interpretation of the source's
+   TARGET_LOC, even if a naive interpretation of the source's
    mergeinfo says otherwise -- See issue #3577.
 
    UNMERGED_CATALOG represents the history (as mergeinfo) from
-   TARGET_REPOS_REL_PATH that is not represented in SOURCE_REPOS_REL_PATH's
+   TARGET_LOC that is not represented in SOURCE_LOC's
    explicit/inherited mergeinfo as represented by MERGED_CATALOG.
    MERGEINFO_CATALOG may be empty if the source has no explicit or inherited
    mergeinfo.
 
-   Using RA_SESSION, which is pointed at TARGET_REPOS_REL_PATH, check that all
+   Using RA_SESSION, which is pointed at TARGET_LOC, check that all
    of the unmerged revisions in UNMERGED_CATALOG's mergeinfos are "phantoms",
    that is, one of the following conditions holds:
 
-     1) The revision affects no corresponding paths in SOURCE_REPOS_REL_PATH.
+     1) The revision affects no corresponding paths in SOURCE_LOC.
 
-     2) The revision affects corresponding paths in SOURCE_REPOS_REL_PATH,
+     2) The revision affects corresponding paths in SOURCE_LOC,
         but based on the mergeinfo in MERGED_CATALOG, the change was
         previously merged.
 
@@ -9822,8 +9812,8 @@ log_find_operative_revs(void *baton,
 
    Use SCRATCH_POOL for all temporary allocations. */
 static svn_error_t *
-find_unsynced_ranges(const char *source_repos_rel_path,
-                     const char *target_repos_rel_path,
+find_unsynced_ranges(const svn_client__pathrev_t *source_loc,
+                     const svn_client__pathrev_t *target_loc,
                      svn_mergeinfo_catalog_t unmerged_catalog,
                      svn_mergeinfo_catalog_t merged_catalog,
                      svn_mergeinfo_catalog_t true_unmerged_catalog,
@@ -9857,6 +9847,10 @@ find_unsynced_ranges(const char *source_
      are not yet merged to it. */
   if (potentially_unmerged_ranges)
     {
+      const char *source_repos_rel_path
+        = svn_client__pathrev_relpath(source_loc, scratch_pool);
+      const char *target_repos_rel_path
+        = svn_client__pathrev_relpath(target_loc, scratch_pool);
       svn_revnum_t oldest_rev =
         (APR_ARRAY_IDX(potentially_unmerged_ranges,
                        0,
@@ -9931,6 +9925,10 @@ find_youngest_merged_rev(svn_revnum_t *y
  * branch SOURCE_URL@SOURCE_REV.  Extend SOURCE_MERGEINFO, modifying it in
  * place, to include the natural history (implicit mergeinfo) of
  * SOURCE_URL@SOURCE_REV.  ### But make these additions in SCRATCH_POOL.
+ *
+ * ### [JAF] This function is named '..._subroutine' simply because I
+ *     factored it out based on code similarity, without knowing what it's
+ *     purpose is.  We should clarify its purpose and choose a better name.
  */
 static svn_error_t *
 find_unmerged_mergeinfo_subroutine(svn_mergeinfo_t *filtered_mergeinfo_p,
@@ -10232,7 +10230,7 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
 /* Helper for svn_client_merge_reintegrate() which calculates the
    'left hand side' of the underlying two-URL merge that a --reintegrate
    merge actually performs.  If no merge should be performed, set
-   *URL_LEFT to NULL and *REV_LEFT to SVN_INVALID_REVNUM.
+   *LEFT_P to NULL.
 
    TARGET->abspath is the absolute working copy path of the reintegrate
    merge.
@@ -10255,17 +10253,16 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
    SOURCE_RA_SESSION is a session opened to the SOURCE_LOC
    and TARGET_RA_SESSION is open to TARGET->loc.url.
 
-   *URL_LEFT, *MERGED_TO_SOURCE_CATALOG , and *UNMERGED_TO_SOURCE_CATALOG are
+   *LEFT_P, *MERGED_TO_SOURCE_CATALOG , and *UNMERGED_TO_SOURCE_CATALOG are
    allocated in RESULT_POOL.  SCRATCH_POOL is used for all temporary
    allocations. */
 static svn_error_t *
-calculate_left_hand_side(const char **url_left,
-                         svn_revnum_t *rev_left,
-                         svn_mergeinfo_t *merged_to_source_catalog,
-                         svn_mergeinfo_t *unmerged_to_source_catalog,
+calculate_left_hand_side(svn_client__pathrev_t **left_p,
+                         svn_mergeinfo_catalog_t *merged_to_source_catalog,
+                         svn_mergeinfo_catalog_t *unmerged_to_source_catalog,
                          const merge_target_t *target,
                          apr_hash_t *subtrees_with_mergeinfo,
-                         const repo_location_t *source_loc,
+                         const svn_client__pathrev_t *source_loc,
                          svn_ra_session_t *source_ra_session,
                          svn_ra_session_t *target_ra_session,
                          svn_client_ctx_t *ctx,
@@ -10280,24 +10277,22 @@ calculate_left_hand_side(const char **ur
   /* hash of paths mapped to arrays of svn_mergeinfo_t. */
   apr_hash_t *target_history_hash = apr_hash_make(scratch_pool);
   svn_revnum_t youngest_merged_rev;
-  const char *yc_ancestor_url;
-  svn_revnum_t yc_ancestor_rev;
+  svn_client__pathrev_t *yc_ancestor;
   const char *source_repos_rel_path;
 
   /* Initialize our return variables. */
-  *url_left = NULL;
-  *rev_left = SVN_INVALID_REVNUM;
+  *left_p = NULL;
 
-  /* TARGET_ABSPATH may not have explicit mergeinfo and thus may not be
+  /* TARGET->abspath may not have explicit mergeinfo and thus may not be
      contained within SUBTREES_WITH_MERGEINFO.  If this is the case then
-     add a dummy item for TARGET_ABSPATH so we get its history (i.e. implicit
+     add a dummy item for TARGET->abspath so we get its history (i.e. implicit
      mergeinfo) below.  */
   if (!apr_hash_get(subtrees_with_mergeinfo, target->abspath,
                     APR_HASH_KEY_STRING))
     apr_hash_set(subtrees_with_mergeinfo, target->abspath,
                  APR_HASH_KEY_STRING, apr_hash_make(result_pool));
 
-  /* Get the history segments (as mergeinfo) for TARGET_ABSPATH and any of
+  /* Get the history segments (as mergeinfo) for TARGET->abspath and any of
      its subtrees with explicit mergeinfo. */
   for (hi = apr_hash_first(scratch_pool, subtrees_with_mergeinfo);
        hi;
@@ -10317,7 +10312,7 @@ calculate_left_hand_side(const char **ur
                                                 NULL, FALSE,
                                                 NULL, scratch_pool,
                                                 iterpool));
-      url = svn_path_url_add_component2(target->loc.repo->url,
+      url = svn_path_url_add_component2(target->loc.repos_root_url,
                                         path_rel_to_root, iterpool);
       SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history_as_mergeinfo,
                                                    NULL /* has_rev_zero_hist */,
@@ -10332,15 +10327,12 @@ calculate_left_hand_side(const char **ur
                    APR_HASH_KEY_STRING, target_history_as_mergeinfo);
     }
 
-  /* Check that SOURCE_URL@SOURCE_REV and TARGET_URL@TARGET_REV are
+  /* Check that SOURCE_LOC and TARGET->loc are
      actually related, we can't reintegrate if they are not.  Also
-     get an initial value for YC_ANCESTOR_REV. */
-  SVN_ERR(svn_client__get_youngest_common_ancestor(NULL, &yc_ancestor_url,
-                                                   &yc_ancestor_rev,
-                                                   source_loc->url, source_loc->rev,
-                                                   target->loc.url, target->loc.rev,
-                                                   ctx, iterpool));
-  if (!(yc_ancestor_url && SVN_IS_VALID_REVNUM(yc_ancestor_rev)))
+     get an initial value for the YCA revision number. */
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            &yc_ancestor, source_loc, &target->loc, ctx, iterpool, iterpool));
+  if (! yc_ancestor)
     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
                              _("'%s@%ld' must be ancestrally related to "
                                "'%s@%ld'"), source_loc->url, source_loc->rev,
@@ -10349,7 +10341,7 @@ calculate_left_hand_side(const char **ur
   /* If the source revision is the same as the youngest common
      revision, then there can't possibly be any unmerged revisions
      that we need to apply to target. */
-  if (source_loc->rev == yc_ancestor_rev)
+  if (source_loc->rev == yc_ancestor->rev)
     {
       svn_pool_destroy(iterpool);
       return SVN_NO_ERROR;
@@ -10363,8 +10355,7 @@ calculate_left_hand_side(const char **ur
                                svn_mergeinfo_inherited,
                                TRUE, iterpool));
 
-  source_repos_rel_path = svn_uri_skip_ancestor(source_loc->repo->url,
-                                                source_loc->url, scratch_pool);
+  source_repos_rel_path = svn_client__pathrev_relpath(source_loc, scratch_pool);
   if (mergeinfo_catalog)
     SVN_ERR(svn_mergeinfo__add_prefix_to_catalog(&mergeinfo_catalog,
                                                  mergeinfo_catalog,
@@ -10382,7 +10373,7 @@ calculate_left_hand_side(const char **ur
      TARGET_REPOS_REL_PATH@TARGET_REV to SOURCE_REPOS_REL_PATH@SOURCE_REV. */
   SVN_ERR(find_unmerged_mergeinfo(&unmerged_catalog,
                                   &youngest_merged_rev,
-                                  yc_ancestor_rev,
+                                  yc_ancestor->rev,
                                   mergeinfo_catalog,
                                   target_history_hash,
                                   source_repos_rel_path,
@@ -10402,18 +10393,15 @@ calculate_left_hand_side(const char **ur
   if (youngest_merged_rev == SVN_INVALID_REVNUM)
     {
       /* We never merged to the source.  Just return the branch point. */
-      *url_left = apr_pstrdup(result_pool, yc_ancestor_url);
-      *rev_left = yc_ancestor_rev;
+      *left_p = svn_client__pathrev_dup(yc_ancestor, result_pool);
     }
   else
     {
       /* We've previously merged some or all of the target, up to
-         youngest_merged_rev, from TARGET_ABSPATH to the source.  Set
-         *URL_LEFT and *REV_LEFT to cover the youngest part of this range. */
-      *rev_left = youngest_merged_rev;
-      SVN_ERR(svn_client__repos_location(url_left, target_ra_session,
-                                         target->loc.url, target->loc.rev,
-                                         youngest_merged_rev,
+         youngest_merged_rev, to the source.  Set
+         *LEFT_P to cover the youngest part of this range. */
+      SVN_ERR(svn_client__repos_location(left_p, target_ra_session,
+                                         &target->loc, youngest_merged_rev,
                                          ctx, result_pool, iterpool));
     }
 
@@ -10430,27 +10418,27 @@ calculate_left_hand_side(const char **ur
  *
  * Set *SOURCE_P to
  * the source-left and source-right locations of the required merge.  Set
- * *YC_ANCESTOR_REV_P to the revision number of the youngest ancestor.
+ * *YC_ANCESTOR_P to the location of the youngest ancestor.
  * Any of these output pointers may be NULL if not wanted.
  *
  * See svn_client_find_reintegrate_merge() for other details.
  */
 static svn_error_t *
 find_reintegrate_merge(merge_source_t **source_p,
-                       svn_revnum_t *yc_ancestor_rev_p,
+                       svn_client__pathrev_t **yc_ancestor_p,
                        svn_ra_session_t *source_ra_session,
-                       const repo_location_t *source_loc,
+                       const svn_client__pathrev_t *source_loc,
                        svn_ra_session_t *target_ra_session,
                        const merge_target_t *target,
                        svn_client_ctx_t *ctx,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
-  const char *yc_ancestor_relpath;
-  svn_revnum_t yc_ancestor_rev;
+  svn_client__pathrev_t *yc_ancestor;
+  svn_client__pathrev_t *loc1;
   merge_source_t source;
-  svn_mergeinfo_t unmerged_to_source_mergeinfo_catalog;
-  svn_mergeinfo_t merged_to_source_mergeinfo_catalog;
+  svn_mergeinfo_catalog_t unmerged_to_source_mergeinfo_catalog;
+  svn_mergeinfo_catalog_t merged_to_source_mergeinfo_catalog;
   svn_error_t *err;
   apr_hash_t *subtrees_with_mergeinfo;
 
@@ -10461,8 +10449,8 @@ find_reintegrate_merge(merge_source_t **
   /* ### Bogus/obsolete comment? */
 
   /* Can't reintegrate to or from the root of the repository. */
-  if (strcmp(source_loc->url, source_loc->repo->url) == 0
-      || strcmp(target->loc.url, target->loc.repo->url) == 0)
+  if (strcmp(source_loc->url, source_loc->repos_root_url) == 0
+      || strcmp(target->loc.url, target->loc.repos_root_url) == 0)
     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
                              _("Neither the reintegrate source nor target "
                                "can be the root of the repository"));
@@ -10477,7 +10465,7 @@ find_reintegrate_merge(merge_source_t **
     err = svn_error_quick_wrap(err, _("Reintegrate merge not possible"));
   SVN_ERR(err);
 
-  SVN_ERR(calculate_left_hand_side(&source.loc1.url, &source.loc1.rev,
+  SVN_ERR(calculate_left_hand_side(&loc1,
                                    &merged_to_source_mergeinfo_catalog,
                                    &unmerged_to_source_mergeinfo_catalog,
                                    target,
@@ -10486,54 +10474,47 @@ find_reintegrate_merge(merge_source_t **
                                    source_ra_session,
                                    target_ra_session,
                                    ctx,
-                                   result_pool, scratch_pool));
+                                   scratch_pool, scratch_pool));
 
   /* Did calculate_left_hand_side() decide that there was no merge to
      be performed here?  */
-  if (! source.loc1.url)
+  if (! loc1)
     {
       if (source_p)
         *source_p = NULL;
-      if (yc_ancestor_rev_p)
-        *yc_ancestor_rev_p = SVN_INVALID_REVNUM;
+      if (yc_ancestor_p)
+        *yc_ancestor_p = NULL;
       return SVN_NO_ERROR;
     }
 
-  source.loc2 = *source_loc;
+  source.loc1 = loc1;
+  source.loc2 = source_loc;
 
   /* If the target was moved after the source was branched from it,
      it is possible that the left URL differs from the target's current
      URL.  If so, then adjust TARGET_RA_SESSION to point to the old URL. */
-  if (strcmp(source.loc1.url, target->loc.url))
-    SVN_ERR(svn_ra_reparent(target_ra_session, source.loc1.url, scratch_pool));
+  if (strcmp(source.loc1->url, target->loc.url))
+    SVN_ERR(svn_ra_reparent(target_ra_session, source.loc1->url, scratch_pool));
 
-  SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_ancestor_relpath, NULL,
-                                                   &yc_ancestor_rev,
-                                                   source.loc2.url,
-                                                   source.loc2.rev,
-                                                   source.loc1.url,
-                                                   source.loc1.rev,
-                                                   ctx, scratch_pool));
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            &yc_ancestor, source.loc2, source.loc1,
+            ctx, scratch_pool, scratch_pool));
 
-  if (!(yc_ancestor_relpath && SVN_IS_VALID_REVNUM(yc_ancestor_rev)))
+  if (! yc_ancestor)
     return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE, NULL,
                              _("'%s@%ld' must be ancestrally related to "
                                "'%s@%ld'"),
-                             source.loc1.url, source.loc1.rev,
-                             source.loc2.url, source.loc2.rev);
+                             source.loc1->url, source.loc1->rev,
+                             source.loc2->url, source.loc2->rev);
 
-  if (source.loc1.rev > yc_ancestor_rev)
+  if (source.loc1->rev > yc_ancestor->rev)
     {
       /* Have we actually merged anything to the source from the
          target?  If so, make sure we've merged a contiguous
          prefix. */
       svn_mergeinfo_t final_unmerged_catalog = apr_hash_make(scratch_pool);
-      const char *source_repos_rel_path
-        = svn_uri_skip_ancestor(source_loc->repo->url, source_loc->url,
-                                scratch_pool);
 
-      SVN_ERR(find_unsynced_ranges(source_repos_rel_path,
-                                   yc_ancestor_relpath,
+      SVN_ERR(find_unsynced_ranges(source_loc, yc_ancestor,
                                    unmerged_to_source_mergeinfo_catalog,
                                    merged_to_source_mergeinfo_catalog,
                                    final_unmerged_catalog,
@@ -10555,7 +10536,7 @@ find_reintegrate_merge(merge_source_t **
                                      "previously merged from %s to the "
                                      "reintegrate source, but this is "
                                      "not the case:\n%s"),
-                                   yc_ancestor_rev + 1, source.loc2.rev,
+                                   yc_ancestor->rev + 1, source.loc2->rev,
                                    target->loc.url,
                                    source_mergeinfo_cat_string->data);
         }
@@ -10564,9 +10545,10 @@ find_reintegrate_merge(merge_source_t **
   /* Left side: trunk@youngest-trunk-rev-merged-to-branch-at-specified-peg-rev
    * Right side: branch@specified-peg-revision */
   if (source_p)
-    *source_p = apr_pmemdup(result_pool, &source, sizeof(source));
-  if (yc_ancestor_rev_p)
-    *yc_ancestor_rev_p = yc_ancestor_rev;
+    *source_p = merge_source_dup(&source, result_pool);
+
+  if (yc_ancestor_p)
+    *yc_ancestor_p = svn_client__pathrev_dup(yc_ancestor, result_pool);
   return SVN_NO_ERROR;
 }
 
@@ -10588,7 +10570,7 @@ find_reintegrate_merge(merge_source_t **
  */
 static svn_error_t *
 open_reintegrate_source_and_target(svn_ra_session_t **source_ra_session_p,
-                                   repo_location_t **source_loc_p,
+                                   svn_client__pathrev_t **source_loc_p,
                                    svn_ra_session_t **target_ra_session_p,
                                    merge_target_t **target_p,
                                    const char *source_path_or_url,
@@ -10598,7 +10580,7 @@ open_reintegrate_source_and_target(svn_r
                                    apr_pool_t *result_pool,
                                    apr_pool_t *scratch_pool)
 {
-  repo_location_t *source_loc;
+  svn_client__pathrev_t *source_loc;
   merge_target_t *target;
 
   /* Open the target WC.  A reintegrate merge requires the merge target to
@@ -10622,12 +10604,12 @@ open_reintegrate_source_and_target(svn_r
                               source_path_or_url, source_peg_revision,
                               ctx, result_pool, scratch_pool));
 
-  /* source_loc->repo and target->loc.repo are required to be the same,
+  /* source_loc and target->loc are required to be in the same repository,
      as mergeinfo doesn't come into play for cross-repository merging. */
-  SVN_ERR(check_same_repos(source_loc->repo,
+  SVN_ERR(check_same_repos(source_loc,
                            svn_dirent_local_style(source_path_or_url,
                                                   scratch_pool),
-                           target->loc.repo,
+                           &target->loc,
                            svn_dirent_local_style(target->abspath,
                                                   scratch_pool),
                            TRUE /* strict_urls */, scratch_pool));
@@ -10651,7 +10633,7 @@ svn_client_find_reintegrate_merge(const 
 {
   const char *target_abspath;
   svn_ra_session_t *source_ra_session;
-  repo_location_t *source_loc;
+  svn_client__pathrev_t *source_loc;
   svn_ra_session_t *target_ra_session;
   merge_target_t *target;
   merge_source_t *source;
@@ -10670,10 +10652,10 @@ svn_client_find_reintegrate_merge(const 
                                  ctx, result_pool, scratch_pool));
   if (source)
     {
-      *url1_p = source->loc1.url;
-      *rev1_p = source->loc1.rev;
-      *url2_p = source->loc2.url;
-      *rev2_p = source->loc2.rev;
+      *url1_p = source->loc1->url;
+      *rev1_p = source->loc1->rev;
+      *url2_p = source->loc2->url;
+      *rev2_p = source->loc2->rev;
     }
   else
     {
@@ -10697,9 +10679,9 @@ merge_reintegrate_locked(const char *sou
 {
   svn_ra_session_t *target_ra_session, *source_ra_session;
   merge_target_t *target;
-  repo_location_t *source_loc;
+  svn_client__pathrev_t *source_loc;
   merge_source_t *source;
-  svn_revnum_t yc_ancestor_rev;
+  svn_client__pathrev_t *yc_ancestor;
   svn_boolean_t use_sleep;
   svn_error_t *err;
 
@@ -10708,7 +10690,7 @@ merge_reintegrate_locked(const char *sou
             source_path_or_url, source_peg_revision, target_abspath,
             ctx, scratch_pool, scratch_pool));
 
-  SVN_ERR(find_reintegrate_merge(&source, &yc_ancestor_rev,
+  SVN_ERR(find_reintegrate_merge(&source, &yc_ancestor,
                                  source_ra_session, source_loc,
                                  target_ra_session, target,
                                  ctx, scratch_pool, scratch_pool));
@@ -10726,7 +10708,7 @@ merge_reintegrate_locked(const char *sou
   err = merge_cousins_and_supplement_mergeinfo(target,
                                                target_ra_session,
                                                source_ra_session,
-                                               source, yc_ancestor_rev,
+                                               source, yc_ancestor->rev,
                                                TRUE /* same_repos */,
                                                svn_depth_infinity,
                                                FALSE /* ignore_ancestry */,
@@ -10790,7 +10772,7 @@ merge_peg_locked(const char *source_path
                  apr_pool_t *scratch_pool)
 {
   merge_target_t *target;
-  repo_location_t *source_loc;
+  svn_client__pathrev_t *source_loc;
   apr_array_header_t *merge_sources;
   svn_ra_session_t *ra_session;
   apr_pool_t *sesspool;
@@ -10812,13 +10794,12 @@ merge_peg_locked(const char *source_path
 

[... 222 lines stripped ...]


Mime
View raw message