You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2018/09/16 12:50:34 UTC

svn commit: r1840997 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/conflicts.c svn/conflict-callbacks.c

Author: stsp
Date: Sun Sep 16 12:50:34 2018
New Revision: 1840997

URL: http://svn.apache.org/viewvc?rev=1840997&view=rev
Log:
Improve the semantics of four public API resolver functions.

In all cases, the old APIs would raise an assertion failure if an unexpected
option was passed. This is bad API design since it forces clients to maintain
a static copy of the list of valid options. Furthermore, because we're
adding support for new options in future releases, we require API users
to keep this list updated when they update to a newer version of SVN.

The new versions of these APIs return NULL instead of asserting valid input.
This allows clients to simply pass in any option and check if that gives
a valid result.

Do not bother emulating the old behaviour; code written against the
guarantees of the old API will just keep working.

Make use of the new API versions in 'svn', which also serves as an
example of new API semantics are more friendly to API users.

Improve the API docstrings a little while here.

I am declaring the APIs added here as "New in 1.11" in hope that this
change will be backported to the recently created 1.11.x branch.

* subversion/include/svn_client.h
  (svn_client_conflict_option_get_moved_to_repos_relpath_candidates2,
  (svn_client_conflict_option_set_moved_to_repos_relpath): New.
  (svn_client_conflict_option_get_moved_to_repos_relpath_candidates,
  (svn_client_conflict_option_set_moved_to_repos_relpath): Deprecate.
  (svn_client_conflict_option_get_moved_to_abspath_candidates2,
  (svn_client_conflict_option_set_moved_to_abspath): New.
  (svn_client_conflict_option_get_moved_to_abspath_candidates,
  (svn_client_conflict_option_set_moved_to_abspath): Deprecate.

* subversion/libsvn_client/conflicts.c
  (svn_client_conflict_option_get_moved_to_repos_relpath_candidates,
  (svn_client_conflict_option_set_moved_to_repos_relpath): New.
  (svn_client_conflict_option_get_moved_to_repos_relpath_candidates,
  (svn_client_conflict_option_set_moved_to_repos_relpath): Implement
   as a wrapper around the new API.
  (svn_client_conflict_option_get_moved_to_abspath_candidates2,
  (svn_client_conflict_option_set_moved_to_abspath): New.
  (svn_client_conflict_option_get_moved_to_abspath_candidates,
  (svn_client_conflict_option_set_moved_to_abspath): Implement as a
   wrapper around the new API.

* subversion/svn/conflict-callbacks.c
  (build_tree_conflict_options): Remove a large list of options which are
   acceptable to old APIs. Call the new API and check its result instead.
  (find_conflict_option_with_repos_move_targets,
   find_conflict_option_with_working_copy_move_targets): New helper functions.
  (handle_tree_conflict): Simplify support of ambiguous moves by using new APIs.

Modified:
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/conflicts.c
    subversion/trunk/subversion/svn/conflict-callbacks.c

Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1840997&r1=1840996&r2=1840997&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Sun Sep 16 12:50:34 2018
@@ -4585,27 +4585,45 @@ svn_client_conflict_option_set_merged_pr
   const svn_string_t *merged_propval);
 
 /**
- * Get a list of possible repository paths which can be applied to the
- * svn_client_conflict_option_incoming_move_file_text_merge, or
- * svn_client_conflict_option_local_move_file_text_merge, or
- * svn_client_conflict_option_incoming_move_dir_merge resolution
- * @a option. (If a different option is passed in, this function will
- * raise an assertion failure.)
- *
- * In some situations, there can be multiple possible destinations for an
- * incoming move. One such situation is where a file was copied and moved
- * in the same revision: svn cp a b; svn mv a c; svn commit
+ * Get a list of possible repository paths which can be applied to @a option.
+ *
+ * In some situations, there can be multiple possible destinations for a move.
+ * One such situation is where a file was copied and moved in the same revision:
+ *   svn cp a b; svn mv a c; svn commit
  * When this move is merged elsewhere, both b and c will appear as valid move
  * destinations to the conflict resolver. To resolve such ambiguity, the client
  * may call this function to obtain a list of possible destinations the user
  * may choose from.
  *
+ * @a *possible_moved_to_repos_relpaths is set to NULL if the @a option does
+ * not support multiple move targets. API users may assume that only one option
+ * among those which can be applied to a conflict supports move targets.
+ *
  * The array is allocated in @a result_pool and will have "const char *"
  * elements pointing to strings also allocated in @a result_pool.
  * All paths are relpaths, and relative to the repository root.
  *
- * @see svn_client_conflict_option_set_moved_to_repos_relpath()
+ * @see svn_client_conflict_option_set_moved_to_repos_relpath2()
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_conflict_option_get_moved_to_repos_relpath_candidates2(
+  apr_array_header_t **possible_moved_to_repos_relpaths,
+  svn_client_conflict_option_t *option,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool);
+
+/**
+ * Get a list of possible repository paths which can be applied to the
+ * svn_client_conflict_option_incoming_move_file_text_merge, or the
+ * svn_client_conflict_option_incoming_move_dir_merge resolution @a option.
+ *
+ * In SVN 1.10, if a different option is passed in, this function will
+ * raise an assertion failure. Otherwise this function behaves just like
+ * svn_client_conflict_option_get_moved_to_repos_relpath_candidates2().
+ *
  * @since New in 1.10.
+ * @deprecated use svn_client_conflict_option_get_moved_to_repos_relpath_candidates2()
  */
 svn_error_t *
 svn_client_conflict_option_get_moved_to_repos_relpath_candidates(
@@ -4615,10 +4633,9 @@ svn_client_conflict_option_get_moved_to_
   apr_pool_t *scratch_pool);
 
 /**
- * Set the preferred moved target repository path for the
- * svn_client_conflict_option_incoming_move_file_text_merge or
- * svn_client_conflict_option_incoming_move_dir_merge resolution option.
- * 
+ * Set the preferred moved target repository path. If @a option is not
+ * applicable to a moved target repository path, do nothing.
+ *
  * @a preferred_move_target_idx must be a valid index into the list returned
  * by svn_client_conflict_option_get_moved_to_repos_relpath_candidates().
  * 
@@ -4627,7 +4644,23 @@ svn_client_conflict_option_get_moved_to_
  * svn_client_conflict_option_get_description(). Call these functions again
  * to get updated descriptions containing the newly selected move target.
  *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_conflict_option_set_moved_to_repos_relpath2(
+  svn_client_conflict_option_t *option,
+  int preferred_move_target_idx,
+  svn_client_ctx_t *ctx,
+  apr_pool_t *scratch_pool);
+
+/**
+ * Like svn_client_conflict_option_set_moved_to_repos_relpath2(), except
+ * that in SVN 1.10 it raises an assertion failure if an option other
+ * than svn_client_conflict_option_incoming_move_file_text_merge or
+ * svn_client_conflict_option_incoming_move_dir_merge is passed.
+ *
  * @since New in 1.10.
+ * @deprecated use svn_client_conflict_option_set_moved_to_repos_relpath2()
  */
 svn_error_t *
 svn_client_conflict_option_set_moved_to_repos_relpath(
@@ -4638,25 +4671,45 @@ svn_client_conflict_option_set_moved_to_
 
 /**
  * Get a list of possible moved-to abspaths in the working copy which can be
- * applied to the svn_client_conflict_option_incoming_move_file_text_merge,
- * svn_client_conflict_option_local_move_file_text_merge,
- * or svn_client_conflict_option_incoming_move_dir_merge resolution @a option.
- * (If a different option is passed in, this function will raise an assertion
- * failure.)
- *
- * All paths in the returned list correspond to the repository path which
- * is assumed to be the destination of the incoming move operation.
- * To support cases where this destination path is ambiguous, the client may
- * call svn_client_conflict_option_get_moved_to_repos_relpath_candidates()
- * before calling this function to let the user select a repository path first.
+ * applied to @a option.
+ *
+ * All working copy paths in the returned list correspond to one repository
+ * path which is be one of the possible destinations of a move operation.
+ * More than one repository-side move target candidate may exist; call
+ * svn_client_conflict_option_get_moved_to_repos_relpath_candidates() before
+ * calling this function to let the user select a repository path first.
+ * Otherwise, one of the repository-side paths will be selected internally.
  * 
+ * @a *possible_moved_to_abspaths is set to NULL if the @a option does not
+ * support multiple move targets. API users may assume that only one option
+ * among those which can be applied to a conflict supports move targets.
+ *
  * If no possible moved-to paths can be found, return an empty array.
  * This doesn't mean that no move happened in the repository. It is possible
  * that the move destination is outside the scope of the current working copy,
  * for example, in which case the conflict must be resolved in some other way.
  *
- * @see svn_client_conflict_option_set_moved_to_abspath()
+ * @see svn_client_conflict_option_set_moved_to_abspath2()
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_conflict_option_get_moved_to_abspath_candidates2(
+  apr_array_header_t **possible_moved_to_abspaths,
+  svn_client_conflict_option_t *option,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool);
+
+/**
+ * Get a list of possible moved-to abspaths in the working copy which can be
+ * svn_client_conflict_option_incoming_move_file_text_merge, or the
+ * svn_client_conflict_option_incoming_move_dir_merge resolution @a option.
+ *
+ * In SVN 1.10, if a different option is passed in, this function will
+ * raise an assertion failure. Otherwise this function behaves just like
+ * svn_client_conflict_option_get_moved_to_abspath_candidates2().
+ *
  * @since New in 1.10.
+ * @deprecated use svn_client_conflict_option_get_moved_to_abspath_candidates2()
  */
 svn_error_t *
 svn_client_conflict_option_get_moved_to_abspath_candidates(
@@ -4666,15 +4719,34 @@ svn_client_conflict_option_get_moved_to_
   apr_pool_t *scratch_pool);
 
 /**
- * Set the preferred moved target abspath for the
- * svn_client_conflict_option_incoming_move_file_text_merge or
- * svn_client_conflict_option_local_move_file_text_merge or
- * svn_client_conflict_option_incoming_move_dir_merge resolution option.
+ * Set the preferred moved target working copy path. If @a option is not
+ * applicable to a moved target working copy path, do nothing.
  * 
  * @a preferred_move_target_idx must be a valid index into the list
- * returned by svn_client_conflict_option_get_moved_to_abspath_candidates().
+ * returned by svn_client_conflict_option_get_moved_to_abspath_candidates2().
  * 
+ * This function can be called multiple times.
+ * It affects the output of svn_client_conflict_tree_get_description() and
+ * svn_client_conflict_option_get_description(). Call these functions again
+ * to get updated descriptions containing the newly selected move target.
+ *
+ * @since New in 1.11.
+ */
+svn_error_t *
+svn_client_conflict_option_set_moved_to_abspath2(
+  svn_client_conflict_option_t *option,
+  int preferred_move_target_idx,
+  svn_client_ctx_t *ctx,
+  apr_pool_t *scratch_pool);
+
+/**
+ * Like svn_client_conflict_option_set_moved_to_abspath2(), except that
+ * in SVN 1.10 this function raises an assertion failure if an option
+ * other than svn_client_conflict_option_incoming_move_file_text_merge or
+ * svn_client_conflict_option_incoming_move_dir_merge is passed.
+ *
  * @since New in 1.10.
+ * @deprecated use svn_client_conflict_option_set_moved_to_abspath2()
  */
 svn_error_t *
 svn_client_conflict_option_set_moved_to_abspath(

Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1840997&r1=1840996&r2=1840997&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Sun Sep 16 12:50:34 2018
@@ -10527,7 +10527,7 @@ get_repos_relpath_candidates(
 }
 
 svn_error_t *
-svn_client_conflict_option_get_moved_to_repos_relpath_candidates(
+svn_client_conflict_option_get_moved_to_repos_relpath_candidates2(
   apr_array_header_t **possible_moved_to_repos_relpaths,
   svn_client_conflict_option_t *option,
   apr_pool_t *result_pool,
@@ -10538,17 +10538,20 @@ svn_client_conflict_option_get_moved_to_
   svn_wc_operation_t operation;
   svn_wc_conflict_action_t incoming_change;
   svn_wc_conflict_reason_t local_change;
+  svn_client_conflict_option_id_t id;
 
-  SVN_ERR_ASSERT(svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_local_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_dir_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_dir_merge);
+  id = svn_client_conflict_option_get_id(option);
+  if (id != svn_client_conflict_option_incoming_move_file_text_merge &&
+      id != svn_client_conflict_option_incoming_move_dir_merge &&
+      id != svn_client_conflict_option_local_move_file_text_merge &&
+      id != svn_client_conflict_option_local_move_dir_merge &&
+      id != svn_client_conflict_option_sibling_move_file_text_merge &&
+      id != svn_client_conflict_option_sibling_move_dir_merge)
+    {
+      /* We cannot operate on this option. */
+      *possible_moved_to_repos_relpaths = NULL;
+      return SVN_NO_ERROR;
+    }
 
   victim_abspath = svn_client_conflict_get_local_abspath(conflict);
   operation = svn_client_conflict_get_operation(conflict);
@@ -10595,6 +10598,22 @@ svn_client_conflict_option_get_moved_to_
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_client_conflict_option_get_moved_to_repos_relpath_candidates(
+  apr_array_header_t **possible_moved_to_repos_relpaths,
+  svn_client_conflict_option_t *option,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool)
+{
+  /* The only difference to API version 2 is an assertion failure if
+   * an unexpected option is passed.
+   * We do not emulate this old behaviour since clients written against
+   * the previous API will just keep working. */
+  return svn_error_trace(
+    svn_client_conflict_option_get_moved_to_repos_relpath_candidates2(
+      possible_moved_to_repos_relpaths, option, result_pool, scratch_pool));
+}
+
 static svn_error_t *
 set_wc_move_target(const char **new_hash_key,
                    apr_hash_t *wc_move_targets,
@@ -10646,7 +10665,7 @@ set_wc_move_target(const char **new_hash
 }
 
 svn_error_t *
-svn_client_conflict_option_set_moved_to_repos_relpath(
+svn_client_conflict_option_set_moved_to_repos_relpath2(
   svn_client_conflict_option_t *option,
   int preferred_move_target_idx,
   svn_client_ctx_t *ctx,
@@ -10657,17 +10676,16 @@ svn_client_conflict_option_set_moved_to_
   svn_wc_operation_t operation;
   svn_wc_conflict_action_t incoming_change;
   svn_wc_conflict_reason_t local_change;
+  svn_client_conflict_option_id_t id;
 
-  SVN_ERR_ASSERT(svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_local_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_dir_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_dir_merge);
+  id = svn_client_conflict_option_get_id(option);
+  if (id != svn_client_conflict_option_incoming_move_file_text_merge &&
+      id != svn_client_conflict_option_incoming_move_dir_merge &&
+      id != svn_client_conflict_option_local_move_file_text_merge &&
+      id != svn_client_conflict_option_local_move_dir_merge &&
+      id != svn_client_conflict_option_sibling_move_file_text_merge &&
+      id != svn_client_conflict_option_sibling_move_dir_merge)
+    return SVN_NO_ERROR; /* We cannot operate on this option. Nothing to do. */
 
   victim_abspath = svn_client_conflict_get_local_abspath(conflict);
   operation = svn_client_conflict_get_operation(conflict);
@@ -10732,7 +10750,23 @@ svn_client_conflict_option_set_moved_to_
 }
 
 svn_error_t *
-svn_client_conflict_option_get_moved_to_abspath_candidates(
+svn_client_conflict_option_set_moved_to_repos_relpath(
+  svn_client_conflict_option_t *option,
+  int preferred_move_target_idx,
+  svn_client_ctx_t *ctx,
+  apr_pool_t *scratch_pool)
+{
+  /* The only difference to API version 2 is an assertion failure if
+   * an unexpected option is passed.
+   * We do not emulate this old behaviour since clients written against
+   * the previous API will just keep working. */
+  return svn_error_trace(
+    svn_client_conflict_option_set_moved_to_repos_relpath2(option,
+      preferred_move_target_idx, ctx, scratch_pool));
+}
+
+svn_error_t *
+svn_client_conflict_option_get_moved_to_abspath_candidates2(
   apr_array_header_t **possible_moved_to_abspaths,
   svn_client_conflict_option_t *option,
   apr_pool_t *result_pool,
@@ -10744,17 +10778,20 @@ svn_client_conflict_option_get_moved_to_
   svn_wc_conflict_action_t incoming_change;
   svn_wc_conflict_reason_t local_change;
   int i;
+  svn_client_conflict_option_id_t id;
 
-  SVN_ERR_ASSERT(svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_local_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_dir_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_dir_merge);
+  id = svn_client_conflict_option_get_id(option);
+  if (id != svn_client_conflict_option_incoming_move_file_text_merge &&
+      id != svn_client_conflict_option_incoming_move_dir_merge &&
+      id != svn_client_conflict_option_local_move_file_text_merge &&
+      id != svn_client_conflict_option_local_move_dir_merge &&
+      id != svn_client_conflict_option_sibling_move_file_text_merge &&
+      id != svn_client_conflict_option_sibling_move_dir_merge)
+    {
+      /* We cannot operate on this option. */
+      *possible_moved_to_abspaths = NULL;
+      return NULL;
+    }
 
   victim_abspath = svn_client_conflict_get_local_abspath(conflict);
   operation = svn_client_conflict_get_operation(conflict);
@@ -10848,7 +10885,23 @@ svn_client_conflict_option_get_moved_to_
 }
 
 svn_error_t *
-svn_client_conflict_option_set_moved_to_abspath(
+svn_client_conflict_option_get_moved_to_abspath_candidates(
+  apr_array_header_t **possible_moved_to_abspaths,
+  svn_client_conflict_option_t *option,
+  apr_pool_t *result_pool,
+  apr_pool_t *scratch_pool)
+{
+  /* The only difference to API version 2 is an assertion failure if
+   * an unexpected option is passed.
+   * We do not emulate this old behaviour since clients written against
+   * the previous API will just keep working. */
+  return svn_error_trace(
+    svn_client_conflict_option_get_moved_to_abspath_candidates2(
+      possible_moved_to_abspaths, option, result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_client_conflict_option_set_moved_to_abspath2(
   svn_client_conflict_option_t *option,
   int preferred_move_target_idx,
   svn_client_ctx_t *ctx,
@@ -10859,17 +10912,16 @@ svn_client_conflict_option_set_moved_to_
   svn_wc_operation_t operation;
   svn_wc_conflict_action_t incoming_change;
   svn_wc_conflict_reason_t local_change;
+  svn_client_conflict_option_id_t id;
 
-  SVN_ERR_ASSERT(svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_local_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_incoming_move_dir_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_file_text_merge ||
-                 svn_client_conflict_option_get_id(option) ==
-                 svn_client_conflict_option_sibling_move_dir_merge);
+  id = svn_client_conflict_option_get_id(option);
+  if (id != svn_client_conflict_option_incoming_move_file_text_merge &&
+      id != svn_client_conflict_option_incoming_move_dir_merge &&
+      id != svn_client_conflict_option_local_move_file_text_merge &&
+      id != svn_client_conflict_option_local_move_dir_merge &&
+      id != svn_client_conflict_option_sibling_move_file_text_merge &&
+      id != svn_client_conflict_option_sibling_move_dir_merge)
+    return NULL; /* We cannot operate on this option. Nothing to do. */
 
   victim_abspath = svn_client_conflict_get_local_abspath(conflict);
   operation = svn_client_conflict_get_operation(conflict);
@@ -10990,6 +11042,22 @@ svn_client_conflict_option_set_moved_to_
 }
 
 svn_error_t *
+svn_client_conflict_option_set_moved_to_abspath(
+  svn_client_conflict_option_t *option,
+  int preferred_move_target_idx,
+  svn_client_ctx_t *ctx,
+  apr_pool_t *scratch_pool)
+{
+  /* The only difference to API version 2 is an assertion failure if
+   * an unexpected option is passed.
+   * We do not emulate this old behaviour since clients written against
+   * the previous API will just keep working. */
+  return svn_error_trace(
+    svn_client_conflict_option_set_moved_to_abspath2(option,
+      preferred_move_target_idx, ctx, scratch_pool));
+}
+
+svn_error_t *
 svn_client_conflict_tree_get_resolution_options(apr_array_header_t **options,
                                                 svn_client_conflict_t *conflict,
                                                 svn_client_ctx_t *ctx,

Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1840997&r1=1840996&r2=1840997&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Sun Sep 16 12:50:34 2018
@@ -1534,21 +1534,16 @@ build_tree_conflict_options(
           id != svn_client_conflict_option_accept_current_wc_state)
         *all_options_are_dumb = FALSE;
 
-      if (id == svn_client_conflict_option_incoming_move_file_text_merge ||
-          id == svn_client_conflict_option_incoming_move_dir_merge ||
-          id == svn_client_conflict_option_local_move_file_text_merge ||
-          id == svn_client_conflict_option_local_move_dir_merge ||
-          id == svn_client_conflict_option_sibling_move_file_text_merge ||
-          id == svn_client_conflict_option_sibling_move_dir_merge)
-        {
+        if (*possible_moved_to_repos_relpaths == NULL)
           SVN_ERR(
-            svn_client_conflict_option_get_moved_to_repos_relpath_candidates(
+            svn_client_conflict_option_get_moved_to_repos_relpath_candidates2(
               possible_moved_to_repos_relpaths, builtin_option,
               result_pool, iterpool));
-          SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates(
+
+        if (*possible_moved_to_abspaths == NULL)
+          SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates2(
                     possible_moved_to_abspaths, builtin_option,
                     result_pool, iterpool));
-        }
     }
 
   svn_pool_destroy(iterpool);
@@ -1679,6 +1674,69 @@ prompt_move_target_path(int *preferred_m
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+find_conflict_option_with_repos_move_targets(
+  svn_client_conflict_option_t **option_with_move_targets,
+  apr_array_header_t *options,
+  apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+  apr_array_header_t *possible_moved_to_repos_relpaths = NULL;
+  
+  *option_with_move_targets = NULL;
+
+  for (i = 0; i < options->nelts; i++)
+    {
+      svn_client_conflict_option_t *option;
+
+      svn_pool_clear(iterpool);
+      option = APR_ARRAY_IDX(options, i, svn_client_conflict_option_t *);
+      SVN_ERR(svn_client_conflict_option_get_moved_to_repos_relpath_candidates2(
+        &possible_moved_to_repos_relpaths, option, iterpool, iterpool));
+      if (possible_moved_to_repos_relpaths)
+        {
+          *option_with_move_targets = option;
+          break;
+        }
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+find_conflict_option_with_working_copy_move_targets(
+  svn_client_conflict_option_t **option_with_move_targets,
+  apr_array_header_t *options,
+  apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+  apr_array_header_t *possible_moved_to_abspaths = NULL;
+  
+  *option_with_move_targets = NULL;
+
+  for (i = 0; i < options->nelts; i++)
+    {
+      svn_client_conflict_option_t *option;
+
+      svn_pool_clear(iterpool);
+      option = APR_ARRAY_IDX(options, i, svn_client_conflict_option_t *);
+      SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates2(
+              &possible_moved_to_abspaths, option, scratch_pool,
+              iterpool));
+      if (possible_moved_to_abspaths)
+        {
+          *option_with_move_targets = option;
+          break;
+        }
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Ask the user what to do about the tree conflict described by CONFLICT
  * and either resolve the conflict accordingly or postpone resolution.
  * SCRATCH_POOL is used for temporary allocations. */
@@ -1806,7 +1864,7 @@ handle_tree_conflict(svn_boolean_t *reso
         {
           int preferred_move_target_idx;
           apr_array_header_t *options;
-          svn_client_conflict_option_t *conflict_option;
+          svn_client_conflict_option_t *option;
 
           SVN_ERR(prompt_move_target_path(&preferred_move_target_idx,
                                           possible_moved_to_repos_relpaths,
@@ -1819,45 +1877,12 @@ handle_tree_conflict(svn_boolean_t *reso
                                                                   ctx,
                                                                   iterpool,
                                                                   iterpool));
-          conflict_option =
-            svn_client_conflict_option_find_by_id( 
-              options,
-              svn_client_conflict_option_incoming_move_file_text_merge);
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options, svn_client_conflict_option_incoming_move_dir_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options, svn_client_conflict_option_local_move_file_text_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options, svn_client_conflict_option_local_move_dir_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options, svn_client_conflict_option_sibling_move_file_text_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options, svn_client_conflict_option_sibling_move_dir_merge);
-            }
-          if (conflict_option)
+          SVN_ERR(find_conflict_option_with_repos_move_targets(
+            &option, options, iterpool));
+          if (option)
             {
-              SVN_ERR(svn_client_conflict_option_set_moved_to_repos_relpath(
-                        conflict_option, preferred_move_target_idx,
-                        ctx, iterpool));
+              SVN_ERR(svn_client_conflict_option_set_moved_to_repos_relpath2(
+                        option, preferred_move_target_idx, ctx, iterpool));
               repos_move_target_chosen = TRUE;
               wc_move_target_chosen = FALSE;
 
@@ -1883,7 +1908,7 @@ handle_tree_conflict(svn_boolean_t *reso
         {
           int preferred_move_target_idx;
           apr_array_header_t *options;
-          svn_client_conflict_option_t *conflict_option;
+          svn_client_conflict_option_t *option;
 
           SVN_ERR(prompt_move_target_path(&preferred_move_target_idx,
                                            possible_moved_to_abspaths, TRUE,
@@ -1895,50 +1920,12 @@ handle_tree_conflict(svn_boolean_t *reso
                                                                   ctx,
                                                                   iterpool,
                                                                   iterpool));
-          conflict_option =
-            svn_client_conflict_option_find_by_id( 
-              options,
-              svn_client_conflict_option_incoming_move_file_text_merge);
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options,
-                  svn_client_conflict_option_local_move_file_text_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options,
-                  svn_client_conflict_option_local_move_dir_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options,
-                  svn_client_conflict_option_sibling_move_file_text_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options,
-                  svn_client_conflict_option_sibling_move_dir_merge);
-            }
-          if (conflict_option == NULL)
-            {
-              conflict_option =
-                svn_client_conflict_option_find_by_id( 
-                  options, svn_client_conflict_option_incoming_move_dir_merge);
-            }
-
-          if (conflict_option)
+          SVN_ERR(find_conflict_option_with_working_copy_move_targets(
+            &option, options, iterpool));
+          if (option)
             {
-              SVN_ERR(svn_client_conflict_option_set_moved_to_abspath(
-                        conflict_option, preferred_move_target_idx, ctx,
-                        iterpool));
+              SVN_ERR(svn_client_conflict_option_set_moved_to_abspath2(
+                        option, preferred_move_target_idx, ctx, iterpool));
               wc_move_target_chosen = TRUE;
 
               /* Update option description. */