You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2012/05/11 02:05:43 UTC

svn commit: r1336974 [2/4] - in /subversion/branches/ev2-export: ./ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/lib...

Modified: subversion/branches/ev2-export/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/merge.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/merge.c Fri May 11 00:05:41 2012
@@ -866,7 +866,8 @@ filter_self_referential_mergeinfo(apr_ar
   apr_array_header_t *adjusted_props;
   int i;
   apr_pool_t *iterpool;
-  svn_boolean_t is_added;
+  svn_boolean_t is_copy;
+  const char *repos_relpath;
   svn_client__pathrev_t target_base;
 
   /* Issue #3383: We don't want mergeinfo from a foreign repos.
@@ -891,17 +892,17 @@ filter_self_referential_mergeinfo(apr_ar
 
   /* If this is a merge from the same repository and PATH itself has been
      added there is no need to filter. */
-  SVN_ERR(svn_wc__node_is_added(&is_added, ctx->wc_ctx, target_abspath, pool));
-  if (is_added)
-    return SVN_NO_ERROR;
+  SVN_ERR(svn_wc__node_get_origin(&is_copy,  &target_base.rev, &repos_relpath,
+                                  &target_base.repos_root_url,
+                                  &target_base.repos_uuid, NULL,
+                                  ctx->wc_ctx, target_abspath, FALSE,
+                                  pool, pool));
+
+  if (is_copy || !repos_relpath)
+    return SVN_NO_ERROR; /* A copy or a local addition */
 
-  SVN_ERR(svn_wc__node_get_url(&target_base.url, ctx->wc_ctx, target_abspath,
-                               pool, pool));
-  SVN_ERR(svn_wc__node_get_base(&target_base.rev, NULL, NULL, NULL,
-                                ctx->wc_ctx, target_abspath, pool, 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));
+  target_base.url = svn_path_url_add_component2(target_base.repos_root_url,
+                                                repos_relpath, pool);
 
   adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
   iterpool = svn_pool_create(pool);
@@ -1131,31 +1132,33 @@ filter_self_referential_mergeinfo(apr_ar
   return SVN_NO_ERROR;
 }
 
-/* Used for both file and directory property merges. */
+/* Prepare a set of property changes PROPCHANGES to be used for a merge
+   operation on LOCAL_ABSPATH. Store the result in *PROP_UPDATES.
+
+   Store information on where mergeinfo is updated in MERGE_B.
+
+   Used for both file and directory property merges. */
 static svn_error_t *
-merge_props_changed(svn_wc_notify_state_t *state,
-                    svn_boolean_t *tree_conflicted,
-                    const char *local_abspath,
-                    const apr_array_header_t *propchanges,
-                    apr_hash_t *original_props,
-                    void *baton,
-                    apr_pool_t *scratch_pool)
+prepare_merge_props_changed(const apr_array_header_t **prop_updates,
+                            const char *local_abspath,
+                            const apr_array_header_t *propchanges,
+                            merge_cmd_baton_t *merge_b,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool)
 {
   apr_array_header_t *props;
-  merge_cmd_baton_t *merge_b = baton;
-  svn_client_ctx_t *ctx = merge_b->ctx;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   SVN_ERR(svn_categorize_props(propchanges, NULL, NULL, &props,
-                               scratch_pool));
+                               result_pool));
 
   /* If we are only applying mergeinfo changes then we need to do
      additional filtering of PROPS so it contains only mergeinfo changes. */
   if (merge_b->record_only && props->nelts)
     {
       apr_array_header_t *mergeinfo_props =
-        apr_array_make(scratch_pool, 1, sizeof(svn_prop_t));
+        apr_array_make(result_pool, 1, sizeof(svn_prop_t));
       int i;
 
       for (i = 0; i < props->nelts; i++)
@@ -1175,8 +1178,6 @@ merge_props_changed(svn_wc_notify_state_
      definition, 'svn merge' shouldn't touch any data within .svn/  */
   if (props->nelts)
     {
-      svn_error_t *err;
-
       /* If this is a forward merge then don't add new mergeinfo to
          PATH that is already part of PATH's own history, see
          http://svn.haxx.se/dev/archive-2008-09/0006.shtml.  If the
@@ -1191,88 +1192,67 @@ merge_props_changed(svn_wc_notify_state_
                                                   merge_b->reintegrate_merge,
                                                   merge_b->ra_session2,
                                                   merge_b->ctx,
-                                                  scratch_pool));
+                                                  result_pool));
+    }
+  *prop_updates = props;
 
-      err = svn_wc_merge_props3(state, ctx->wc_ctx, local_abspath, NULL, NULL,
-                                original_props, props, merge_b->dry_run,
-                                ctx->conflict_func2, ctx->conflict_baton2,
-                                ctx->cancel_func, ctx->cancel_baton,
-                                scratch_pool);
+  /* If this is not a dry run then make a record in BATON if we find a
+     PATH where mergeinfo is added where none existed previously or PATH
+     is having its existing mergeinfo deleted. */
+  if (!merge_b->dry_run && props->nelts)
+    {
+      int i;
 
-      /* If this is not a dry run then make a record in BATON if we find a
-         PATH where mergeinfo is added where none existed previously or PATH
-         is having its existing mergeinfo deleted. */
-      if (!merge_b->dry_run)
+      for (i = 0; i < props->nelts; ++i)
         {
-          int i;
+          svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
 
-          for (i = 0; i < props->nelts; ++i)
+          if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0)
             {
-              svn_prop_t *prop = &APR_ARRAY_IDX(props, i, svn_prop_t);
-
-              if (strcmp(prop->name, SVN_PROP_MERGEINFO) == 0)
-                {
-                  /* Does LOCAL_ABSPATH have any pristine mergeinfo? */
-                  svn_boolean_t has_pristine_mergeinfo = FALSE;
-                  apr_hash_t *pristine_props;
-
-                  SVN_ERR(svn_wc_get_pristine_props(&pristine_props,
-                                                    ctx->wc_ctx,
-                                                    local_abspath,
-                                                    scratch_pool,
-                                                    scratch_pool));
+              /* Does LOCAL_ABSPATH have any pristine mergeinfo? */
+              svn_boolean_t has_pristine_mergeinfo = FALSE;
+              apr_hash_t *pristine_props;
+
+              SVN_ERR(svn_wc_get_pristine_props(&pristine_props,
+                                                merge_b->ctx->wc_ctx,
+                                                local_abspath,
+                                                scratch_pool,
+                                                scratch_pool));
 
-                  if (pristine_props
-                      && apr_hash_get(pristine_props, SVN_PROP_MERGEINFO,
-                                      APR_HASH_KEY_STRING))
-                    has_pristine_mergeinfo = TRUE;
+              if (pristine_props
+                  && apr_hash_get(pristine_props, SVN_PROP_MERGEINFO,
+                                  APR_HASH_KEY_STRING))
+                has_pristine_mergeinfo = TRUE;
 
-                  if (!has_pristine_mergeinfo && prop->value)
-                    {
-                      /* If BATON->PATHS_WITH_NEW_MERGEINFO needs to be
-                         allocated do so in BATON->POOL so it has a
-                         sufficient lifetime. */
-                      if (!merge_b->paths_with_new_mergeinfo)
-                        merge_b->paths_with_new_mergeinfo =
-                          apr_hash_make(merge_b->pool);
-
-                      apr_hash_set(merge_b->paths_with_new_mergeinfo,
-                                   apr_pstrdup(merge_b->pool, local_abspath),
-                                   APR_HASH_KEY_STRING, local_abspath);
-                    }
-                  else if (has_pristine_mergeinfo && !prop->value)
-                    {
-                      /* If BATON->PATHS_WITH_DELETED_MERGEINFO needs to be
-                         allocated do so in BATON->POOL so it has a
-                         sufficient lifetime. */
-                      if (!merge_b->paths_with_deleted_mergeinfo)
-                        merge_b->paths_with_deleted_mergeinfo =
-                          apr_hash_make(merge_b->pool);
-
-                      apr_hash_set(merge_b->paths_with_deleted_mergeinfo,
-                                   apr_pstrdup(merge_b->pool, local_abspath),
-                                   APR_HASH_KEY_STRING, local_abspath);
-                    }
+              if (!has_pristine_mergeinfo && prop->value)
+                {
+                  /* If BATON->PATHS_WITH_NEW_MERGEINFO needs to be
+                     allocated do so in BATON->POOL so it has a
+                     sufficient lifetime. */
+                  if (!merge_b->paths_with_new_mergeinfo)
+                    merge_b->paths_with_new_mergeinfo =
+                      apr_hash_make(merge_b->pool);
+
+                  apr_hash_set(merge_b->paths_with_new_mergeinfo,
+                               apr_pstrdup(merge_b->pool, local_abspath),
+                               APR_HASH_KEY_STRING, local_abspath);
+                }
+              else if (has_pristine_mergeinfo && !prop->value)
+                {
+                  /* If BATON->PATHS_WITH_DELETED_MERGEINFO needs to be
+                     allocated do so in BATON->POOL so it has a
+                     sufficient lifetime. */
+                  if (!merge_b->paths_with_deleted_mergeinfo)
+                    merge_b->paths_with_deleted_mergeinfo =
+                      apr_hash_make(merge_b->pool);
+
+                  apr_hash_set(merge_b->paths_with_deleted_mergeinfo,
+                               apr_pstrdup(merge_b->pool, local_abspath),
+                               APR_HASH_KEY_STRING, local_abspath);
                 }
             }
         }
-
-      if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND
-                  || err->apr_err == SVN_ERR_WC_PATH_UNEXPECTED_STATUS))
-        {
-          /* If the entry doesn't exist in the wc, this is a tree-conflict. */
-          if (state)
-            *state = svn_wc_notify_state_missing;
-          if (tree_conflicted)
-            *tree_conflicted = TRUE;
-          svn_error_clear(err);
-          return SVN_NO_ERROR;
-        }
-      else if (err)
-        return svn_error_trace(err);
     }
-  else if (state)
-    *state = svn_wc_notify_state_unchanged;
 
   return SVN_NO_ERROR;
 }
@@ -1289,12 +1269,15 @@ merge_dir_props_changed(svn_wc_notify_st
                         apr_pool_t *scratch_pool)
 {
   merge_cmd_baton_t *merge_b = diff_baton;
+  const apr_array_header_t *props;
   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
                                               local_relpath, scratch_pool);
   svn_wc_notify_state_t obstr_state;
+  svn_boolean_t is_deleted;
+  svn_node_kind_t kind;
 
-  SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL,
-                                    NULL,
+  SVN_ERR(perform_obstruction_check(&obstr_state, NULL, &is_deleted,
+                                    &kind,
                                     merge_b, local_abspath, svn_node_dir,
                                     scratch_pool));
 
@@ -1305,6 +1288,26 @@ merge_dir_props_changed(svn_wc_notify_st
       return SVN_NO_ERROR;
     }
 
+  if (kind != svn_node_dir || is_deleted)
+    {
+      svn_wc_conflict_reason_t reason;
+
+      if (is_deleted)
+        reason = svn_wc_conflict_reason_deleted;
+      else
+        reason = svn_wc_conflict_reason_missing;
+
+      SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
+                            svn_wc_conflict_action_edit, reason));
+
+      if (tree_conflicted)
+        *tree_conflicted = TRUE;
+      if (state)
+        *state = svn_wc_notify_state_missing;
+
+      return SVN_NO_ERROR;
+    }
+
   if (dir_was_added
       && merge_b->dry_run
       && dry_run_added_p(merge_b, local_abspath))
@@ -1312,13 +1315,26 @@ merge_dir_props_changed(svn_wc_notify_st
       return SVN_NO_ERROR; /* We can't do a real prop merge for added dirs */
     }
 
-  return svn_error_trace(merge_props_changed(state,
-                                             tree_conflicted,
-                                             local_abspath,
-                                             propchanges,
-                                             original_props,
-                                             diff_baton,
-                                             scratch_pool));
+  SVN_ERR(prepare_merge_props_changed(&props, local_abspath, propchanges,
+                                      merge_b, scratch_pool, scratch_pool));
+
+  /* We only want to merge "regular" version properties:  by
+     definition, 'svn merge' shouldn't touch any pristine data  */
+  if (props->nelts)
+    {
+      svn_client_ctx_t *ctx = merge_b->ctx;
+
+      SVN_ERR(svn_wc_merge_props3(state, ctx->wc_ctx, local_abspath,
+                                  NULL, NULL, original_props, props,
+                                  merge_b->dry_run,
+                                  ctx->conflict_func2, ctx->conflict_baton2,
+                                  ctx->cancel_func, ctx->cancel_baton,
+                                  scratch_pool));
+    }
+  else if (state)
+    *state = svn_wc_notify_state_unchanged;
+
+  return SVN_NO_ERROR;
 }
 
 /* Contains any state collected while resolving conflicts. */
@@ -1472,12 +1488,15 @@ merge_file_changed(svn_wc_notify_state_t
                    apr_pool_t *scratch_pool)
 {
   merge_cmd_baton_t *merge_b = baton;
-  const char *mine_abspath = svn_dirent_join(merge_b->target->abspath,
-                                             mine_relpath, scratch_pool);
+  svn_client_ctx_t *ctx = merge_b->ctx;
+  const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
+                                              mine_relpath, scratch_pool);
   svn_node_kind_t wc_kind;
   svn_boolean_t is_deleted;
+  const svn_wc_conflict_version_t *left;
+  const svn_wc_conflict_version_t *right;
 
-  SVN_ERR_ASSERT(mine_abspath && svn_dirent_is_absolute(mine_abspath));
+  SVN_ERR_ASSERT(local_abspath && svn_dirent_is_absolute(local_abspath));
   SVN_ERR_ASSERT(!older_abspath || svn_dirent_is_absolute(older_abspath));
   SVN_ERR_ASSERT(!yours_abspath || svn_dirent_is_absolute(yours_abspath));
 
@@ -1490,7 +1509,7 @@ merge_file_changed(svn_wc_notify_state_t
 
     SVN_ERR(perform_obstruction_check(&obstr_state, NULL,
                                       &is_deleted, &wc_kind,
-                                      merge_b, mine_abspath, svn_node_unknown,
+                                      merge_b, local_abspath, svn_node_unknown,
                                       scratch_pool));
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
@@ -1508,7 +1527,7 @@ merge_file_changed(svn_wc_notify_state_t
 
   /* Other easy outs:  if the merge target isn't under version
      control, or is just missing from disk, fogettaboutit.  There's no
-     way svn_wc_merge4() can do the merge. */
+     way svn_wc_merge5() can do the merge. */
   if (wc_kind != svn_node_file || is_deleted)
     {
       const char *moved_to_abspath;
@@ -1524,8 +1543,8 @@ merge_file_changed(svn_wc_notify_state_t
            * a conflict. Non-inheritable mergeinfo will be recorded, allowing
            * future merges into non-shallow working copies to merge changes
            * we missed this time around. */
-          SVN_ERR(svn_wc__node_get_depth(&parent_depth, merge_b->ctx->wc_ctx,
-                                         svn_dirent_dirname(mine_abspath,
+          SVN_ERR(svn_wc__node_get_depth(&parent_depth, ctx->wc_ctx,
+                                         svn_dirent_dirname(local_abspath,
                                                             scratch_pool),
                                          scratch_pool));
           if (parent_depth < svn_depth_files
@@ -1543,12 +1562,15 @@ merge_file_changed(svn_wc_notify_state_t
        * #2282.  See also notes/tree-conflicts/detection.txt
        */
       err = svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
-                                        merge_b->ctx->wc_ctx, mine_abspath,
+                                        ctx->wc_ctx, local_abspath,
                                         scratch_pool, scratch_pool);
       if (err)
         {
           if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-            svn_error_clear(err);
+            {
+              svn_error_clear(err);
+              moved_to_abspath = NULL;
+            }
           else
             return svn_error_trace(err);
         }
@@ -1557,7 +1579,7 @@ merge_file_changed(svn_wc_notify_state_t
         {
           /* File has been moved away locally -- apply incoming
            * changes at the new location. */
-          mine_abspath = moved_to_abspath;
+          local_abspath = moved_to_abspath;
         }
       else
         {
@@ -1567,7 +1589,7 @@ merge_file_changed(svn_wc_notify_state_t
             reason = svn_wc_conflict_reason_deleted;
           else
             reason = svn_wc_conflict_reason_missing;
-          SVN_ERR(tree_conflict(merge_b, mine_abspath, svn_node_file,
+          SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
                                 svn_wc_conflict_action_edit, reason));
           if (tree_conflicted)
             *tree_conflicted = TRUE;
@@ -1593,31 +1615,37 @@ merge_file_changed(svn_wc_notify_state_t
   */
 
   /* This callback is essentially no more than a wrapper around
-     svn_wc_merge4().  Thank goodness that all the
+     svn_wc_merge5().  Thank goodness that all the
      diff-editor-mechanisms are doing the hard work of getting the
      fulltexts! */
 
-  /* Do property merge before text merge so that keyword expansion takes
-     into account the new property values. */
+  if (prop_state)
+    *prop_state = svn_wc_notify_state_unchanged;
+
   if (prop_changes->nelts > 0)
     {
-      svn_boolean_t tree_conflicted2 = FALSE;
-
-      SVN_ERR(merge_props_changed(prop_state, &tree_conflicted2,
-                                  mine_abspath, prop_changes, original_props,
-                                  baton, scratch_pool));
+      /* Filter entry-props and unneeded properties in case of a record only
+         merge */
+      SVN_ERR(prepare_merge_props_changed(&prop_changes, local_abspath,
+                                          prop_changes, merge_b,
+                                          scratch_pool, scratch_pool));
+    }
 
-      /* If the prop change caused a tree-conflict, just bail. */
-      if (tree_conflicted2)
-        {
-          if (tree_conflicted != NULL)
-            *tree_conflicted = TRUE;
+  SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
+                                 svn_node_file, merge_b));
 
-          return SVN_NO_ERROR;
-        }
+  /* Do property merge now, if we are not going to perform a text merge */
+  if ((merge_b->record_only || !older_abspath) && prop_changes->nelts)
+    {
+      SVN_ERR(svn_wc_merge_props3(prop_state, ctx->wc_ctx, local_abspath,
+                                  left, right,
+                                  original_props, prop_changes,
+                                  merge_b->dry_run,
+                                  ctx->conflict_func2,
+                                  ctx->conflict_baton2,
+                                  ctx->cancel_func, ctx->cancel_baton,
+                                  scratch_pool));
     }
-  else if (prop_state)
-    *prop_state = svn_wc_notify_state_unchanged;
 
   /* Easy out: We are only applying mergeinfo differences. */
   if (merge_b->record_only)
@@ -1630,7 +1658,7 @@ merge_file_changed(svn_wc_notify_state_t
   if (older_abspath)
     {
       svn_boolean_t has_local_mods;
-      enum svn_wc_merge_outcome_t merge_outcome;
+      enum svn_wc_merge_outcome_t content_outcome;
 
       /* xgettext: the '.working', '.merge-left.r%ld' and
          '.merge-right.r%ld' strings are used to tag onto a file
@@ -1643,40 +1671,39 @@ merge_file_changed(svn_wc_notify_state_t
                                              _(".merge-right.r%ld"),
                                              yours_rev);
       conflict_resolver_baton_t conflict_baton = { 0 };
-      const svn_wc_conflict_version_t *left;
-      const svn_wc_conflict_version_t *right;
 
-      SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, merge_b->ctx->wc_ctx,
-                                      mine_abspath, FALSE, scratch_pool));
+      SVN_ERR(svn_wc_text_modified_p2(&has_local_mods, ctx->wc_ctx,
+                                      local_abspath, FALSE, scratch_pool));
 
-      conflict_baton.wrapped_func = merge_b->ctx->conflict_func2;
-      conflict_baton.wrapped_baton = merge_b->ctx->conflict_baton2;
+      conflict_baton.wrapped_func = ctx->conflict_func2;
+      conflict_baton.wrapped_baton = ctx->conflict_baton2;
       conflict_baton.conflicted_paths = &merge_b->conflicted_paths;
       conflict_baton.pool = merge_b->pool;
 
-      SVN_ERR(make_conflict_versions(&left, &right, mine_abspath,
-                                     svn_node_file, merge_b));
-      SVN_ERR(svn_wc_merge4(&merge_outcome, merge_b->ctx->wc_ctx,
-                            older_abspath, yours_abspath, mine_abspath,
+      /* Do property merge and text merge in one step so that keyword expansion
+         takes into account the new property values. */
+      SVN_ERR(svn_wc_merge5(&content_outcome, prop_state, ctx->wc_ctx,
+                            older_abspath, yours_abspath, local_abspath,
                             left_label, right_label, target_label,
                             left, right,
                             merge_b->dry_run, merge_b->diff3_cmd,
-                            merge_b->merge_options, prop_changes,
+                            merge_b->merge_options,
+                            original_props, prop_changes,
                             conflict_resolver, &conflict_baton,
-                            merge_b->ctx->cancel_func,
-                            merge_b->ctx->cancel_baton,
+                            ctx->cancel_func,
+                            ctx->cancel_baton,
                             scratch_pool));
 
       if (content_state)
         {
-          if (merge_outcome == svn_wc_merge_conflict)
+          if (content_outcome == svn_wc_merge_conflict)
             *content_state = svn_wc_notify_state_conflicted;
           else if (has_local_mods
-                   && merge_outcome != svn_wc_merge_unchanged)
+                   && content_outcome != svn_wc_merge_unchanged)
             *content_state = svn_wc_notify_state_merged;
-          else if (merge_outcome == svn_wc_merge_merged)
+          else if (content_outcome == svn_wc_merge_merged)
             *content_state = svn_wc_notify_state_changed;
-          else if (merge_outcome == svn_wc_merge_no_merge)
+          else if (content_outcome == svn_wc_merge_no_merge)
             *content_state = svn_wc_notify_state_missing;
           else /* merge_outcome == svn_wc_merge_unchanged */
             *content_state = svn_wc_notify_state_unchanged;
@@ -3760,11 +3787,11 @@ ensure_implicit_mergeinfo(svn_client__me
    REVISION1 and REVISION2 describe the merge range requested from
    MERGEINFO_PATH.
 
-   TARGET_MERGEINFO is the portion of CHILD->ABSPATH's explicit or inherited
+   TARGET_RANGELIST is the portion of CHILD->ABSPATH's explicit or inherited
    mergeinfo that intersects with the merge history described by
-   MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2.  TARGET_MERGEINFO
+   MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2.  TARGET_RANGELIST
    should be NULL if there is no explicit or inherited mergeinfo on
-   CHILD->ABSPATH or an empty hash if CHILD->ABSPATH has empty mergeinfo or
+   CHILD->ABSPATH or an empty list if CHILD->ABSPATH has empty mergeinfo or
    explicit mergeinfo that exclusively describes non-intersecting history
    with MERGEINFO_PATH@REVISION1:MERGEINFO_PATH@REVISION2.
 
@@ -3779,7 +3806,7 @@ static svn_error_t *
 filter_merged_revisions(svn_client__merge_path_t *parent,
                         svn_client__merge_path_t *child,
                         const char *mergeinfo_path,
-                        svn_mergeinfo_t target_mergeinfo,
+                        apr_array_header_t *target_rangelist,
                         svn_revnum_t revision1,
                         svn_revnum_t revision2,
                         svn_boolean_t child_inherits_implicit,
@@ -3788,7 +3815,7 @@ filter_merged_revisions(svn_client__merg
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
 {
-  apr_array_header_t *requested_rangelist, *target_rangelist,
+  apr_array_header_t *requested_rangelist,
     *target_implicit_rangelist, *explicit_rangelist;
 
   /* Convert REVISION1 and REVISION2 to a rangelist.
@@ -3813,12 +3840,8 @@ filter_merged_revisions(svn_client__merg
          our svn_rangelist_* APIs to work properly. */
       SVN_ERR(svn_rangelist_reverse(requested_rangelist, scratch_pool));
 
-      if (target_mergeinfo)
-        target_rangelist = apr_hash_get(target_mergeinfo,
-                                        mergeinfo_path, APR_HASH_KEY_STRING);
-      else
-        target_rangelist = NULL;
-
+      /* Set EXPLICIT_RANGELIST to the list of source-range revs that are
+         already recorded as merged to target. */
       if (target_rangelist)
         {
           /* Return the intersection of the revs which are both already
@@ -3902,16 +3925,12 @@ filter_merged_revisions(svn_client__merg
     }
   else /* This is a forward merge */
     {
-      if (target_mergeinfo)
-        target_rangelist = apr_hash_get(target_mergeinfo, mergeinfo_path,
-                                        APR_HASH_KEY_STRING);
-      else
-        target_rangelist = NULL;
-
-      /* See earlier comment preceding svn_rangelist_intersect() for
-         why we don't consider inheritance here. */
+      /* Set EXPLICIT_RANGELIST to the list of source-range revs that are
+         NOT already recorded as merged to target. */
       if (target_rangelist)
         {
+          /* See earlier comment preceding svn_rangelist_intersect() for
+             why we don't consider inheritance here. */
           SVN_ERR(svn_rangelist_remove(&explicit_rangelist,
                                        target_rangelist,
                                        requested_rangelist, FALSE,
@@ -4047,54 +4066,40 @@ calculate_remaining_ranges(svn_client__m
                             ? source->loc2->url : source->loc1->url;
   /* Intersection of TARGET_MERGEINFO and the merge history
      described by SOURCE. */
-  svn_mergeinfo_t adjusted_target_mergeinfo = NULL;
+  apr_array_header_t *target_rangelist;
   svn_revnum_t child_base_revision;
 
   /* Determine which of the requested ranges to consider merging... */
   SVN_ERR(svn_ra__get_fspath_relative_to_root(ra_session, &mergeinfo_path,
                                               primary_url, result_pool));
 
-  /* Does SOURCE describe a single, unbroken line of history or is there a
-     copy as allowed by `MERGEINFO MERGE SOURCE NORMALIZATION'? */
-  if (implicit_src_gap && child->pre_merge_mergeinfo)
-    {
-      /* Handle issue #3242: The presence of IMPLICIT_SRC_GAP implies that
-         a single copy of SOURCE->LOC1->URL@SOURCE->LOC1->REV was made
-         between SOURCE->LOC1->REV + 1 and SOURCE->LOC2->REV and that
-         there exists a single range M:N, where
-         SOURCE->LOC1->REV < M < N < SOURCE->LOC2->REV, such that
-         SOURCE->LOC2->URL@M:SOURCE->LOC2->URL@N either doesn't exist
-         or describes a different line of history than SOURCE.  In either
-         case we don't want to consider this range as merged so remove it
-         from TARGET_MERGEINFO. */
-      apr_array_header_t *explicit_mergeinfo_gap_ranges =
-        apr_hash_get(child->pre_merge_mergeinfo, mergeinfo_path,
-                     APR_HASH_KEY_STRING);
-
-      if (explicit_mergeinfo_gap_ranges)
-        {
-          svn_mergeinfo_t gap_mergeinfo = apr_hash_make(scratch_pool);
-
-          apr_hash_set(gap_mergeinfo, mergeinfo_path, APR_HASH_KEY_STRING,
-                       implicit_src_gap);
-          SVN_ERR(svn_mergeinfo_remove2(&adjusted_target_mergeinfo,
-                                        gap_mergeinfo, target_mergeinfo,
-                                        FALSE, result_pool, scratch_pool));
-        }
-    }
+  /* Set TARGET_RANGELIST to the portion of TARGET_MERGEINFO that refers
+     to SOURCE (excluding any gap in SOURCE): first get all ranges from
+     TARGET_MERGEINFO that refer to the path of SOURCE, and then prune
+     any ranges that lie in the gap in SOURCE.
+
+     ### [JAF] In fact, that may still leave some ranges that lie entirely
+     outside the range of SOURCE; it seems we don't care about that.  */
+  if (target_mergeinfo)
+    target_rangelist = apr_hash_get(target_mergeinfo, mergeinfo_path,
+                                    APR_HASH_KEY_STRING);
   else
+    target_rangelist = NULL;
+  if (implicit_src_gap && target_rangelist)
     {
-      /* The simple case: SOURCE->LOC1->URL2@SOURCE->LOC1->REV:
-         SOURCE->LOC2->URL2@SOURCE->LOC2->REV describes two locations
-         along a single, unbroken line of history, there is nothing to
-         filter out. */
-      adjusted_target_mergeinfo = target_mergeinfo;
+      /* Remove any mergeinfo referring to the 'gap' in SOURCE, as that
+         mergeinfo doesn't really refer to SOURCE at all but instead
+         refers to locations that are non-existent or on a different
+         line of history.  (Issue #3242.) */
+      SVN_ERR(svn_rangelist_remove(&target_rangelist,
+                                   implicit_src_gap, target_rangelist,
+                                   FALSE, result_pool));
     }
 
   /* Initialize CHILD->REMAINING_RANGES and filter out revisions already
      merged (or, in the case of reverse merges, ranges not yet merged). */
   SVN_ERR(filter_merged_revisions(parent, child, mergeinfo_path,
-                                  adjusted_target_mergeinfo,
+                                  target_rangelist,
                                   source->loc1->rev, source->loc2->rev,
                                   child_inherits_implicit,
                                   ra_session, ctx, result_pool,
@@ -8740,6 +8745,7 @@ do_directory_merge(svn_mergeinfo_catalog
     {
       const char *mergeinfo_path;
 
+      /* ### Leaks merge_conflict_err */
       SVN_ERR(svn_ra__get_fspath_relative_to_root(ra_session, &mergeinfo_path,
                                                   primary_url, scratch_pool));
       err = record_mergeinfo_for_dir_merge(result_catalog,
@@ -10940,6 +10946,58 @@ svn_client_merge_peg4(const char *source
 
 #ifdef SVN_WITH_SYMMETRIC_MERGE
 
+/* The location-history of a branch.
+ *
+ * This structure holds the set of path-revisions occupied by a branch,
+ * from an externally chosen 'tip' location back to its origin.  The
+ * 'tip' location is the youngest location that we are considering on
+ * the branch. */
+typedef struct branch_history_t
+{
+  /* The tip location of the branch.  That is, the youngest location that's
+   * in the repository and that we're considering.  If we're considering a
+   * target branch right up to an uncommitted WC, then this is the WC base
+   * (pristine) location. */
+  svn_client__pathrev_t *tip;
+  /* The location-segment history, as mergeinfo. */
+  svn_mergeinfo_t history;
+  /* Whether the location-segment history reached as far as (necessarily
+     the root path in) revision 0 -- a fact that can't be represented as
+     mergeinfo. */
+  svn_boolean_t has_r0_history;
+} branch_history_t;
+
+/* Return the location on BRANCH_HISTORY at revision REV, or NULL if none. */
+static svn_client__pathrev_t *
+location_on_branch_at_rev(const branch_history_t *branch_history,
+                          svn_revnum_t rev,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, branch_history->history); hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *fspath = svn__apr_hash_index_key(hi);
+      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+      int i;
+
+      for (i = 0; i < rangelist->nelts; i++)
+        {
+          svn_merge_range_t *r = APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+          if (r->start < rev && rev <= r->end)
+            {
+              return svn_client__pathrev_create_with_relpath(
+                       branch_history->tip->repos_root_url,
+                       branch_history->tip->repos_uuid,
+                       rev, fspath + 1, result_pool);
+            }
+        }
+    }
+  return NULL;
+}
+
 /* Details of a symmetric merge. */
 struct svn_client__symmetric_merge_t
 {
@@ -10951,8 +11009,22 @@ typedef struct source_and_target_t
 {
   svn_client__pathrev_t *source;
   svn_ra_session_t *source_ra_session;
+  branch_history_t source_branch;
+
   merge_target_t *target;
   svn_ra_session_t *target_ra_session;
+  branch_history_t target_branch;
+
+  /* The complete mergeinfo on SOURCE.
+     That is, the explicit or inherited mergeinfo.  */
+  svn_mergeinfo_t source_mergeinfo;
+
+  /* The complete mergeinfo on (the current, working version of) TARGET.
+     That is, the explicit or inherited mergeinfo. */
+  svn_mergeinfo_t target_mergeinfo;
+
+  /* Repos location of the youngest common ancestor of SOURCE and TARGET. */
+  svn_client__pathrev_t *yca;
 } source_and_target_t;
 
 /* "Open" the source and target branches of a merge.  That means:
@@ -11005,18 +11077,214 @@ close_source_and_target(source_and_targe
   return SVN_NO_ERROR;
 }
 
+/* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the
+ * revision range OLDEST_REV to YOUNGEST_REV (inclusive).
+ *
+ * If the intersection is empty, the result will be a branch history object
+ * containing an empty (not null) history.
+ *
+ * ### The 'tip' of the result is currently unchanged.
+ */
+static svn_error_t *
+branch_history_intersect_range(branch_history_t **intersection_p,
+                               const branch_history_t *branch_history,
+                               svn_revnum_t oldest_rev,
+                               svn_revnum_t youngest_rev,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  branch_history_t *result = apr_palloc(result_pool, sizeof(*result));
+
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(oldest_rev));
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+  SVN_ERR_ASSERT(oldest_rev >= 1);
+  /* Allow a just-empty range (oldest = youngest + 1) but not an
+   * arbitrary reverse range (such as oldest = youngest + 2). */
+  SVN_ERR_ASSERT(oldest_rev <= youngest_rev + 1);
+
+  if (oldest_rev <= youngest_rev)
+    {
+      SVN_ERR(svn_mergeinfo__filter_mergeinfo_by_ranges(
+                &result->history, branch_history->history,
+                youngest_rev, oldest_rev - 1, TRUE /* include_range */,
+                result_pool, scratch_pool));
+      result->history = svn_mergeinfo_dup(result->history, result_pool);
+    }
+  else
+    {
+      result->history = apr_hash_make(result_pool);
+    }
+  result->has_r0_history = FALSE;
+
+  /* ### TODO: Set RESULT->tip to the tip of the intersection. */
+  result->tip = svn_client__pathrev_dup(branch_history->tip, result_pool);
+
+  *intersection_p = result;
+  return SVN_NO_ERROR;
+}
+
+/* Set *OLDEST_P and *YOUNGEST_P to the oldest and youngest locations
+ * (inclusive) along BRANCH.  OLDEST_P and/or YOUNGEST_P may be NULL if not
+ * wanted.
+ */
+static svn_error_t *
+branch_history_get_endpoints(svn_client__pathrev_t **oldest_p,
+                             svn_client__pathrev_t **youngest_p,
+                             const branch_history_t *branch,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_revnum_t youngest_rev, oldest_rev;
+
+  SVN_ERR(svn_mergeinfo__get_range_endpoints(
+            &youngest_rev, &oldest_rev,
+            branch->history, scratch_pool));
+  if (oldest_p)
+    *oldest_p = location_on_branch_at_rev(
+                  branch, oldest_rev + 1, result_pool, scratch_pool);
+  if (youngest_p)
+    *youngest_p = location_on_branch_at_rev(
+                    branch, youngest_rev, result_pool, scratch_pool);
+  return SVN_NO_ERROR;
+}
+
+/* Set *BASE_P to the last location on SOURCE_BRANCH such that all changes
+ * on SOURCE_BRANCH up to and including *BASE_P have already been merged
+ * into the target branch -- or, specifically, are recorded in
+ * TARGET_MERGEINFO.
+ *
+ *               *BASE_P       TIP
+ *          o-------o-----------o--- SOURCE_BRANCH
+ *         /         \
+ *   -----o     prev. \
+ *     YCA \    merges \
+ *          o-----------o-----------
+ *
+ * In terms of mergeinfo:
+ *
+ *     Source     a--...                     o=change, -=no-op revision
+ *       branch  /   \
+ *     YCA -->  o     a---o---o---o---o---   d=delete, a=add-as-a-copy
+ *
+ *     Eligible -.eee.eeeeeeeeeeeeeeeeeeee   .=not a source branch location
+ *
+ *     Tgt-mi   -.mmm.mm-mm-------m-------   m=merged, -=not merged
+ *
+ *     Eligible -.---.--e--eeeeeee-eeeeeee
+ *
+ *     Next     --------^-----------------   BASE is just before here.
+ *
+ *             /         \
+ *       -----o     prev. \
+ *         YCA \    merges \
+ *              o-----------o-------------
+ *
+ * If no locations on SOURCE_BRANCH are recorded in TARGET_MERGEINFO, set
+ * *BASE_P to the YCA.
+ */
+static svn_error_t *
+find_last_merged_location(svn_client__pathrev_t **base_p,
+                          svn_client__pathrev_t *yca,
+                          const branch_history_t *source_branch,
+                          svn_mergeinfo_t target_mergeinfo,
+                          svn_client_ctx_t *ctx,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
+{
+  /*
+   To find the youngest location on BRANCH_A that is fully merged to BRANCH_B:
+
+     Find the longest set of locations in BRANCH_A, starting after YCA,
+     such that each location is (any of):
+       (a) in BRANCH_B's mergeinfo; or
+       (b) a merge onto BRANCH_A of logical changes that are all from the
+           target branch or already in BRANCH_B's mergeinfo; or
+       (c) inoperative on BRANCH_A.
+
+     Report the youngest such location, or the YCA if there are none.
+
+     Part (b) can perhaps, initially, be simplified to something like:
+     a merge onto BRANCH_A of (including? entirely?) revisions from
+     BRANCH_B's history.
+
+     Part (c) is only necessary if we want to allow sparse mergeinfo --
+     that is, if we don't want to do some partially- or completely-
+     inoperative merges to fill in mergeinfo gaps.
+   */
+  branch_history_t *eligible_locations;
+
+  /* Start with a list of all source locations after YCA up to the tip. */
+  SVN_ERR(branch_history_intersect_range(
+            &eligible_locations,
+            source_branch, yca->rev + 1, source_branch->tip->rev,
+            scratch_pool, scratch_pool));
+
+  /* Remove any locations that match (a), (b) or (c). */
+  /* For (a), remove any locations that are in TARGET's mergeinfo. */
+  SVN_ERR(svn_mergeinfo_remove(&eligible_locations->history,
+                               target_mergeinfo, eligible_locations->history,
+                               scratch_pool));
+  /* For (b) ... */
+
+  /* For (c) ... */
+
+  /* This leaves a list of source locations that are eligible to merge.
+     The location that we want is the source location just before oldest
+     eligible location remaining in this list; or the youngest source
+     location if there are none left in this list. */
+  if (apr_hash_count(eligible_locations->history) > 0)
+    {
+      /* Find the oldest eligible rev.
+       * Eligible -.---.--e--eeeeeee-eeeeeee
+       *                  ^
+       *                  BASE is just before here.
+       */
+
+      svn_client__pathrev_t *oldest_eligible;
+      branch_history_t *contiguous_source;
+
+      SVN_ERR(branch_history_get_endpoints(
+                &oldest_eligible, NULL,
+                eligible_locations, scratch_pool, scratch_pool));
+
+      /* Find the branch location just before the oldest eligible rev.
+       * (We can't just subtract 1 from the rev because the branch might
+       * have a gap there.) */
+      SVN_ERR(branch_history_intersect_range(
+                &contiguous_source,
+                source_branch, yca->rev, oldest_eligible->rev - 1,
+                scratch_pool, scratch_pool));
+      SVN_ERR(branch_history_get_endpoints(
+                NULL, base_p,
+                contiguous_source, result_pool, scratch_pool));
+    }
+  else
+    {
+      /* The whole source branch is merged already, so the base for
+       * the next merge is its tip. */
+      *base_p = source_branch->tip;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Find a merge base location on the target branch, like in a sync
  * merge.
  *
- *          (Source-left) (Source-right = S_T->source)
- *                BASE        RIGHT
+ *                BASE          S_T->source
  *          o-------o-----------o---
  *         /         \           \
  *   -----o     prev. \           \  this
  *     YCA \    merge  \           \ merge
  *          o-----------o-----------o
- *                                TARGET
+ *                                  S_T->target
+ *
+ * Set *BASE_P to BASE, the youngest location in the history of S_T->source
+ * (at or after the YCA) at which all revisions up to BASE are recorded as
+ * merged into S_T->target.
  *
+ * If no locations on the history of S_T->source are recorded as merged to
+ * S_T->target, set *BASE_P to the YCA.
  */
 static svn_error_t *
 find_base_on_source(svn_client__pathrev_t **base_p,
@@ -11025,67 +11293,35 @@ find_base_on_source(svn_client__pathrev_
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
-  svn_mergeinfo_t target_mergeinfo;
-  svn_client__merge_path_t *merge_target;
-  svn_boolean_t inherited;
-  svn_client__pathrev_t loc1;
-  merge_source_t source;
-  svn_merge_range_t *r;
-
-  merge_target = svn_client__merge_path_create(s_t->target->abspath,
-                                               scratch_pool);
-
-  /* Fetch target mergeinfo (all the way back to revision 1). */
-  SVN_ERR(get_full_mergeinfo(&target_mergeinfo,
-                             &merge_target->implicit_mergeinfo,
-                             &inherited, svn_mergeinfo_inherited,
-                             s_t->target_ra_session, s_t->target->abspath,
-                             s_t->source->rev, 1,
-                             ctx, scratch_pool, scratch_pool));
-
-  /* In order to find the first unmerged change in the source, set
-   * MERGE_TARGET->remaining_ranges to the ranges left to merge,
-   * and look at the start revision of the first such range. */
-  loc1.repos_root_url = s_t->source->repos_root_url;
-  loc1.repos_uuid = s_t->source->repos_uuid;
-  loc1.url = s_t->source->url;  /* ### WRONG: need historical URL/REV */
-  loc1.rev = 1;
-  source.loc1 = &loc1;
-  source.loc2 = s_t->source;
-  SVN_ERR(calculate_remaining_ranges(NULL, merge_target,
-                                     &source,
-                                     target_mergeinfo,
-                                     NULL /*merge_b->implicit_src_gap*/,
-                                     FALSE /*child_inherits_implicit*/,
-                                     s_t->source_ra_session,
-                                     ctx, scratch_pool, scratch_pool));
-
-  r = APR_ARRAY_IDX(merge_target->remaining_ranges, 0, svn_merge_range_t *);
-
-  /* ### WRONG: need historical URL instead of s_t->source->url. */
-  *base_p = svn_client__pathrev_create(s_t->source->repos_root_url,
-                                       s_t->source->repos_uuid,
-                                       r->start, s_t->source->url, result_pool);
+  SVN_ERR(find_last_merged_location(base_p,
+                                    s_t->yca,
+                                    &s_t->source_branch,
+                                    s_t->target_mergeinfo,
+                                    ctx, result_pool, scratch_pool));
   return SVN_NO_ERROR;
 }
 
 /* Find a merge base location on the target branch, like in a reintegrate
  * merge.
  *
- *                     MID    RIGHT
+ *                     MID      S_T->source
  *          o-----------o-------o---
  *         /    prev.  /         \
  *   -----o     merge /           \  this
  *     YCA \         /             \ merge
  *          o-------o---------------o
- *                BASE            TARGET
+ *                BASE              S_T->target
+ *
+ * Set *BASE_P to BASE, the youngest location in the history of S_T->target
+ * (at or after the YCA) at which all revisions up to BASE are recorded as
+ * merged into S_T->source.
  *
- * Set *BASE_P to the latest location on the history of S_T->target at
- * which all revisions up to *BASE_P are recorded as merged into RIGHT
- * (which is S_T->source).
+ * Set *MID_P to the first location on the history of S_T->source at which
+ * all revisions up to BASE are recorded as merged.
+ * ### This is not implemented yet.
  *
- * ### TODO: Set *MID_P to the first location on the history of
- * S_T->source at which all revisions up to BASE_P are recorded as merged.
+ * If no locations on the history of S_T->target are recorded as merged to
+ * S_T->source, set both *BASE_P and *MID_P to the YCA.
  */
 static svn_error_t *
 find_base_on_target(svn_client__pathrev_t **base_p,
@@ -11095,34 +11331,12 @@ find_base_on_target(svn_client__pathrev_
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
-  svn_mergeinfo_catalog_t unmerged_to_source_mergeinfo_catalog;
-  svn_mergeinfo_catalog_t merged_to_source_mergeinfo_catalog;
-  apr_hash_t *subtrees_with_mergeinfo;
-
-  /* Find all the subtrees in TARGET_WCPATH that have explicit mergeinfo. */
-  SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo,
-                                            s_t->target->abspath,
-                                            svn_depth_infinity,
-                                            ctx, scratch_pool, scratch_pool));
-
-  SVN_ERR(calculate_left_hand_side(base_p,
-                                   &merged_to_source_mergeinfo_catalog,
-                                   &unmerged_to_source_mergeinfo_catalog,
-                                   s_t->target,
-                                   subtrees_with_mergeinfo,
-                                   s_t->source,
-                                   s_t->source_ra_session,
-                                   s_t->target_ra_session,
-                                   ctx, result_pool, scratch_pool));
-
-  if (*base_p)
-    {
-      *mid_p = s_t->source;  /* ### WRONG! This is quite difficult. */
-    }
-  else
-    {
-      *mid_p = NULL;
-    }
+  SVN_ERR(find_last_merged_location(base_p,
+                                    s_t->yca,
+                                    &s_t->target_branch,
+                                    s_t->source_mergeinfo,
+                                    ctx, result_pool, scratch_pool));
+  *mid_p = *base_p;  /* ### Wrong! */
 
   return SVN_NO_ERROR;
 }
@@ -11130,8 +11344,7 @@ find_base_on_target(svn_client__pathrev_
 /* The body of svn_client__find_symmetric_merge(), which see.
  */
 static svn_error_t *
-find_symmetric_merge(svn_client__pathrev_t **yca_p,
-                     svn_client__pathrev_t **base_p,
+find_symmetric_merge(svn_client__pathrev_t **base_p,
                      svn_client__pathrev_t **mid_p,
                      source_and_target_t *s_t,
                      svn_client_ctx_t *ctx,
@@ -11140,8 +11353,37 @@ find_symmetric_merge(svn_client__pathrev
 {
   svn_client__pathrev_t *base_on_source, *base_on_target, *mid;
 
+  /* Fetch mergeinfo of source branch (tip) and target branch (working). */
+  SVN_ERR(svn_client__get_repos_mergeinfo(&s_t->source_mergeinfo,
+                                          s_t->source_ra_session,
+                                          s_t->source->url,
+                                          s_t->source->rev,
+                                          svn_mergeinfo_inherited,
+                                          FALSE /* squelch_incapable */,
+                                          scratch_pool));
+  SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(&s_t->target_mergeinfo,
+                                                NULL /* inherited */,
+                                                NULL /* from_repos */,
+                                                FALSE /* repos_only */,
+                                                svn_mergeinfo_inherited,
+                                                s_t->target_ra_session,
+                                                s_t->target->abspath,
+                                                ctx, scratch_pool));
+
+  /* Get the location-history of each branch. */
+  s_t->source_branch.tip = s_t->source;
+  SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &s_t->source_branch.history, &s_t->source_branch.has_r0_history,
+            s_t->source, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+            s_t->source_ra_session, ctx, scratch_pool));
+  s_t->target_branch.tip = &s_t->target->loc;
+  SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &s_t->target_branch.history, &s_t->target_branch.has_r0_history,
+            &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+            s_t->target_ra_session, ctx, scratch_pool));
+
   SVN_ERR(svn_client__get_youngest_common_ancestor(
-            yca_p, s_t->source, &s_t->target->loc,
+            &s_t->yca, s_t->source, &s_t->target->loc,
             ctx, result_pool, result_pool));
 
   /* Find the latest revision of A synced to B and the latest
@@ -11155,32 +11397,20 @@ find_symmetric_merge(svn_client__pathrev
   SVN_ERR(find_base_on_target(&base_on_target, &mid, s_t,
                               ctx, scratch_pool, scratch_pool));
 
-  if (base_on_source)
-    SVN_DBG(("base on source: %s@%ld\n", base_on_source->url, base_on_source->rev));
-  if (base_on_target)
-    SVN_DBG(("base on target: %s@%ld\n", base_on_target->url, base_on_target->rev));
+  SVN_DBG(("base on source: %s@%ld\n", base_on_source->url, base_on_source->rev));
+  SVN_DBG(("base on target: %s@%ld\n", base_on_target->url, base_on_target->rev));
 
   /* Choose a base. */
-  if (base_on_source
-      && (! base_on_target || (base_on_source->rev > base_on_target->rev)))
+  if (base_on_source->rev >= base_on_target->rev)
     {
       *base_p = base_on_source;
       *mid_p = NULL;
     }
-  else if (base_on_target)
+  else
     {
       *base_p = base_on_target;
       *mid_p = mid;
     }
-  else
-    {
-      /* No previous merge was found, so this is the simple case where
-       * the base is the youngest common ancestor of the branches.  We'll
-       * set MID=NULL; in theory the end result should be the same if we
-       * set MID=YCA instead. */
-      *base_p = *yca_p;
-      *mid_p = NULL;
-    }
 
   return SVN_NO_ERROR;
 }
@@ -11211,8 +11441,9 @@ svn_client__find_symmetric_merge(svn_cli
                            &s_t->target->loc, target_wcpath,
                            TRUE /* strict_urls */, scratch_pool));
 
-  SVN_ERR(find_symmetric_merge(&merge->yca, &merge->base, &merge->mid, s_t,
+  SVN_ERR(find_symmetric_merge(&merge->base, &merge->mid, s_t,
                                ctx, result_pool, scratch_pool));
+  merge->yca = s_t->yca;
   merge->right = s_t->source;
 
   *merge_p = merge;

Modified: subversion/branches/ev2-export/subversion/libsvn_client/resolved.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_client/resolved.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_client/resolved.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_client/resolved.c Fri May 11 00:05:41 2012
@@ -55,12 +55,14 @@ svn_client_resolve(const char *path,
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
 
-  SVN_ERR(svn_wc_resolved_conflict5(ctx->wc_ctx, local_abspath,
+  SVN_ERR(svn_wc__resolve_conflicts(ctx->wc_ctx, local_abspath,
                                     depth,
                                     TRUE /* resolve_text */,
                                     "" /* resolve_prop (ALL props) */,
                                     TRUE /* resolve_tree */,
                                     conflict_choice,
+                                    ctx->conflict_func2,
+                                    ctx->conflict_baton2,
                                     ctx->cancel_func, ctx->cancel_baton,
                                     ctx->notify_func2, ctx->notify_baton2,
                                     pool));

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/blame.c Fri May 11 00:05:41 2012
@@ -427,7 +427,7 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *relative_url, *basecoll_url, *req_url;
+  const char *req_url;
   svn_error_t *err;
 
   blame_ctx = apr_pcalloc(pool, sizeof(*blame_ctx));
@@ -440,10 +440,10 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   blame_ctx->include_merged_revisions = include_merged_revisions;
   blame_ctx->done = FALSE;
 
-  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
-                                         NULL, session->session_url.path,
-                                         end, NULL, pool));
-  req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                      session, NULL /* conn */,
+                                      NULL /* url */, end,
+                                      pool, pool));
 
   handler = apr_pcalloc(pool, sizeof(*handler));
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/commit.c Fri May 11 00:05:41 2012
@@ -48,17 +48,18 @@
 
 /* Structure associated with a CHECKOUT request. */
 typedef struct checkout_context_t {
-
-  /* Record information about the checked-out resource.  */
-  const char *resource_url;
-
-  /* These four fields are used during the actual CHECKOUT. They will be
-     NULL for resources implicitly checked out (ie. an ancestor was
-     checked out).  */
+  /* The handler running the CHECKOUT.  */
   svn_ra_serf__handler_t *handler;
+
+  /* The pool for allocating RESOURCE_URL.  */
   apr_pool_t *result_pool;
+
+  /* The activity that will hold the checked-out resource.  */
   const char *activity_url;
 
+  /* The output:  */
+  const char *resource_url;
+
 } checkout_context_t;
 
 /* Baton passed back with the commit editor. */
@@ -84,7 +85,7 @@ typedef struct commit_context_t {
 
   /* HTTP v1 stuff (only valid when 'txn_url' is NULL) */
   const char *activity_url;      /* activity base URL... */
-  const checkout_context_t *baseline;  /* checkout for the baseline */
+  const char *baseline_url;      /* the working-baseline resource */
   const char *checked_in_url;    /* checked-in root to base CHECKOUTs from */
   const char *vcc_url;           /* vcc url */
 
@@ -162,9 +163,9 @@ typedef struct dir_context_t {
   apr_hash_t *changed_props;
   apr_hash_t *removed_props;
 
-  /* The checked out context for this directory.  May be NULL; if so
+  /* The checked-out working resource for this directory.  May be NULL; if so
      call checkout_dir() first.  */
-  checkout_context_t *checkout;
+  const char *working_url;
 
 } dir_context_t;
 
@@ -184,8 +185,8 @@ typedef struct file_context_t {
   const char *relpath;
   const char *name;
 
-  /* The checked out context for this file. */
-  checkout_context_t *checkout;
+  /* The checked-out working resource for this file. */
+  const char *working_url;
 
   /* The base revision of the file. */
   svn_revnum_t base_revision;
@@ -325,16 +326,78 @@ handle_checkout(serf_request_t *request,
   return err;
 }
 
+
+/* Using the HTTPv1 protocol, perform a CHECKOUT of NODE_URL within the
+   given COMMIT_CTX. The resulting working resource will be returned in
+   *WORKING_URL, allocated from RESULT_POOL. All temporary allocations
+   are performed in SCRATCH_POOL.
+
+   ### are these URLs actually repos relpath values? or fspath? or maybe
+   ### the abspath portion of the full URL.
+
+   This function operates synchronously.
+
+   Strictly speaking, we could perform "all" of the CHECKOUT requests
+   when the commit starts, and only block when we need a specific
+   answer. Or, at a minimum, send off these individual requests async
+   and block when we need the answer (eg PUT or PROPPATCH).
+
+   However: the investment to speed this up is not worthwhile, given
+   that CHECKOUT (and the related round trip) is completely obviated
+   in HTTPv2.
+*/
 static svn_error_t *
-checkout_dir(dir_context_t *dir)
+checkout_node(const char **working_url,
+              const commit_context_t *commit_ctx,
+              const char *node_url,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
+{
+  svn_ra_serf__handler_t handler = { 0 };
+  checkout_context_t checkout_ctx = { 0 };
+
+  /* HANDLER_POOL is the scratch pool since we don't need to remember
+     anything from the handler. We just want the working resource.  */
+  handler.handler_pool = scratch_pool;
+  handler.session = commit_ctx->session;
+  handler.conn = commit_ctx->conn;
+
+  checkout_ctx.handler = &handler;
+  checkout_ctx.result_pool = result_pool;
+  checkout_ctx.activity_url = commit_ctx->activity_url;
+
+  handler.body_delegate = create_checkout_body;
+  handler.body_delegate_baton = &checkout_ctx;
+  handler.body_type = "text/xml";
+
+  handler.response_handler = handle_checkout;
+  handler.response_baton = &checkout_ctx;
+
+  handler.method = "CHECKOUT";
+  handler.path = node_url;
+
+  SVN_ERR(svn_ra_serf__context_run_one(&handler, scratch_pool));
+
+  if (handler.sline.code != 201)
+    return svn_error_trace(return_response_err(&handler));
+
+  /* Already in the correct pool.  */
+  *working_url = checkout_ctx.resource_url;
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+checkout_dir(dir_context_t *dir,
+             apr_pool_t *scratch_pool)
 {
-  checkout_context_t *checkout_ctx;
-  svn_ra_serf__handler_t *handler;
   svn_error_t *err;
   dir_context_t *p_dir = dir;
   const char *checkout_url;
+  const char **working;
 
-  if (dir->checkout)
+  if (dir->working_url)
     {
       return SVN_NO_ERROR;
     }
@@ -346,67 +409,41 @@ checkout_dir(dir_context_t *dir)
       if (p_dir->added)
         {
           /* Implicitly checkout this dir now. */
-          dir->checkout = apr_pcalloc(dir->pool, sizeof(*dir->checkout));
-          dir->checkout->resource_url =
-            svn_path_url_add_component2(dir->parent_dir->checkout->resource_url,
-                                        dir->name, dir->pool);
-
+          dir->working_url = svn_path_url_add_component2(
+                                   dir->parent_dir->working_url,
+                                   dir->name, dir->pool);
           return SVN_NO_ERROR;
         }
       p_dir = p_dir->parent_dir;
     }
 
-  /* Checkout our directory into the activity URL now. */
-  handler = apr_pcalloc(dir->pool, sizeof(*handler));
-  handler->handler_pool = dir->pool;
-  handler->session = dir->commit->session;
-  handler->conn = dir->commit->conn;
-
-  checkout_ctx = apr_pcalloc(dir->pool, sizeof(*checkout_ctx));
-  checkout_ctx->handler = handler;
-  checkout_ctx->result_pool = dir->pool;
-  checkout_ctx->activity_url = dir->commit->activity_url;
-
   /* We could be called twice for the root: once to checkout the baseline;
    * once to checkout the directory itself if we need to do so.
    * Note: CHECKOUT_URL should live longer than HANDLER.
    */
-  if (!dir->parent_dir && !dir->commit->baseline)
+  if (!dir->parent_dir && !dir->commit->baseline_url)
     {
       checkout_url = dir->commit->vcc_url;
-      dir->commit->baseline = checkout_ctx;
+      working = &dir->commit->baseline_url;
     }
   else
     {
       checkout_url = dir->url;
-      dir->checkout = checkout_ctx;
+      working = &dir->working_url;
     }
 
-  handler->body_delegate = create_checkout_body;
-  handler->body_delegate_baton = checkout_ctx;
-  handler->body_type = "text/xml";
-
-  handler->response_handler = handle_checkout;
-  handler->response_baton = checkout_ctx;
-
-  handler->method = "CHECKOUT";
-  handler->path = checkout_url;
-
-  err = svn_ra_serf__context_run_one(handler, dir->pool);
+  /* Checkout our directory into the activity URL now. */
+  err = checkout_node(working, dir->commit, checkout_url,
+                      dir->pool, scratch_pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_FS_CONFLICT)
-        SVN_ERR_W(err, apr_psprintf(dir->pool,
+        SVN_ERR_W(err, apr_psprintf(scratch_pool,
                   _("Directory '%s' is out of date; try updating"),
-                  svn_dirent_local_style(dir->relpath, dir->pool)));
+                  svn_dirent_local_style(dir->relpath, scratch_pool)));
       return err;
     }
 
-  if (handler->sline.code != 201)
-    {
-      return svn_error_trace(return_response_err(handler));
-    }
-
   return SVN_NO_ERROR;
 }
 
@@ -424,16 +461,17 @@ checkout_dir(dir_context_t *dir)
  * BASE_REVISION, and set *CHECKED_IN_URL to the concatenation of that
  * with RELPATH.
  *
- * Allocate the result in POOL, and use POOL for temporary allocation.
+ * Allocate the result in RESULT_POOL, and use SCRATCH_POOL for
+ * temporary allocation.
  */
 static svn_error_t *
 get_version_url(const char **checked_in_url,
                 svn_ra_serf__session_t *session,
-                svn_ra_serf__connection_t *conn,
                 const char *relpath,
                 svn_revnum_t base_revision,
                 const char *parent_vsn_url,
-                apr_pool_t *pool)
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
   const char *root_checkout;
 
@@ -441,15 +479,16 @@ get_version_url(const char **checked_in_
     {
       const svn_string_t *current_version;
 
-      SVN_ERR(session->wc_callbacks->get_wc_prop(session->wc_callback_baton,
-                                                 relpath,
-                                                 SVN_RA_SERF__WC_CHECKED_IN_URL,
-                                                 &current_version, pool));
+      SVN_ERR(session->wc_callbacks->get_wc_prop(
+                session->wc_callback_baton,
+                relpath,
+                SVN_RA_SERF__WC_CHECKED_IN_URL,
+                &current_version, scratch_pool));
 
       if (current_version)
         {
           *checked_in_url =
-            svn_urlpath__canonicalize(current_version->data, pool);
+            svn_urlpath__canonicalize(current_version->data, result_pool);
           return SVN_NO_ERROR;
         }
     }
@@ -460,61 +499,50 @@ get_version_url(const char **checked_in_
     }
   else
     {
-      svn_ra_serf__propfind_context_t *propfind_ctx;
-      apr_hash_t *props;
       const char *propfind_url;
-
-      props = apr_hash_make(pool);
+      svn_ra_serf__connection_t *conn = session->conns[0];
 
       if (SVN_IS_VALID_REVNUM(base_revision))
         {
-          const char *bc_url, *bc_relpath;
-
           /* mod_dav_svn can't handle the "Label:" header that
              svn_ra_serf__deliver_props() is going to try to use for
              this lookup, so we'll do things the hard(er) way, by
              looking up the version URL from a resource in the
              baseline collection. */
-          SVN_ERR(svn_ra_serf__get_baseline_info(&bc_url, &bc_relpath,
-                                                 session, conn,
-                                                 session->session_url.path,
-                                                 base_revision, NULL, pool));
-          propfind_url = svn_path_url_add_component2(bc_url, bc_relpath, pool);
+          /* ### conn==NULL for session->conns[0]. same as CONN.  */
+          SVN_ERR(svn_ra_serf__get_stable_url(&propfind_url,
+                                              NULL /* latest_revnum */,
+                                              session, NULL /* conn */,
+                                              NULL /* url */, base_revision,
+                                              scratch_pool, scratch_pool));
         }
       else
         {
           propfind_url = session->session_url.path;
         }
 
-      /* ### switch to svn_ra_serf__retrieve_props  */
-      SVN_ERR(svn_ra_serf__deliver_props(&propfind_ctx, props, session, conn,
-                                         propfind_url, base_revision, "0",
-                                         checked_in_props, NULL, pool));
-      SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, session, pool));
-
-      /* We wouldn't get here if the url wasn't found (404), so the checked-in
-         property should have been set. */
-      root_checkout =
-          svn_ra_serf__get_ver_prop(props, propfind_url,
-                                    base_revision, "DAV:", "checked-in");
-
+      SVN_ERR(svn_ra_serf__fetch_dav_prop(&root_checkout,
+                                          conn, propfind_url, base_revision,
+                                          "checked-in",
+                                          scratch_pool, scratch_pool));
       if (!root_checkout)
         return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
                                  _("Path '%s' not present"),
                                  session->session_url.path);
 
-      root_checkout = svn_urlpath__canonicalize(root_checkout, pool);
+      root_checkout = svn_urlpath__canonicalize(root_checkout, scratch_pool);
     }
 
-  *checked_in_url = svn_path_url_add_component2(root_checkout, relpath, pool);
+  *checked_in_url = svn_path_url_add_component2(root_checkout, relpath,
+                                                result_pool);
 
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
-checkout_file(file_context_t *file)
+checkout_file(file_context_t *file,
+              apr_pool_t *scratch_pool)
 {
-  svn_ra_serf__handler_t *handler;
   svn_error_t *err;
   dir_context_t *parent_dir = file->parent_dir;
   const char *checkout_url;
@@ -527,61 +555,33 @@ checkout_file(file_context_t *file)
       if (parent_dir->added)
         {
           /* Implicitly checkout this file now. */
-          file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout));
-          file->checkout->resource_url =
-            svn_path_url_add_component2(parent_dir->checkout->resource_url,
-                                        svn_relpath_skip_ancestor(
-                                          parent_dir->relpath, file->relpath),
-                                        file->pool);
+          file->working_url = svn_path_url_add_component2(
+                                    parent_dir->working_url,
+                                    svn_relpath_skip_ancestor(
+                                      parent_dir->relpath, file->relpath),
+                                    file->pool);
           return SVN_NO_ERROR;
         }
       parent_dir = parent_dir->parent_dir;
     }
 
-  /* Checkout our file into the activity URL now. */
-  handler = apr_pcalloc(file->pool, sizeof(*handler));
-  handler->handler_pool = file->pool;
-  handler->session = file->commit->session;
-  handler->conn = file->commit->conn;
-
-  file->checkout = apr_pcalloc(file->pool, sizeof(*file->checkout));
-  file->checkout->handler = handler;
-  file->checkout->result_pool = file->pool;
-  file->checkout->activity_url = file->commit->activity_url;
-
   SVN_ERR(get_version_url(&checkout_url,
-                          file->commit->session, file->commit->conn,
+                          file->commit->session,
                           file->relpath, file->base_revision,
-                          NULL, handler->handler_pool));
-
-  handler->body_delegate = create_checkout_body;
-  handler->body_delegate_baton = file->checkout;
-  handler->body_type = "text/xml";
-
-  handler->response_handler = handle_checkout;
-  handler->response_baton = file->checkout;
-
-  handler->method = "CHECKOUT";
-  handler->path = checkout_url;
+                          NULL, scratch_pool, scratch_pool));
 
-  /* There's no need to wait here as we only need this when we start the
-   * PROPPATCH or PUT of the file.
-   */
-  err = svn_ra_serf__context_run_one(handler, file->pool);
+  /* Checkout our file into the activity URL now. */
+  err = checkout_node(&file->working_url, file->commit, checkout_url,
+                      file->pool, scratch_pool);
   if (err)
     {
       if (err->apr_err == SVN_ERR_FS_CONFLICT)
-        SVN_ERR_W(err, apr_psprintf(file->pool,
+        SVN_ERR_W(err, apr_psprintf(scratch_pool,
                   _("File '%s' is out of date; try updating"),
-                  svn_dirent_local_style(file->relpath, file->pool)));
+                  svn_dirent_local_style(file->relpath, scratch_pool)));
       return err;
     }
 
-  if (handler->sline.code != 201)
-    {
-      return svn_error_trace(return_response_err(handler));
-    }
-
   return SVN_NO_ERROR;
 }
 
@@ -1054,8 +1054,8 @@ setup_copy_file_headers(serf_bucket_t *h
 
   serf_bucket_headers_set(headers, "Destination", absolute_uri);
 
-  serf_bucket_headers_set(headers, "Depth", "0");
-  serf_bucket_headers_set(headers, "Overwrite", "T");
+  serf_bucket_headers_setn(headers, "Depth", "0");
+  serf_bucket_headers_setn(headers, "Overwrite", "T");
 
   return SVN_NO_ERROR;
 }
@@ -1079,19 +1079,18 @@ setup_copy_dir_headers(serf_bucket_t *he
   else
     {
       uri.path = (char *)svn_path_url_add_component2(
-                                    dir->parent_dir->checkout->resource_url,
+                                    dir->parent_dir->working_url,
                                     dir->name, pool);
     }
   absolute_uri = apr_uri_unparse(pool, &uri, 0);
 
   serf_bucket_headers_set(headers, "Destination", absolute_uri);
 
-  serf_bucket_headers_set(headers, "Depth", "infinity");
-  serf_bucket_headers_set(headers, "Overwrite", "T");
+  serf_bucket_headers_setn(headers, "Depth", "infinity");
+  serf_bucket_headers_setn(headers, "Overwrite", "T");
 
   /* Implicitly checkout this dir now. */
-  dir->checkout = apr_pcalloc(dir->pool, sizeof(*dir->checkout));
-  dir->checkout->resource_url = apr_pstrdup(dir->pool, uri.path);
+  dir->working_url = apr_pstrdup(dir->pool, uri.path);
 
   return SVN_NO_ERROR;
 }
@@ -1121,8 +1120,8 @@ setup_delete_headers(serf_bucket_t *head
           serf_bucket_headers_set(headers, "If", token_header);
 
           if (ctx->keep_locks)
-            serf_bucket_headers_set(headers, SVN_DAV_OPTIONS_HEADER,
-                                    SVN_DAV_OPTION_KEEP_LOCKS);
+            serf_bucket_headers_setn(headers, SVN_DAV_OPTIONS_HEADER,
+                                     SVN_DAV_OPTION_KEEP_LOCKS);
         }
     }
 
@@ -1361,19 +1360,12 @@ open_root(void *edit_baton,
     }
   else
     {
-      svn_ra_serf__options_context_t *opt_ctx;
       const char *activity_str;
 
-      SVN_ERR(svn_ra_serf__create_options_req(&opt_ctx, ctx->session,
-                                              ctx->session->conns[0],
-                                              ctx->session->session_url.path,
-                                              ctx->pool));
-
-      SVN_ERR(svn_ra_serf__context_run_wait(
-        svn_ra_serf__get_options_done_ptr(opt_ctx),
-        ctx->session, ctx->pool));
-
-      activity_str = svn_ra_serf__options_get_activity_collection(opt_ctx);
+      SVN_ERR(svn_ra_serf__v1_get_activity_collection(&activity_str,
+                                                      ctx->session->conns[0],
+                                                      ctx->pool,
+                                                      ctx->pool));
       if (!activity_str)
         return svn_error_create(SVN_ERR_RA_DAV_OPTIONS_REQ_FAILED, NULL,
                                 _("The OPTIONS response did not include the "
@@ -1434,15 +1426,15 @@ open_root(void *edit_baton,
       dir->removed_props = apr_hash_make(dir->pool);
 
       SVN_ERR(get_version_url(&dir->url, dir->commit->session,
-                              dir->commit->conn, dir->relpath,
+                              dir->relpath,
                               dir->base_revision, ctx->checked_in_url,
-                              dir->pool));
+                              dir->pool, dir->pool /* scratch_pool */));
       ctx->checked_in_url = dir->url;
 
       /* Checkout our root dir */
-      SVN_ERR(checkout_dir(dir));
+      SVN_ERR(checkout_dir(dir, dir->pool /* scratch_pool */));
 
-      proppatch_target = ctx->baseline->resource_url;
+      proppatch_target = ctx->baseline_url;
     }
 
 
@@ -1509,8 +1501,8 @@ delete_entry(const char *path,
   else
     {
       /* Ensure our directory has been checked out */
-      SVN_ERR(checkout_dir(dir));
-      delete_target = svn_path_url_add_component2(dir->checkout->resource_url,
+      SVN_ERR(checkout_dir(dir, pool /* scratch_pool */));
+      delete_target = svn_path_url_add_component2(dir->working_url,
                                                   svn_relpath_basename(path,
                                                                        NULL),
                                                   pool);
@@ -1612,12 +1604,12 @@ add_directory(const char *path,
   else
     {
       /* Ensure our parent is checked out. */
-      SVN_ERR(checkout_dir(parent));
+      SVN_ERR(checkout_dir(parent, dir->pool /* scratch_pool */));
 
       dir->url = svn_path_url_add_component2(parent->commit->checked_in_url,
                                              dir->name, dir->pool);
       mkcol_target = svn_path_url_add_component2(
-                               parent->checkout->resource_url,
+                               parent->working_url,
                                dir->name, dir->pool);
     }
 
@@ -1636,7 +1628,7 @@ add_directory(const char *path,
   else
     {
       apr_uri_t uri;
-      const char *rel_copy_path, *basecoll_url, *req_url;
+      const char *req_url;
 
       status = apr_uri_parse(dir->pool, dir->copy_path, &uri);
       if (status)
@@ -1646,13 +1638,12 @@ add_directory(const char *path,
                                    dir->copy_path);
         }
 
-      SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &rel_copy_path,
-                                             dir->commit->session,
-                                             dir->commit->conn,
-                                             uri.path, dir->copy_revision,
-                                             NULL, dir_pool));
-      req_url = svn_path_url_add_component2(basecoll_url, rel_copy_path,
-                                            dir->pool);
+      /* ### conn==NULL for session->conns[0]. same as commit->conn.  */
+      SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                          dir->commit->session,
+                                          NULL /* conn */,
+                                          uri.path, dir->copy_revision,
+                                          dir_pool, dir_pool));
 
       handler->method = "COPY";
       handler->path = req_url;
@@ -1722,9 +1713,10 @@ open_directory(const char *path,
   else
     {
       SVN_ERR(get_version_url(&dir->url,
-                              dir->commit->session, dir->commit->conn,
+                              dir->commit->session,
                               dir->relpath, dir->base_revision,
-                              dir->commit->checked_in_url, dir->pool));
+                              dir->commit->checked_in_url,
+                              dir->pool, dir->pool /* scratch_pool */));
     }
   *child_baton = dir;
 
@@ -1749,9 +1741,9 @@ change_dir_prop(void *dir_baton,
   else
     {
       /* Ensure we have a checked out dir. */
-      SVN_ERR(checkout_dir(dir));
+      SVN_ERR(checkout_dir(dir, pool /* scratch_pool */));
 
-      proppatch_target = dir->checkout->resource_url;
+      proppatch_target = dir->working_url;
     }
 
   name = apr_pstrdup(dir->pool, name);
@@ -1811,7 +1803,7 @@ close_directory(void *dir_baton,
         }
       else
         {
-          proppatch_ctx->path = dir->checkout->resource_url;
+          proppatch_ctx->path = dir->working_url;
         }
 
       SVN_ERR(proppatch_resource(proppatch_ctx, dir->commit, dir->pool));
@@ -1859,10 +1851,10 @@ add_file(const char *path,
   else
     {
       /* Ensure our parent directory has been checked out */
-      SVN_ERR(checkout_dir(dir));
+      SVN_ERR(checkout_dir(dir, new_file->pool /* scratch_pool */));
 
       new_file->url =
-        svn_path_url_add_component2(dir->checkout->resource_url,
+        svn_path_url_add_component2(dir->working_url,
                                     new_file->name, new_file->pool);
     }
 
@@ -1938,9 +1930,9 @@ open_file(const char *path,
   else
     {
       /* CHECKOUT the file into our activity. */
-      SVN_ERR(checkout_file(new_file));
+      SVN_ERR(checkout_file(new_file, new_file->pool /* scratch_pool */));
 
-      new_file->url = new_file->checkout->resource_url;
+      new_file->url = new_file->working_url;
     }
 
   *file_baton = new_file;
@@ -2026,7 +2018,7 @@ change_file_prop(void *file_baton,
 static svn_error_t *
 close_file(void *file_baton,
            const char *text_checksum,
-           apr_pool_t *pool)
+           apr_pool_t *scratch_pool)
 {
   file_context_t *ctx = file_baton;
   svn_boolean_t put_empty_file = FALSE;
@@ -2038,9 +2030,9 @@ close_file(void *file_baton,
     {
       svn_ra_serf__handler_t *handler;
       apr_uri_t uri;
-      const char *rel_copy_path, *basecoll_url, *req_url;
+      const char *req_url;
 
-      status = apr_uri_parse(pool, ctx->copy_path, &uri);
+      status = apr_uri_parse(scratch_pool, ctx->copy_path, &uri);
       if (status)
         {
           return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
@@ -2048,15 +2040,15 @@ close_file(void *file_baton,
                                    ctx->copy_path);
         }
 
-      SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &rel_copy_path,
-                                             ctx->commit->session,
-                                             ctx->commit->conn,
-                                             uri.path, ctx->copy_revision,
-                                             NULL, pool));
-      req_url = svn_path_url_add_component2(basecoll_url, rel_copy_path, pool);
+      /* ### conn==NULL for session->conns[0]. same as commit->conn.  */
+      SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                          ctx->commit->session,
+                                          NULL /* conn */,
+                                          uri.path, ctx->copy_revision,
+                                          scratch_pool, scratch_pool));
 
-      handler = apr_pcalloc(pool, sizeof(*handler));
-      handler->handler_pool = pool;
+      handler = apr_pcalloc(scratch_pool, sizeof(*handler));
+      handler->handler_pool = scratch_pool;
       handler->method = "COPY";
       handler->path = req_url;
       handler->conn = ctx->commit->conn;
@@ -2068,7 +2060,7 @@ close_file(void *file_baton,
       handler->header_delegate = setup_copy_file_headers;
       handler->header_delegate_baton = ctx;
 
-      SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
+      SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
       if (handler->sline.code != 201 && handler->sline.code != 204)
         {
@@ -2087,8 +2079,8 @@ close_file(void *file_baton,
     {
       svn_ra_serf__handler_t *handler;
 
-      handler = apr_pcalloc(pool, sizeof(*handler));
-      handler->handler_pool = pool;
+      handler = apr_pcalloc(scratch_pool, sizeof(*handler));
+      handler->handler_pool = scratch_pool;
       handler->method = "PUT";
       handler->path = ctx->url;
       handler->conn = ctx->commit->conn;
@@ -2113,7 +2105,7 @@ close_file(void *file_baton,
       handler->header_delegate = setup_put_headers;
       handler->header_delegate_baton = ctx;
 
-      SVN_ERR(svn_ra_serf__context_run_one(handler, pool));
+      SVN_ERR(svn_ra_serf__context_run_one(handler, scratch_pool));
 
       if (handler->sline.code != 204 && handler->sline.code != 201)
         {
@@ -2122,7 +2114,7 @@ close_file(void *file_baton,
     }
 
   if (ctx->svndiff)
-    SVN_ERR(svn_io_file_close(ctx->svndiff, pool));
+    SVN_ERR(svn_io_file_close(ctx->svndiff, scratch_pool));
 
   /* If we had any prop changes, push them via PROPPATCH. */
   if (apr_hash_count(ctx->changed_props) ||
@@ -2334,8 +2326,8 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
   svn_ra_serf__session_t *session = ra_session->priv;
   proppatch_context_t *proppatch_ctx;
   commit_context_t *commit;
-  const char *vcc_url, *proppatch_target, *ns;
-  apr_hash_t *props;
+  const char *proppatch_target;
+  const char *ns;
   svn_error_t *err;
 
   if (old_value_p)
@@ -2362,21 +2354,15 @@ svn_ra_serf__change_rev_prop(svn_ra_sess
     }
   else
     {
-      svn_ra_serf__propfind_context_t *propfind_ctx;
+      const char *vcc_url;
 
       SVN_ERR(svn_ra_serf__discover_vcc(&vcc_url, commit->session,
                                         commit->conn, pool));
 
-      props = apr_hash_make(pool);
-
-      /* ### switch to svn_ra_serf__retrieve_props  */
-      SVN_ERR(svn_ra_serf__deliver_props(&propfind_ctx, props, commit->session,
-                                         commit->conn, vcc_url, rev, "0",
-                                         checked_in_props, NULL, pool));
-      SVN_ERR(svn_ra_serf__wait_for_props(propfind_ctx, commit->session, pool));
-
-      proppatch_target = svn_ra_serf__get_ver_prop(props, vcc_url, rev,
-                                                   "DAV:", "href");
+      SVN_ERR(svn_ra_serf__fetch_dav_prop(&proppatch_target,
+                                          commit->conn, vcc_url, rev,
+                                          "href",
+                                          pool, pool));
     }
 
   if (strncmp(name, SVN_PROP_PREFIX, sizeof(SVN_PROP_PREFIX) - 1) == 0)

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/get_deleted_rev.c Fri May 11 00:05:41 2012
@@ -187,7 +187,7 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
   svn_ra_serf__session_t *ras = session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *relative_url, *basecoll_url, *req_url;
+  const char *req_url;
   svn_error_t *err;
 
   drev_ctx = apr_pcalloc(pool, sizeof(*drev_ctx));
@@ -198,11 +198,10 @@ svn_ra_serf__get_deleted_rev(svn_ra_sess
   drev_ctx->revision_deleted = revision_deleted;
   drev_ctx->done = FALSE;
 
-  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url,
-                                         ras, NULL, NULL, peg_revision, NULL,
-                                         pool));
-
-  req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                      ras, NULL /* conn */,
+                                      NULL /* url */, peg_revision,
+                                      pool, pool));
 
   parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
   parser_ctx->pool = pool;

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocations.c Fri May 11 00:05:41 2012
@@ -227,7 +227,7 @@ svn_ra_serf__get_locations(svn_ra_sessio
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *relative_url, *basecoll_url, *req_url;
+  const char *req_url;
   svn_error_t *err;
 
   loc_ctx = apr_pcalloc(pool, sizeof(*loc_ctx));
@@ -240,11 +240,10 @@ svn_ra_serf__get_locations(svn_ra_sessio
 
   *locations = loc_ctx->paths;
 
-  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
-                                         NULL, NULL, peg_revision, NULL,
-                                         pool));
-
-  req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                      session, NULL /* conn */,
+                                      NULL /* url */, peg_revision,
+                                      pool, pool));
 
   handler = apr_pcalloc(pool, sizeof(*handler));
 

Modified: subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c?rev=1336974&r1=1336973&r2=1336974&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c (original)
+++ subversion/branches/ev2-export/subversion/libsvn_ra_serf/getlocationsegments.c Fri May 11 00:05:41 2012
@@ -181,7 +181,7 @@ svn_ra_serf__get_location_segments(svn_r
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
   svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *relative_url, *basecoll_url, *req_url;
+  const char *req_url;
   svn_error_t *err;
 
   gls_ctx = apr_pcalloc(pool, sizeof(*gls_ctx));
@@ -195,10 +195,10 @@ svn_ra_serf__get_location_segments(svn_r
   gls_ctx->inside_report = FALSE;
   gls_ctx->done = FALSE;
 
-  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
-                                         NULL, NULL, peg_revision, NULL, pool));
-
-  req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool);
+  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                      session, NULL /* conn */,
+                                      NULL /* url */, peg_revision,
+                                      pool, pool));
 
   handler = apr_pcalloc(pool, sizeof(*handler));