Modified: subversion/branches/authzperf/subversion/libsvn_client/conflicts.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_client/conflicts.c?rev=1764707&r1=1764706&r2=1764707&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_client/conflicts.c 
(original)
+++ subversion/branches/authzperf/subversion/libsvn_client/conflicts.c Thu Oct 
13 15:25:15 2016
@@ -38,6 +38,9 @@
 #include "svn_hash.h"
 #include "svn_sorts.h"
 #include "client.h"
+
+#include "private/svn_diff_tree.h"
+#include "private/svn_ra_private.h"
 #include "private/svn_sorts_private.h"
 #include "private/svn_token.h"
 #include "private/svn_wc_private.h"
@@ -53,6 +56,7 @@
 typedef svn_error_t *(*tree_conflict_get_description_func_t)(
   const char **change_description,
   svn_client_conflict_t *conflict,
+  svn_client_ctx_t *ctx,
   apr_pool_t *result_pool,
   apr_pool_t *scratch_pool);
 
@@ -60,16 +64,16 @@ typedef svn_error_t *(*tree_conflict_get
  * This function may contact the repository. */
 typedef svn_error_t *(*tree_conflict_get_details_func_t)(
   svn_client_conflict_t *conflict,
+  svn_client_ctx_t *ctx,
   apr_pool_t *scratch_pool);
 
 struct svn_client_conflict_t
 {
   const char *local_abspath;
-  svn_client_ctx_t *ctx;
   apr_hash_t *prop_conflicts;
 
   /* Indicate which options were chosen to resolve a text or tree conflict
-   * on the conflited node. */
+   * on the conflicted node. */
   svn_client_conflict_option_id_t resolution_text;
   svn_client_conflict_option_id_t resolution_tree;
 
@@ -112,6 +116,7 @@ struct svn_client_conflict_t
 typedef svn_error_t *(*conflict_option_resolve_func_t)(
   svn_client_conflict_option_t *option,
   svn_client_conflict_t *conflict,
+  svn_client_ctx_t *ctx,
   apr_pool_t *scratch_pool);
 
 struct svn_client_conflict_option_t
@@ -122,6 +127,9 @@ struct svn_client_conflict_option_t
   svn_client_conflict_t *conflict;
   conflict_option_resolve_func_t do_resolve_func;
 
+  /* The pool this option was allocated from. */
+  apr_pool_t *pool;
+
   /* Data which is specific to particular conflicts and options. */
   union {
     struct {
@@ -235,49 +243,60 @@ static const svn_token_map_t map_conflic
 };
 
 /* Describes a server-side move (really a copy+delete within the same
- * revision) which was identified by scanning the revision log. */
+ * revision) which was identified by scanning the revision log.
+ * This structure can represent one or more "chains" of moves, i.e.
+ * multiple move operations which occurred across a range of revisions. */
 struct repos_move_info {
-  /* The repository relpath the node was moved from. */
-  const char *moved_from_repos_relpath;
-
-  /* The repository relpath the node was moved to. */
-  const char *moved_to_repos_relpath;
- 
   /* The revision in which this move was committed. */
   svn_revnum_t rev;
 
   /* The author who commited the revision in which this move was committed. */
   const char *rev_author;
 
+  /* The repository relpath the node was moved from in this revision. */
+  const char *moved_from_repos_relpath;
+
+  /* The repository relpath the node was moved to in this revision. */
+  const char *moved_to_repos_relpath;
+
   /* The copyfrom revision of the moved-to path. */
   svn_revnum_t copyfrom_rev;
 
-  /* Prev and next pointers. NULL if no prior or next move exists. */
+  /* Prev pointer. NULL if no prior move exists in the chain. */
   struct repos_move_info *prev;
-  struct repos_move_info *next;
+
+  /* An array of struct repos_move_info * elements, each representing
+   * a possible way forward in the move chain. NULL if no next move
+   * exists in this chain. If the deleted node was copied only once in
+   * this revision, then this array has only one element and the move
+   * chain does not fork. But if this revision contains multiple copies of
+   * the deleted node, each of these copies appears as an element of this
+   * array, and each element represents a different path the next move
+   * might have taken. */
+  apr_array_header_t *next;
 };
 
-/* Set *RELATED to true if the deleted node at repository relpath
- * DELETED_REPOS_RELPATH@DELETED_REV is ancestrally related to the node at
- * repository relpath COPYFROM_PATH@COPYFROM_REV, else set it to false. */
+/* Set *RELATED to true if the deleted node DELETED_REPOS_RELPATH@DELETED_REV
+ * is an ancestor of the copied node COPYFROM_PATH@COPYFROM_REV.
+ * If CHECK_LAST_CHANGED_REV is non-zero, also ensure that the copied node
+ * is a copy of the deleted node's last-changed revision's content, rather
+ * than a copy of some older content. If it's not, set *RELATED to false. */
 static svn_error_t *
 check_move_ancestry(svn_boolean_t *related,
+                    svn_ra_session_t *ra_session,
                     const char *repos_root_url,
                     const char *deleted_repos_relpath,
                     svn_revnum_t deleted_rev,
                     const char *copyfrom_path,
                     svn_revnum_t copyfrom_rev,
-                    svn_client_ctx_t *ctx,
+                    svn_boolean_t check_last_changed_rev,
                     apr_pool_t *scratch_pool)
 {
   apr_hash_t *locations;
   const char *deleted_url;
   const char *deleted_location;
-  svn_ra_session_t *ra_session;
-  const char *corrected_url;
   apr_array_header_t *location_revisions;
-
-  *related = FALSE;
+  const char *old_session_url;
 
   location_revisions = apr_array_make(scratch_pool, 1, sizeof(svn_revnum_t));
   APR_ARRAY_PUSH(location_revisions, svn_revnum_t) = copyfrom_rev;
@@ -286,11 +305,8 @@ check_move_ancestry(svn_boolean_t *relat
                                                  deleted_repos_relpath,
                                                  NULL),
                                      scratch_pool);
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
-                                               deleted_url, NULL,
-                                               NULL, FALSE, FALSE,
-                                               ctx, scratch_pool,
-                                               scratch_pool));
+  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+                                            deleted_url, scratch_pool));
   SVN_ERR(svn_ra_get_locations(ra_session, &locations, "",
                                deleted_rev - 1, location_revisions,
                                scratch_pool));
@@ -301,9 +317,34 @@ check_move_ancestry(svn_boolean_t *relat
     {
       if (deleted_location[0] == '/')
         deleted_location++;
-      *related = (strcmp(deleted_location, copyfrom_path) == 0);
+      if (strcmp(deleted_location, copyfrom_path) != 0)
+        {
+          *related = FALSE;
+          return SVN_NO_ERROR;
+        }
+    }
+  else
+    {
+      *related = FALSE;
+      return SVN_NO_ERROR;
+    }
+
+  if (check_last_changed_rev)
+    {
+      svn_dirent_t *dirent;
+
+      /* Verify that copyfrom_rev >= last-changed revision of the
+       * deleted node. */
+      SVN_ERR(svn_ra_stat(ra_session, "", deleted_rev - 1, &dirent,
+                          scratch_pool));
+      if (dirent == NULL || copyfrom_rev < dirent->created_rev)
+        {
+          *related = FALSE;
+          return SVN_NO_ERROR;
+        }
     }
 
+  *related = TRUE;
   return SVN_NO_ERROR;
 }
 
@@ -314,15 +355,16 @@ struct copy_info {
 };
 
 /* Update MOVES_TABLE and MOVED_PATHS based on information from
- * revision data in LOG_ENTRY, COPIES, and DELETED_PATHS. */
+ * revision data in LOG_ENTRY, COPIES, and DELETED_PATHS.
+ * Use RA_SESSION to perform the necessary requests. */
 static svn_error_t *
-find_moves_in_revision(apr_hash_t *moves_table,
+find_moves_in_revision(svn_ra_session_t *ra_session,
+                       apr_hash_t *moves_table,
                        apr_hash_t *moved_paths,
                        svn_log_entry_t *log_entry,
                        apr_hash_t *copies,
                        apr_array_header_t *deleted_paths,
                        const char *repos_root_url,
-                       svn_client_ctx_t *ctx,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
@@ -364,20 +406,15 @@ find_moves_in_revision(apr_hash_t *moves
            * from revision log_entry->revision-1 (where the deleted node is
            * guaranteed to exist) to the copyfrom-revision, we must end up
            * at the copyfrom-path. */
-          SVN_ERR(check_move_ancestry(&related, repos_root_url,
+          SVN_ERR(check_move_ancestry(&related, ra_session, repos_root_url,
                                       deleted_repos_relpath,
                                       log_entry->revision,
                                       copy->copyfrom_path,
                                       copy->copyfrom_rev,
-                                      ctx, iterpool));
+                                      TRUE, iterpool));
           if (!related)
             continue;
 
-          /* ### TODO:
-           * If the node was not copied from the most recent last-changed
-           * revision of the deleted node, this is not a move but a
-           * "copy from the past + delete". */
-
           /* Remember details of this move. */
           move = apr_pcalloc(result_pool, sizeof(*move));
           move->moved_from_repos_relpath = apr_pstrdup(result_pool,
@@ -398,18 +435,23 @@ find_moves_in_revision(apr_hash_t *moves
               /* Tracing back history of the delete-half of the next move
                * to the copyfrom-revision of the prior move we must end up
                * at the delete-half of the prior move. */
-              SVN_ERR(check_move_ancestry(&related, repos_root_url,
+              SVN_ERR(check_move_ancestry(&related, ra_session, repos_root_url,
                                           next_move->moved_from_repos_relpath,
                                           next_move->rev,
                                           move->moved_from_repos_relpath,
                                           move->copyfrom_rev,
-                                          ctx, iterpool));
+                                          FALSE, iterpool));
               if (related)
                 {
                   SVN_ERR_ASSERT(move->rev < next_move->rev);
 
                   /* Prepend this move to the linked list. */
-                  move->next = next_move;
+                  if (move->next == NULL)
+                    move->next = apr_array_make(
+                                   result_pool, 1,
+                                   sizeof (struct repos_move_info *));
+                  APR_ARRAY_PUSH(move->next,
+                                 struct repos_move_info *) = next_move;
                   next_move->prev = move;
                 }
             }
@@ -445,6 +487,7 @@ struct find_deleted_rev_baton
   const char *repos_root_url;
   const char *repos_uuid;
   svn_client_ctx_t *ctx;
+  const char *victim_abspath; /* for notifications */
 
   /* Variables below are results for the caller of svn_ra_get_log2(). */
   svn_revnum_t deleted_rev;
@@ -500,14 +543,50 @@ struct find_deleted_rev_baton
   /* Temporary map of moved paths to struct repos_move_info.
    * Used to link multiple moves of the same node across revisions. */
   apr_hash_t *moved_paths;
+
+  /* Extra RA session that can be used to make additional requests. */
+  svn_ra_session_t *extra_ra_session;
 };
 
+/* Find the youngest common ancestor of REPOS_RELPATH1@PEG_REV1 and
+ * REPOS_RELPATH2@PEG_REV2. Return the result in *YCA_LOC.
+ * Set *YCA_LOC to NULL if no common ancestor exists. */
+static svn_error_t *
+find_yca(svn_client__pathrev_t **yca_loc,
+         const char *repos_relpath1,
+         svn_revnum_t peg_rev1,
+         const char *repos_relpath2,
+         svn_revnum_t peg_rev2,
+         const char *repos_root_url,
+         const char *repos_uuid,
+         svn_client_ctx_t *ctx,
+         apr_pool_t *result_pool,
+         apr_pool_t *scratch_pool)
+{
+  svn_client__pathrev_t *loc1;
+  svn_client__pathrev_t *loc2;
+
+  *yca_loc = NULL;
+
+  loc1 = svn_client__pathrev_create_with_relpath(repos_root_url, repos_uuid,
+                                                 peg_rev1, repos_relpath1,
+                                                 scratch_pool);
+  loc2 = svn_client__pathrev_create_with_relpath(repos_root_url, repos_uuid,
+                                                 peg_rev2, repos_relpath2,
+                                                 scratch_pool);
+  SVN_ERR(svn_client__get_youngest_common_ancestor(yca_loc, loc1, loc2, NULL,
+                                                   ctx, result_pool,
+                                                   scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Implements svn_log_entry_receiver_t.
  *
  * Find the revision in which a node, optionally ancestrally related to the
  * node specified via find_deleted_rev_baton, was deleted, When the revision
  * was found, store it in BATON->DELETED_REV and abort the log operation
- * by raising SVN_ERR_CANCELLED.
+ * by raising SVN_ERR_CEASE_INVOCATION.
  *
  * If no such revision can be found, leave BATON->DELETED_REV and
  * BATON->REPLACING_NODE_KIND alone.
@@ -520,7 +599,7 @@ struct find_deleted_rev_baton
  * works in cases where we do not already know a revision in which the deleted
  * node once used to exist.
  * 
- * If the node node was moved, rather than deleted, return move information
+ * If the node was moved, rather than deleted, return move information
  * in BATON->MOVE.
  */
 static svn_error_t *
@@ -535,6 +614,18 @@ find_deleted_rev(void *baton,
   apr_array_header_t *deleted_paths;
   apr_hash_t *copies;
 
+  if (b->ctx->notify_func2)
+    {
+      svn_wc_notify_t *notify;
+
+      notify = svn_wc_create_notify(
+                 b->victim_abspath,
+                 svn_wc_notify_tree_conflict_details_progress,
+                 scratch_pool),
+      notify->revision = log_entry->revision;
+      b->ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
+    }
+
   /* No paths were changed in this revision.  Nothing to do. */
   if (! log_entry->changed_paths2)
     return SVN_NO_ERROR;
@@ -606,27 +697,32 @@ find_deleted_rev(void *baton,
           if (b->related_repos_relpath != NULL &&
               b->related_repos_peg_rev != SVN_INVALID_REVNUM)
             {
-              svn_client__pathrev_t *yca_loc = NULL;
-              svn_client__pathrev_t *loc1;
-              svn_client__pathrev_t *loc2;
+              svn_client__pathrev_t *yca_loc;
+              svn_error_t *err;
 
               /* We found a deleted node which occupies the correct path.
                * To be certain that this is the deleted node we're looking for,
                * we must establish whether it is ancestrally related to the
                * "related node" specified in our baton. */
-              loc1 = svn_client__pathrev_create_with_relpath(
-                       b->repos_root_url, b->repos_uuid,
-                       b->related_repos_peg_rev,
-                       b->related_repos_relpath, iterpool);
-              loc2 = svn_client__pathrev_create_with_relpath(
-                       b->repos_root_url, b->repos_uuid,
-                       log_entry->revision - 1,
-                       b->deleted_repos_relpath, iterpool);
-              SVN_ERR(svn_client__get_youngest_common_ancestor(&yca_loc,
-                                                               loc1, loc2,
-                                                               NULL, b->ctx,
-                                                               iterpool,
-                                                               iterpool));
+              err = find_yca(&yca_loc,
+                             b->related_repos_relpath,
+                             b->related_repos_peg_rev,
+                             b->deleted_repos_relpath,
+                             log_entry->revision - 1,
+                             b->repos_root_url, b->repos_uuid,
+                             b->ctx, iterpool, iterpool);
+              if (err)
+                {
+                  /* ### Happens for moves within other moves and copies. */
+                  if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
+                    {
+                      svn_error_clear(err);
+                      yca_loc = NULL;
+                    }
+                  else
+                    return svn_error_trace(err);
+                }
+
               deleted_node_found = (yca_loc != NULL);
             }
 
@@ -649,14 +745,15 @@ find_deleted_rev(void *baton,
   svn_pool_destroy(iterpool);
 
   /* Check for moves in this revision */
-  SVN_ERR(find_moves_in_revision(b->moves_table, b->moved_paths,
+  SVN_ERR(find_moves_in_revision(b->extra_ra_session,
+                                 b->moves_table, b->moved_paths,
                                  log_entry, copies, deleted_paths,
-                                 b->repos_root_url, b->ctx,
+                                 b->repos_root_url,
                                  b->result_pool, scratch_pool));
   if (deleted_node_found)
     {
       /* We're done. Abort the log operation. */
-      return svn_error_create(SVN_ERR_CANCELLED, NULL, NULL);
+      return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
     }
 
   return SVN_NO_ERROR;
@@ -667,6 +764,7 @@ find_deleted_rev(void *baton,
 static svn_error_t *
 describe_local_file_node_change(const char **description,
                                 svn_client_conflict_t *conflict,
+                                svn_client_ctx_t *ctx,
                                 apr_pool_t *result_pool,
                                 apr_pool_t *scratch_pool)
 {
@@ -726,7 +824,7 @@ describe_local_file_node_change(const ch
           const char *moved_to_abspath;
 
           SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL, 
-                                              conflict->ctx->wc_ctx,
+                                              ctx->wc_ctx,
                                               conflict->local_abspath,
                                               scratch_pool,
                                               scratch_pool));
@@ -745,7 +843,7 @@ describe_local_file_node_change(const ch
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -778,7 +876,7 @@ describe_local_file_node_change(const ch
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -800,7 +898,7 @@ describe_local_file_node_change(const ch
           const char *moved_from_abspath;
 
           SVN_ERR(svn_wc__node_was_moved_here(&moved_from_abspath, NULL, 
-                                              conflict->ctx->wc_ctx,
+                                              ctx->wc_ctx,
                                               conflict->local_abspath,
                                               scratch_pool,
                                               scratch_pool));
@@ -819,7 +917,7 @@ describe_local_file_node_change(const ch
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -851,7 +949,7 @@ describe_local_file_node_change(const ch
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -879,6 +977,7 @@ describe_local_file_node_change(const ch
 static svn_error_t *
 describe_local_dir_node_change(const char **description,
                                svn_client_conflict_t *conflict,
+                               svn_client_ctx_t *ctx,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool)
 {
@@ -915,8 +1014,7 @@ describe_local_dir_node_change(const cha
       case svn_wc_conflict_reason_missing:
         if (operation == svn_wc_operation_update ||
             operation == svn_wc_operation_switch)
-          *description = _("No such directory was found in the working "
-                           "copy.");
+          *description = _("No such directory was found in the working copy.");
         else if (operation == svn_wc_operation_merge)
           {
             /* ### display deleted revision */
@@ -940,7 +1038,7 @@ describe_local_dir_node_change(const cha
           const char *moved_to_abspath;
 
           SVN_ERR(svn_wc__node_was_moved_away(&moved_to_abspath, NULL, 
-                                              conflict->ctx->wc_ctx,
+                                              ctx->wc_ctx,
                                               conflict->local_abspath,
                                               scratch_pool,
                                               scratch_pool));
@@ -959,7 +1057,7 @@ describe_local_dir_node_change(const cha
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -992,7 +1090,7 @@ describe_local_dir_node_change(const cha
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -1014,7 +1112,7 @@ describe_local_dir_node_change(const cha
           const char *moved_from_abspath;
 
           SVN_ERR(svn_wc__node_was_moved_here(&moved_from_abspath, NULL, 
-                                              conflict->ctx->wc_ctx,
+                                              ctx->wc_ctx,
                                               conflict->local_abspath,
                                               scratch_pool,
                                               scratch_pool));
@@ -1033,7 +1131,7 @@ describe_local_dir_node_change(const cha
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -1066,7 +1164,7 @@ describe_local_dir_node_change(const cha
                   const char *wcroot_abspath;
 
                   SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath,
-                                             conflict->ctx->wc_ctx,
+                                             ctx->wc_ctx,
                                              conflict->local_abspath,
                                              scratch_pool,
                                              scratch_pool));
@@ -1095,14 +1193,14 @@ describe_local_dir_node_change(const cha
  * If the node was replaced rather than deleted, set *REPLACING_NODE_KIND to
  * the node kind of the replacing node. Else, set it to svn_node_unknown.
  * Only request the log for revisions up to END_REV from the server.
- * If the deleted node was moved, provide move information in *MOVE.
- * If the node was not moved,set *MOVE to NULL.
+ * If the deleted node was moved, provide heads of move chains in *MOVES.
+ * If the node was not moved,set *MOVES to NULL.
  */
 static svn_error_t *
 find_revision_for_suspected_deletion(svn_revnum_t *deleted_rev,
                                      const char **deleted_rev_author,
                                      svn_node_kind_t *replacing_node_kind,
-                                     struct repos_move_info **move,
+                                     struct apr_array_header_t **moves,
                                      svn_client_conflict_t *conflict,
                                      const char *deleted_basename,
                                      const char *parent_repos_relpath,
@@ -1110,6 +1208,7 @@ find_revision_for_suspected_deletion(svn
                                      svn_revnum_t end_rev,
                                      const char *related_repos_relpath,
                                      svn_revnum_t related_peg_rev,
+                                     svn_client_ctx_t *ctx,
                                      apr_pool_t *result_pool,
                                      apr_pool_t *scratch_pool)
 {
@@ -1121,8 +1220,11 @@ find_revision_for_suspected_deletion(svn
   const char *repos_root_url;
   const char *repos_uuid;
   struct find_deleted_rev_baton b;
+  const char *victim_abspath;
   svn_error_t *err;
 
+  SVN_ERR_ASSERT(start_rev > end_rev);
+
   SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, &repos_uuid,
                                              conflict, scratch_pool,
                                              scratch_pool));
@@ -1130,7 +1232,7 @@ find_revision_for_suspected_deletion(svn
                                     scratch_pool);
   SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
                                                url, NULL, NULL, FALSE, FALSE,
-                                               conflict->ctx, scratch_pool,
+                                               ctx, scratch_pool,
                                                scratch_pool));
 
   paths = apr_array_make(scratch_pool, 1, sizeof(const char *));
@@ -1139,6 +1241,8 @@ find_revision_for_suspected_deletion(svn
   revprops = apr_array_make(scratch_pool, 1, sizeof(const char *));
   APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_AUTHOR;
 
+  victim_abspath = svn_client_conflict_get_local_abspath(conflict);
+  b.victim_abspath = victim_abspath;
   b.deleted_repos_relpath = svn_relpath_join(parent_repos_relpath,
                                              deleted_basename, scratch_pool);
   b.related_repos_relpath = related_repos_relpath;
@@ -1147,10 +1251,12 @@ find_revision_for_suspected_deletion(svn
   b.replacing_node_kind = svn_node_unknown;
   b.repos_root_url = repos_root_url;
   b.repos_uuid = repos_uuid;
-  b.ctx = conflict->ctx;
+  b.ctx = ctx;
   b.moves_table = apr_hash_make(result_pool);
   b.moved_paths = apr_hash_make(scratch_pool);
   b.result_pool = result_pool;
+  SVN_ERR(svn_ra__dup_session(&b.extra_ra_session, ra_session, NULL,
+                              scratch_pool, scratch_pool));
 
   err = svn_ra_get_log2(ra_session, paths, start_rev, end_rev,
                         0, /* no limit */
@@ -1162,8 +1268,9 @@ find_revision_for_suspected_deletion(svn
                         scratch_pool);
   if (err)
     {
-      if (err->apr_err == SVN_ERR_CANCELLED &&
+      if (err->apr_err == SVN_ERR_CEASE_INVOCATION &&
           b.deleted_rev != SVN_INVALID_REVNUM)
+
         {
           /* Log operation was aborted because we found deleted rev. */
           svn_error_clear(err);
@@ -1179,41 +1286,46 @@ find_revision_for_suspected_deletion(svn
       *deleted_rev = SVN_INVALID_REVNUM;
       *deleted_rev_author = NULL;
       *replacing_node_kind = svn_node_unknown;
-      *move = NULL;
+      *moves = NULL;
       return SVN_NO_ERROR;
     }
   else
     {
-      apr_array_header_t *moves;
+      apr_array_header_t *all_moves_in_deleted_rev;
 
       *deleted_rev = b.deleted_rev;
       *deleted_rev_author = b.deleted_rev_author;
       *replacing_node_kind = b.replacing_node_kind;
 
-      /* Look for a move which affects the deleted node. */
-      moves = apr_hash_get(b.moves_table, &b.deleted_rev,
-                           sizeof(svn_revnum_t));
-      if (moves)
+      /* Look for a moves which affect the deleted node. */
+      all_moves_in_deleted_rev = apr_hash_get(b.moves_table, &b.deleted_rev,
+                                             sizeof(svn_revnum_t));
+      if (all_moves_in_deleted_rev)
         {
           int i;
 
-          for (i = 0; i < moves->nelts; i++)
+          *moves = apr_array_make(result_pool, 1, sizeof(const char *));
+          for (i = 0; i < all_moves_in_deleted_rev->nelts; i++)
             {
               struct repos_move_info *this_move;
               
-              this_move = APR_ARRAY_IDX(moves, i, struct repos_move_info *);
+              this_move = APR_ARRAY_IDX(all_moves_in_deleted_rev, i,
+                                        struct repos_move_info *);
               if (strcmp(b.deleted_repos_relpath,
                          this_move->moved_from_repos_relpath) == 0)
                 {
                   /* Because b->moves_table lives in result_pool
                    * there is no need to deep-copy here. */
-                  *move = this_move;
-                  break;
+                   APR_ARRAY_PUSH(*moves, struct repos_move_info *) = 
this_move;
                 }
             }
+
+          /* If we didn't find any applicable moves, return NULL. */
+          if ((*moves)->nelts == 0)
+            *moves = NULL;
         }
       else
-        *move = NULL;
+        *moves = NULL;
     }
 
   return SVN_NO_ERROR;
@@ -1228,14 +1340,19 @@ struct conflict_tree_local_missing_detai
   /* Author who committed DELETED_REV. */
   const char *deleted_rev_author;
 
-  /* Move information. If not NULL, the first move happened in DELETED_REV.
-   * Follow MOVE->NEXT for subsequent moves in later revisions. */
-  struct repos_move_info *move;
+  /* The path which was deleted relative to the repository root. */
+  const char *deleted_repos_relpath;
+
+  /* Move information. If not NULL, this is an array of repos_move_info *
+   * elements. Each element is the head of a move chain which starts in
+   * DELETED_REV. */
+  apr_array_header_t *moves;
 };
 
 /* Implements tree_conflict_get_details_func_t. */
 static svn_error_t *
 conflict_tree_get_details_local_missing(svn_client_conflict_t *conflict,
+                                        svn_client_ctx_t *ctx,
                                         apr_pool_t *scratch_pool)
 {
   const char *old_repos_relpath;
@@ -1248,7 +1365,9 @@ conflict_tree_get_details_local_missing(
   svn_node_kind_t replacing_node_kind;
   const char *deleted_basename;
   struct conflict_tree_local_missing_details *details;
-  struct repos_move_info *move;
+  apr_array_header_t *moves;
+  const char *related_repos_relpath;
+  svn_revnum_t related_peg_rev;
 
   /* We only handle merges here. */
   if (svn_client_conflict_get_operation(conflict) != svn_wc_operation_merge)
@@ -1268,18 +1387,95 @@ conflict_tree_get_details_local_missing(
                                          scratch_pool);
   SVN_ERR(svn_wc__node_get_repos_info(NULL, &parent_repos_relpath,
                                       NULL, NULL,
-                                      conflict->ctx->wc_ctx,
+                                      ctx->wc_ctx,
                                       svn_dirent_dirname(
                                         conflict->local_abspath,
                                         scratch_pool),
                                       scratch_pool,
                                       scratch_pool));
+
+  /* Pick the younger incoming node as our 'related node' which helps
+   * pin-pointing the deleted conflict victim in history. */
+  related_repos_relpath = 
+            (old_rev < new_rev ? new_repos_relpath : old_repos_relpath);
+  related_peg_rev = (old_rev < new_rev ? new_rev : old_rev);
+
+  /* Make sure we're going to search the related node in a revision where
+   * it exists. The younger incoming node might have been deleted in HEAD. */
+  if (related_repos_relpath != NULL && related_peg_rev != SVN_INVALID_REVNUM)
+    {
+      const char *repos_root_url;
+      const char *repos_uuid;
+      const char *related_url;
+      const char *corrected_url;
+      svn_node_kind_t related_node_kind;
+      svn_ra_session_t *ra_session;
+
+      SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url,
+                                                 &repos_uuid,
+                                                 conflict,
+                                                 scratch_pool, scratch_pool));
+      related_url = svn_path_url_add_component2(repos_root_url,
+                                                related_repos_relpath,
+                                                scratch_pool);
+      SVN_ERR(svn_client__open_ra_session_internal(&ra_session,
+                                                   &corrected_url,
+                                                   related_url, NULL,
+                                                   NULL,
+                                                   FALSE,
+                                                   FALSE,
+                                                   ctx,
+                                                   scratch_pool,
+                                                   scratch_pool));
+      SVN_ERR(svn_ra_check_path(ra_session, "", related_peg_rev,
+                                &related_node_kind, scratch_pool));
+      if (related_node_kind == svn_node_none)
+        {
+          svn_revnum_t related_deleted_rev;
+          const char *related_deleted_rev_author;
+          svn_node_kind_t related_replacing_node_kind;
+          const char *related_basename;
+          const char *related_parent_repos_relpath;
+          apr_array_header_t *related_moves;
+          const char *older_incoming_repos_relpath;
+          svn_revnum_t older_incoming_peg_rev;
+
+          /* Looks like the younger incoming node, which we'd like to use as
+           * our 'related node', was also deleted. Try to find its deleted
+           * revision so we can calculate a peg revision at which it exists.
+           * The younger incoming node is related to the older incoming node,
+           * so we can use the older incoming node to guide us in our search. 
*/
+          related_basename = svn_relpath_basename(related_repos_relpath,
+                                                  scratch_pool);
+          related_parent_repos_relpath =
+            svn_relpath_dirname(related_repos_relpath, scratch_pool);
+          older_incoming_repos_relpath =
+                    (old_rev < new_rev ? old_repos_relpath : 
new_repos_relpath);
+          older_incoming_peg_rev = (old_rev < new_rev ? old_rev : new_rev);
+          SVN_ERR(find_revision_for_suspected_deletion(
+                    &related_deleted_rev, &related_deleted_rev_author,
+                    &related_replacing_node_kind, &related_moves,
+                    conflict, related_basename,
+                    related_parent_repos_relpath,
+                    old_rev < new_rev ? new_rev : old_rev, 0,
+                    older_incoming_repos_relpath, older_incoming_peg_rev,
+                    ctx, conflict->pool, scratch_pool));
+
+          /* If we can't find a related node, bail. */
+          if (related_deleted_rev == SVN_INVALID_REVNUM)
+            return SVN_NO_ERROR;
+
+          /* The node should exist in the revision before it was deleted. */
+          related_peg_rev = related_deleted_rev - 1;
+        }
+    }
+    
   SVN_ERR(find_revision_for_suspected_deletion(
-            &deleted_rev, &deleted_rev_author, &replacing_node_kind, &move,
+            &deleted_rev, &deleted_rev_author, &replacing_node_kind, &moves,
             conflict, deleted_basename, parent_repos_relpath,
             old_rev < new_rev ? new_rev : old_rev, 0,
-            old_rev < new_rev ? new_repos_relpath : old_repos_relpath,
-            old_rev < new_rev ? new_rev : old_rev,
+            related_repos_relpath,
+            related_peg_rev, ctx,
             conflict->pool, scratch_pool));
 
   if (deleted_rev == SVN_INVALID_REVNUM)
@@ -1288,7 +1484,10 @@ conflict_tree_get_details_local_missing(
   details = apr_pcalloc(conflict->pool, sizeof(*details));
   details->deleted_rev = deleted_rev;
   details->deleted_rev_author = deleted_rev_author;
-  details->move = move;
+  details->deleted_repos_relpath = svn_relpath_join(parent_repos_relpath,
+                                                    deleted_basename,
+                                                    conflict->pool); 
+  details->moves = moves;
                                          
   conflict->tree_conflict_local_details = details;
 
@@ -1359,24 +1558,31 @@ describe_local_none_node_change(const ch
   return SVN_NO_ERROR;
 }
 
-/* Append a description of all moves in the MOVE chain to DESCRIPTION. */
+/* Append a description of a move chain beginning at NEXT to DESCRIPTION. */
 static const char *
 append_moved_to_chain_description(const char *description,
-                                  struct repos_move_info *move,
+                                  apr_array_header_t *next,
                                   apr_pool_t *result_pool,
                                   apr_pool_t *scratch_pool)
 {
-  if (move == NULL)
+  if (next == NULL)
     return description;
 
-  while (move)
+  while (next)
     {
+      struct repos_move_info *move;
+
+      /* Describe the first possible move chain only. Adding multiple chains
+       * to the description would just be confusing. The user may select a
+       * different move destination while resolving the conflict. */
+      move = APR_ARRAY_IDX(next, 0, struct repos_move_info *);
+
       description = apr_psprintf(scratch_pool,
                                  _("%s\nAnd then moved away to '^/%s' by "
                                    "%s in r%ld."),
                                  description, move->moved_to_repos_relpath,
                                  move->rev_author, move->rev);
-      move = move->next;
+      next = move->next;
     }
 
   return apr_pstrdup(result_pool, description);
@@ -1386,6 +1592,7 @@ append_moved_to_chain_description(const
 static svn_error_t *
 conflict_tree_get_local_description_generic(const char **description,
                                             svn_client_conflict_t *conflict,
+                                            svn_client_ctx_t *ctx,
                                             apr_pool_t *result_pool,
                                             apr_pool_t *scratch_pool)
 {
@@ -1399,11 +1606,11 @@ conflict_tree_get_local_description_gene
     {
       case svn_node_file:
       case svn_node_symlink:
-        SVN_ERR(describe_local_file_node_change(description, conflict,
+        SVN_ERR(describe_local_file_node_change(description, conflict, ctx,
                                                 result_pool, scratch_pool));
         break;
       case svn_node_dir:
-        SVN_ERR(describe_local_dir_node_change(description, conflict,
+        SVN_ERR(describe_local_dir_node_change(description, conflict, ctx,
                                                result_pool, scratch_pool));
         break;
       case svn_node_none:
@@ -1420,6 +1627,7 @@ conflict_tree_get_local_description_gene
 static svn_error_t *
 conflict_tree_get_description_local_missing(const char **description,
                                             svn_client_conflict_t *conflict,
+                                            svn_client_ctx_t *ctx,
                                             apr_pool_t *result_pool,
                                             apr_pool_t *scratch_pool)
 {
@@ -1428,19 +1636,23 @@ conflict_tree_get_description_local_miss
   details = conflict->tree_conflict_local_details;
   if (details == NULL)
     return svn_error_trace(conflict_tree_get_local_description_generic(
-                             description, conflict, result_pool, 
scratch_pool));
+                             description, conflict, ctx,
+                             result_pool, scratch_pool));
 
-  if (details->move)
+  if (details->moves)
     {
+      struct repos_move_info *move;
+
+      move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info *);
       *description = apr_psprintf(
                        result_pool,
                        _("No such file or directory was found in the "
                          "merge target working copy.\nThe item was "
                          "moved away to '^/%s' in r%ld by %s."),
-                       details->move->moved_to_repos_relpath,
-                       details->move->rev, details->move->rev_author);
+                       move->moved_to_repos_relpath,
+                       move->rev, move->rev_author);
       *description = append_moved_to_chain_description(*description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
     }
@@ -1448,8 +1660,9 @@ conflict_tree_get_description_local_miss
     *description = apr_psprintf(
                      result_pool,
                      _("No such file or directory was found in the "
-                       "merge target working copy.\nThe item was "
-                       "deleted in r%ld by %s."),
+                       "merge target working copy.\n'^/%s' was deleted "
+                       "in r%ld by %s."),
+                     details->deleted_repos_relpath,
                      details->deleted_rev, details->deleted_rev_author);
 
   return SVN_NO_ERROR;
@@ -1693,6 +1906,7 @@ static svn_error_t *
 conflict_tree_get_incoming_description_generic(
   const char **incoming_change_description,
   svn_client_conflict_t *conflict,
+  svn_client_ctx_t *ctx,
   apr_pool_t *result_pool,
   apr_pool_t *scratch_pool)
 {
@@ -1700,11 +1914,9 @@ conflict_tree_get_incoming_description_g
   svn_node_kind_t incoming_kind;
   svn_wc_conflict_action_t conflict_action;
   svn_wc_operation_t conflict_operation;
-  svn_node_kind_t conflict_node_kind;
 
   conflict_action = svn_client_conflict_get_incoming_change(conflict);
   conflict_operation = svn_client_conflict_get_operation(conflict);
-  conflict_node_kind = svn_client_conflict_tree_get_victim_node_kind(conflict);
 
   /* Determine the node kind of the incoming change. */
   incoming_kind = svn_node_unknown;
@@ -1767,10 +1979,36 @@ struct conflict_tree_incoming_delete_det
   /* New node kind for a replaced node. This is svn_node_none for deletions. */
   svn_node_kind_t replacing_node_kind;
 
-  /* Move information. If not NULL, the first move happened in DELETED_REV
-   * or in ADDED_REV (in which case moves should be interpreted in reverse).
-   * Follow MOVE->NEXT for subsequent moves in later revisions. */
-  struct repos_move_info *move;
+  /* Move information. If not NULL, this is an array of repos_move_info *
+   * elements. Each element is the head of a move chain which starts in
+   * DELETED_REV or in ADDED_REV (in which case moves should be interpreted
+   * in reverse). */
+  apr_array_header_t *moves;
+
+  /* A map of repos_relpaths and working copy nodes for an incoming move.
+   *
+   * Each key is a "const char *" repository relpath corresponding to a
+   * possible repository-side move destination node in the revision which
+   * is the target revision in case of update and switch, or the merge-right
+   * revision in case of a merge.
+   *
+   * Each value is an apr_array_header_t *.
+   * Each array consists of "const char *" absolute paths to working copy
+   * nodes which correspond to the repository node selected by the map key.
+   * Each such working copy node is a potential local move target which can
+   * be chosen to "follow" the incoming move when resolving a tree conflict.
+   *
+   * This may be an empty hash map in case if there is no move target path
+   * in the working copy. */
+  apr_hash_t *wc_move_targets;
+
+  /* The preferred move target repository relpath. This is our key into
+   * the WC_MOVE_TARGETS map above (can be overridden by the user). */
+  const char *move_target_repos_relpath;
+
+  /* The current index into the list of working copy nodes corresponding to
+   * MOVE_TARGET_REPOS_REPLATH (can be overridden by the user). */
+  int wc_move_target_idx;
 };
 
 static const char *
@@ -1786,62 +2024,180 @@ describe_incoming_deletion_upon_update(
       details->replacing_node_kind == svn_node_symlink)
     {
       if (victim_node_kind == svn_node_dir)
-        return apr_psprintf(result_pool,
-                            _("Directory updated from r%ld to r%ld was "
-                              "replaced with a file by %s in r%ld."),
-                            old_rev, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Directory updated from r%ld to r%ld was "
+                           "replaced with a file by %s in r%ld."),
+                         old_rev, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced directory was moved to "
+                               "'^/%s'."), description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
-        return apr_psprintf(result_pool,
-                            _("File updated from r%ld to r%ld was replaced "
-                              "with a file from another line of history by "
-                              "%s in r%ld."),
-                            old_rev, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("File updated from r%ld to r%ld was replaced "
+                           "with a file from another line of history by "
+                           "%s in r%ld."),
+                         old_rev, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced file was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else
-        return apr_psprintf(result_pool,
-                            _("Item updated from r%ld to r%ld was replaced "
-                              "with a file by %s in r%ld."), old_rev, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Item updated from r%ld to r%ld was replaced "
+                           "with a file by %s in r%ld."), old_rev, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced item was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
     }
   else if (details->replacing_node_kind == svn_node_dir)
     {
       if (victim_node_kind == svn_node_dir)
-        return apr_psprintf(result_pool,
-                            _("Directory updated from r%ld to r%ld was "
-                              "replaced with a directory from another line "
-                              "of history by %s in r%ld."),
-                            old_rev, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                          _("Directory updated from r%ld to r%ld was "
+                            "replaced with a directory from another line "
+                            "of history by %s in r%ld."),
+                          old_rev, new_rev,
+                          details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced directory was moved to "
+                               "'^/%s'."), description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
-        return apr_psprintf(result_pool,
-                            _("Directory updated from r%ld to r%ld was "
-                              "replaced with a file by %s in r%ld."),
-                            old_rev, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("File updated from r%ld to r%ld was "
+                           "replaced with a directory by %s in r%ld."),
+                         old_rev, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced file was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else
-        return apr_psprintf(result_pool,
-                            _("Item updated from r%ld to r%ld was replaced "
-                              "by %s in r%ld."), old_rev, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Item updated from r%ld to r%ld was replaced "
+                           "by %s in r%ld."), old_rev, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced item was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
     }
   else
     {
       if (victim_node_kind == svn_node_dir)
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              const char *description;
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("Directory updated from r%ld to r%ld was "
                                "moved to '^/%s' by %s in r%ld."),
                              old_rev, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -1855,16 +2211,20 @@ describe_incoming_deletion_upon_update(
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("File updated from r%ld to r%ld was moved "
                                "to '^/%s' by %s in r%ld."), old_rev, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -1876,16 +2236,20 @@ describe_incoming_deletion_upon_update(
         }
       else
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description = 
+              const char *description;
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description = 
                 apr_psprintf(result_pool,
                              _("Item updated from r%ld to r%ld was moved "
                                "to '^/%s' by %s in r%ld."), old_rev, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -1992,78 +2356,196 @@ describe_incoming_deletion_upon_switch(
       details->replacing_node_kind == svn_node_symlink)
     {
       if (victim_node_kind == svn_node_dir)
-        return apr_psprintf(result_pool,
-                            _("Directory switched from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
-                              "was replaced with a file by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Directory switched from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
+                           "was replaced with a file by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced directory was moved "
+                               "to '^/%s'."), description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;    
+        }
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
-        return apr_psprintf(result_pool,
-                            _("File switched from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
-                              "replaced with a file from another line of "
-                              "history by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("File switched from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
+                           "replaced with a file from another line of "
+                           "history by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced file was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else
-        return apr_psprintf(result_pool,
-                            _("Item switched from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
-                              "replaced with a file by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Item switched from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
+                           "replaced with a file by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced item was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
     }
   else if (details->replacing_node_kind == svn_node_dir)
     {
       if (victim_node_kind == svn_node_dir)
-        return apr_psprintf(result_pool,
-                            _("Directory switched from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
-                              "was replaced with a directory from another "
-                              "line of history by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Directory switched from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
+                           "was replaced with a directory from another "
+                           "line of history by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced directory was moved to "
+                               "'^/%s'."), description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
-        return apr_psprintf(result_pool,
-                            _("File switched from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
-                              "was replaced with a directory by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("File switched from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
+                           "was replaced with a directory by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced file was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else
-        return apr_psprintf(result_pool,
-                            _("Item switched from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
-                              "replaced with a directory by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Item switched from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
+                           "replaced with a directory by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced item was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
     }
   else
     {
       if (victim_node_kind == svn_node_dir)
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+              
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("Directory switched from\n"
                                "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
                                "was moved to '^/%s' by %s in r%ld."),
                              old_repos_relpath, old_rev,
                              new_repos_relpath, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -2079,19 +2561,23 @@ describe_incoming_deletion_upon_switch(
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("File switched from\n"
                                "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
                                "moved to '^/%s' by %s in r%ld."),
                              old_repos_relpath, old_rev,
                              new_repos_relpath, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -2106,19 +2592,23 @@ describe_incoming_deletion_upon_switch(
         }
       else
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("Item switched from\n"
                                "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
                                "moved to '^/%s' by %s in r%ld."),
                              old_repos_relpath, old_rev,
                              new_repos_relpath, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -2253,23 +2743,61 @@ describe_incoming_deletion_upon_merge(
       details->replacing_node_kind == svn_node_symlink)
     {
       if (victim_node_kind == svn_node_dir)
-        return apr_psprintf(result_pool,
-                            _("Directory merged from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
-                              "was replaced with a file by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Directory merged from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
+                           "was replaced with a file by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced directory was moved to "
+                               "'^/%s'."), description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
-        return apr_psprintf(result_pool,
-                            _("File merged from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
-                              "replaced with a file from another line of "
-                              "history by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("File merged from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
+                           "replaced with a file from another line of "
+                           "history by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced file was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else
         return apr_psprintf(result_pool,
                             _("Item merged from\n"
@@ -2282,49 +2810,110 @@ describe_incoming_deletion_upon_merge(
   else if (details->replacing_node_kind == svn_node_dir)
     {
       if (victim_node_kind == svn_node_dir)
-        return apr_psprintf(result_pool,
-                            _("Directory merged from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
-                              "was replaced with a directory from another "
-                              "line of history by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Directory merged from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
+                           "was replaced with a directory from another "
+                           "line of history by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced directory was moved to "
+                               "'^/%s'."), description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
-        return apr_psprintf(result_pool,
-                            _("File merged from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
-                              "was replaced with a directory by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("File merged from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\n"
+                           "was replaced with a directory by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced file was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
       else
-        return apr_psprintf(result_pool,
-                            _("Item merged from\n"
-                              "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
-                              "replaced with a directory by %s in r%ld."),
-                            old_repos_relpath, old_rev,
-                            new_repos_relpath, new_rev,
-                            details->rev_author, details->deleted_rev);
+        {
+          const char *description =
+            apr_psprintf(result_pool,
+                         _("Item merged from\n"
+                           "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
+                           "replaced with a directory by %s in r%ld."),
+                         old_repos_relpath, old_rev,
+                         new_repos_relpath, new_rev,
+                         details->rev_author, details->deleted_rev);
+          if (details->moves)
+            {
+              struct repos_move_info *move;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
+                apr_psprintf(result_pool,
+                             _("%s\nThe replaced item was moved to '^/%s'."),
+                             description,
+                             move->moved_to_repos_relpath);
+              return append_moved_to_chain_description(description,
+                                                       move->next,
+                                                       result_pool,
+                                                       scratch_pool);
+            }
+          return description;
+        }
     }
   else
     {
       if (victim_node_kind == svn_node_dir)
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("Directory merged from\n"
                                "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
                                "moved to '^/%s' by %s in r%ld."),
                              old_repos_relpath, old_rev,
                              new_repos_relpath, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -2340,19 +2929,23 @@ describe_incoming_deletion_upon_merge(
       else if (victim_node_kind == svn_node_file ||
                victim_node_kind == svn_node_symlink)
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("File merged from\n"
                                "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
                                "moved to '^/%s' by %s in r%ld."),
                              old_repos_relpath, old_rev,
                              new_repos_relpath, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -2367,19 +2960,23 @@ describe_incoming_deletion_upon_merge(
         }
       else
         {
-          if (details->move)
+          if (details->moves)
             {
-              const char *description =
+              struct repos_move_info *move;
+              const char *description;
+
+              move = APR_ARRAY_IDX(details->moves, 0, struct repos_move_info 
*);
+              description =
                 apr_psprintf(result_pool,
                              _("Item merged from\n"
                                "'^/%s@%ld'\nto\n'^/%s@%ld'\nwas "
                                "moved to '^/%s' by %s in r%ld."),
                              old_repos_relpath, old_rev,
                              new_repos_relpath, new_rev,
-                             details->move->moved_to_repos_relpath,
+                             move->moved_to_repos_relpath,
                              details->rev_author, details->deleted_rev);
               return append_moved_to_chain_description(description,
-                                                       details->move->next,
+                                                       move->next,
                                                        result_pool,
                                                        scratch_pool);
             }
@@ -2501,6 +3098,7 @@ static svn_error_t *
 conflict_tree_get_description_incoming_delete(
   const char **incoming_change_description,
   svn_client_conflict_t *conflict,
+  svn_client_ctx_t *ctx,
   apr_pool_t *result_pool,
   apr_pool_t *scratch_pool)
 {
@@ -2516,7 +3114,7 @@ conflict_tree_get_description_incoming_d
   if (conflict->tree_conflict_incoming_details == NULL)
     return svn_error_trace(conflict_tree_get_incoming_description_generic(
                              incoming_change_description,
-                             conflict, result_pool, scratch_pool));
+                             conflict, ctx, result_pool, scratch_pool));
 
   conflict_operation = svn_client_conflict_get_operation(conflict);
   victim_node_kind = svn_client_conflict_tree_get_victim_node_kind(conflict);
@@ -2599,6 +3197,8 @@ conflict_tree_get_description_incoming_d
 /* Baton for find_added_rev(). */
 struct find_added_rev_baton
 {
+  const char *victim_abspath;
+  svn_client_ctx_t *ctx;
   svn_revnum_t added_rev;
   const char *repos_relpath;
   const char *parent_repos_relpath;
@@ -2617,6 +3217,18 @@ find_added_rev(svn_location_segment_t *s
 {
   struct find_added_rev_baton *b = baton;
 
+  if (b->ctx->notify_func2)
+    {
+      svn_wc_notify_t *notify;
+
+      notify = svn_wc_create_notify(
+                 b->victim_abspath,
+                 svn_wc_notify_tree_conflict_details_progress,
+                 scratch_pool),
+      notify->revision = segment->range_start;
+      b->ctx->notify_func2(b->ctx->notify_baton2, notify, scratch_pool);
+    }
+
   if (segment->path) /* not interested in gaps */
     {
       if (b->parent_repos_relpath == NULL ||
@@ -2641,6 +3253,7 @@ get_incoming_delete_details_for_reverse_
   svn_revnum_t old_rev,
   svn_revnum_t new_rev,
   svn_client_ctx_t *ctx,
+  const char *victim_abspath,
   apr_pool_t *result_pool,
   apr_pool_t *scratch_pool)
 {
@@ -2662,15 +3275,19 @@ get_incoming_delete_details_for_reverse_
                                                scratch_pool));
 
   *details = apr_pcalloc(result_pool, sizeof(**details));
+  b.ctx = ctx;
+  b.victim_abspath = victim_abspath;
   b.added_rev = SVN_INVALID_REVNUM;
   b.repos_relpath = NULL;
   b.parent_repos_relpath = NULL;
   b.pool = scratch_pool;
+
   /* Figure out when this node was added. */
   SVN_ERR(svn_ra_get_location_segments(ra_session, "", old_rev,
                                        old_rev, new_rev,
                                        find_added_rev, &b,
                                        scratch_pool));
+
   SVN_ERR(svn_ra_rev_prop(ra_session, b.added_rev,
                           SVN_PROP_REVISION_AUTHOR,
                           &author_revprop, scratch_pool));
@@ -2700,6 +3317,7 @@ get_incoming_delete_details_for_reverse_
  * Find the revision in which the victim was deleted in the repository. */
 static svn_error_t *
 conflict_tree_get_details_incoming_delete(svn_client_conflict_t *conflict,
+                                          svn_client_ctx_t *ctx,
                                           apr_pool_t *scratch_pool)
 {
   const char *old_repos_relpath;

[... 4054 lines stripped ...]


Reply via email to