Modified: subversion/branches/addremove/subversion/libsvn_client/merge.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/merge.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/merge.c Sat May 23 
14:16:56 2020
@@ -215,6 +215,21 @@
 
 /*** Repos-Diff Editor Callbacks ***/
 
+struct merge_cmd_baton_t;
+
+struct notify_begin_state_t
+{
+  /* Cache of which abspath was last notified. */
+  const char *last_abspath;
+
+  /* Reference to the main merge baton */
+  struct merge_cmd_baton_t *merge_b;
+
+  /* the wrapped notification callback */
+  svn_wc_notify_func2_t notify_func2;
+  void *notify_baton2;
+};
+
 typedef struct merge_cmd_baton_t {
   svn_boolean_t force_delete;         /* Delete a file/dir even if modified */
   svn_boolean_t dry_run;
@@ -242,11 +257,15 @@ typedef struct merge_cmd_baton_t {
 
   /* Rangelist containing single range which describes the gap, if any,
      in the natural history of the merge source currently being processed.
-     See http://subversion.tigris.org/issues/show_bug.cgi?id=3432.
+     See https://issues.apache.org/jira/browse/SVN-3432.
      Updated during each call to do_directory_merge().  May be NULL if there
      is no gap. */
   svn_rangelist_t *implicit_src_gap;
 
+  /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global
+     comment) or a similar list for single-file-merges */
+  const apr_array_header_t *children_with_mergeinfo;
+
   svn_client_ctx_t *ctx;              /* Client context for callbacks, etc. */
 
   /* The list of any paths which remained in conflict after a
@@ -319,17 +338,10 @@ typedef struct merge_cmd_baton_t {
      or do_file_merge() in do_merge(). */
   apr_pool_t *pool;
 
-
-  /* State for notify_merge_begin() */
-  struct notify_begin_state_t
-  {
-    /* Cache of which abspath was last notified. */
-    const char *last_abspath;
-
-    /* Reference to the one-and-only CHILDREN_WITH_MERGEINFO (see global
-       comment) or a similar list for single-file-merges */
-    const apr_array_header_t *nodes_with_mergeinfo;
-  } notify_begin;
+  /* Our notification callback, that adds a 'begin' notification */
+  svn_wc_notify_func2_t notify_func;
+  void *notify_baton;
+  struct notify_begin_state_t notify_begin;
 
 } merge_cmd_baton_t;
 
@@ -340,17 +352,25 @@ typedef struct merge_cmd_baton_t {
    merge source is an ancestor of the right-side (or vice-versa), the merge
    source is in the same repository as the merge target, and we are not
    ignoring mergeinfo. */
-#define HONOR_MERGEINFO(merge_b) ((merge_b)->mergeinfo_capable      \
-                                  && (merge_b)->merge_source.ancestral  \
-                                  && (merge_b)->same_repos          \
-                                  && (! (merge_b)->ignore_mergeinfo))
+static svn_boolean_t
+HONOR_MERGEINFO(const merge_cmd_baton_t *merge_b)
+{
+  return (merge_b->mergeinfo_capable
+          && merge_b->merge_source.ancestral
+          && merge_b->same_repos
+          && (!merge_b->ignore_mergeinfo));
+}
 
 
 /* Return TRUE iff we should be recording mergeinfo for the merge described
    by MERGE_B.  Specifically, that is if we are honoring mergeinfo and the
    merge is not a dry run.  */
-#define RECORD_MERGEINFO(merge_b) (HONOR_MERGEINFO(merge_b) \
-                                   && !(merge_b)->dry_run)
+static svn_boolean_t
+RECORD_MERGEINFO(const merge_cmd_baton_t *merge_b)
+{
+  return (HONOR_MERGEINFO(merge_b)
+          && !merge_b->dry_run);
+}
 
 
 /*-----------------------------------------------------------------------*/
@@ -1226,13 +1246,6 @@ struct merge_file_baton_t
   svn_boolean_t add_is_replace; /* Add is second part of replace */
 };
 
-/* Forward declaration */
-static svn_error_t *
-notify_merge_begin(merge_cmd_baton_t *merge_b,
-                   const char *local_abspath,
-                   svn_boolean_t delete_action,
-                   apr_pool_t *scratch_pool);
-
 /* Record the skip for future processing and (later) produce the
    skip notification */
 static svn_error_t *
@@ -1253,18 +1266,16 @@ record_skip(merge_cmd_baton_t *merge_b,
       store_path(merge_b->skipped_abspaths, local_abspath);
     }
 
-  if (merge_b->ctx->notify_func2)
+  if (merge_b->notify_func)
     {
       svn_wc_notify_t *notify;
 
-      SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
-
       notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
       notify->kind = kind;
       notify->content_state = notify->prop_state = state;
 
-      merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
-                                 scratch_pool);
+      merge_b->notify_func(merge_b->notify_baton, notify,
+                           scratch_pool);
     }
   return SVN_NO_ERROR;
 }
@@ -1364,7 +1375,7 @@ record_tree_conflict(merge_cmd_baton_t *
            * but figure out the actual revision range merged. */
           (void)find_nearest_ancestor_with_intersecting_ranges(
             &(range.start), &(range.end),
-            merge_b->notify_begin.nodes_with_mergeinfo,
+            merge_b->children_with_mergeinfo,
             action != svn_wc_conflict_action_delete,
             local_abspath);
           loc1 = svn_client__pathrev_dup(merge_b->merge_source.loc1,
@@ -1423,18 +1434,16 @@ record_tree_conflict(merge_cmd_baton_t *
     }
 
   /* On a replacement we currently get two tree conflicts */
-  if (merge_b->ctx->notify_func2 && notify_tc)
+  if (merge_b->notify_func && notify_tc)
     {
       svn_wc_notify_t *notify;
 
-      SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
-
       notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict,
                                     scratch_pool);
       notify->kind = local_node_kind;
 
-      merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
-                                 scratch_pool);
+      merge_b->notify_func(merge_b->notify_baton, notify,
+                           scratch_pool);
     }
 
   return SVN_NO_ERROR;
@@ -1455,21 +1464,19 @@ record_update_add(merge_cmd_baton_t *mer
       store_path(merge_b->merged_abspaths, local_abspath);
     }
 
-  if (merge_b->ctx->notify_func2)
+  if (merge_b->notify_func)
     {
       svn_wc_notify_t *notify;
       svn_wc_notify_action_t action = svn_wc_notify_update_add;
 
-      SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
-
       if (notify_replaced)
         action = svn_wc_notify_update_replace;
 
       notify = svn_wc_create_notify(local_abspath, action, scratch_pool);
       notify->kind = kind;
 
-      merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
-                                 scratch_pool);
+      merge_b->notify_func(merge_b->notify_baton, notify,
+                           scratch_pool);
     }
 
   return SVN_NO_ERROR;
@@ -1490,20 +1497,18 @@ record_update_update(merge_cmd_baton_t *
       store_path(merge_b->merged_abspaths, local_abspath);
     }
 
-  if (merge_b->ctx->notify_func2)
+  if (merge_b->notify_func)
     {
       svn_wc_notify_t *notify;
 
-      SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE, scratch_pool));
-
       notify = svn_wc_create_notify(local_abspath, svn_wc_notify_update_update,
                                     scratch_pool);
       notify->kind = kind;
       notify->content_state = content_state;
       notify->prop_state = prop_state;
 
-      merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
-                                 scratch_pool);
+      merge_b->notify_func(merge_b->notify_baton, notify,
+                           scratch_pool);
     }
 
   return SVN_NO_ERROR;
@@ -1529,8 +1534,6 @@ record_update_delete(merge_cmd_baton_t *
       store_path(merge_b->merged_abspaths, local_abspath);
     }
 
-  SVN_ERR(notify_merge_begin(merge_b, local_abspath, TRUE, scratch_pool));
-
   if (parent_db)
     {
       const char *dup_abspath = apr_pstrdup(parent_db->pool, local_abspath);
@@ -1552,7 +1555,7 @@ handle_pending_notifications(merge_cmd_b
                              struct merge_dir_baton_t *db,
                              apr_pool_t *scratch_pool)
 {
-  if (merge_b->ctx->notify_func2 && db->pending_deletes)
+  if (merge_b->notify_func && db->pending_deletes)
     {
       apr_hash_index_t *hi;
 
@@ -1569,8 +1572,8 @@ handle_pending_notifications(merge_cmd_b
           notify->kind = svn_node_kind_from_word(
                                     apr_hash_this_val(hi));
 
-          merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
-                                     notify, scratch_pool);
+          merge_b->notify_func(merge_b->notify_baton,
+                               notify, scratch_pool);
         }
 
       db->pending_deletes = NULL;
@@ -1620,13 +1623,10 @@ mark_dir_edited(merge_cmd_baton_t *merge
          for clarity we produce a skip for this node that
          most likely isn't touched by the merge itself */
 
-      if (merge_b->ctx->notify_func2)
+      if (merge_b->notify_func)
         {
           svn_wc_notify_t *notify;
 
-          SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
-                                     scratch_pool));
-
           notify = svn_wc_create_notify(
                             local_abspath,
                             (db->tree_conflict_reason == CONFLICT_REASON_SKIP)
@@ -1636,9 +1636,9 @@ mark_dir_edited(merge_cmd_baton_t *merge
           notify->kind = svn_node_dir;
           notify->content_state = notify->prop_state = db->skip_reason;
 
-          merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
-                                     notify,
-                                     scratch_pool);
+          merge_b->notify_func(merge_b->notify_baton,
+                               notify,
+                               scratch_pool);
         }
 
       if (merge_b->merge_source.ancestral
@@ -1706,21 +1706,18 @@ mark_file_edited(merge_cmd_baton_t *merg
          for clarity we produce a skip for this node that
          most likely isn't touched by the merge itself */
 
-      if (merge_b->ctx->notify_func2)
+      if (merge_b->notify_func)
         {
           svn_wc_notify_t *notify;
 
-          SVN_ERR(notify_merge_begin(merge_b, local_abspath, FALSE,
-                                     scratch_pool));
-
           notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip,
                                         scratch_pool);
           notify->kind = svn_node_file;
           notify->content_state = notify->prop_state = fb->skip_reason;
 
-          merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2,
-                                     notify,
-                                     scratch_pool);
+          merge_b->notify_func(merge_b->notify_baton,
+                               notify,
+                               scratch_pool);
         }
 
       if (merge_b->merge_source.ancestral
@@ -3390,7 +3387,7 @@ merge_dir_closed(const char *relpath,
 
    We register a skipped path, which will make parent mergeinfo non-
    inheritable. This ensures that a future merge might see these skipped
-   changes as eligable for merging.
+   changes as eligible for merging.
 
    For legacy reasons we also notify the path as skipped.
  */
@@ -3413,6 +3410,49 @@ merge_node_absent(const char *relpath,
   return SVN_NO_ERROR;
 }
 
+/* Return a diff processor that will apply the merge to the WC.
+ */
+static svn_diff_tree_processor_t *
+merge_apply_processor(merge_cmd_baton_t *merge_cmd_baton,
+                      apr_pool_t *result_pool)
+{
+  svn_diff_tree_processor_t *merge_processor;
+
+  merge_processor = svn_diff__tree_processor_create(merge_cmd_baton,
+                                                    result_pool);
+
+  merge_processor->dir_opened   = merge_dir_opened;
+  merge_processor->dir_changed  = merge_dir_changed;
+  merge_processor->dir_added    = merge_dir_added;
+  merge_processor->dir_deleted  = merge_dir_deleted;
+  merge_processor->dir_closed   = merge_dir_closed;
+
+  merge_processor->file_opened  = merge_file_opened;
+  merge_processor->file_changed = merge_file_changed;
+  merge_processor->file_added   = merge_file_added;
+  merge_processor->file_deleted = merge_file_deleted;
+  /* Not interested in file_closed() */
+
+  merge_processor->node_absent = merge_node_absent;
+
+  return merge_processor;
+}
+
+/* Initialize minimal dir baton to allow calculating 'R'eplace
+   from 'D'elete + 'A'dd. */
+static void *
+open_dir_for_replace_single_file(apr_pool_t *result_pool)
+{
+  struct merge_dir_baton_t *dir_baton = apr_pcalloc(result_pool, 
sizeof(*dir_baton));
+
+  dir_baton->pool = result_pool;
+  dir_baton->tree_conflict_reason = CONFLICT_REASON_NONE;
+  dir_baton->tree_conflict_action = svn_wc_conflict_action_edit;
+  dir_baton->skip_reason = svn_wc_notify_state_unknown;
+
+  return dir_baton;
+}
+
 /*-----------------------------------------------------------------------*/
 
 /*** Merge Notification ***/
@@ -3608,20 +3648,9 @@ notify_merge_completed(const char *targe
     }
 }
 
-/* Is the notification the result of a real operative merge? */
-#define IS_OPERATIVE_NOTIFICATION(notify)  \
-                    (notify->content_state == svn_wc_notify_state_conflicted \
-                     || notify->content_state == svn_wc_notify_state_merged  \
-                     || notify->content_state == svn_wc_notify_state_changed \
-                     || notify->prop_state == svn_wc_notify_state_conflicted \
-                     || notify->prop_state == svn_wc_notify_state_merged     \
-                     || notify->prop_state == svn_wc_notify_state_changed    \
-                     || notify->action == svn_wc_notify_update_add \
-                     || notify->action == svn_wc_notify_tree_conflict)
-
 
 /* Remove merge source gaps from range used for merge notifications.
-   See http://subversion.tigris.org/issues/show_bug.cgi?id=4138
+   See https://issues.apache.org/jira/browse/SVN-4138
 
    If IMPLICIT_SRC_GAP is not NULL then it is a rangelist containing a
    single range (see the implicit_src_gap member of merge_cmd_baton_t).
@@ -3656,27 +3685,28 @@ remove_source_gap(svn_merge_range_t *ran
  * This calls the client's notification receiver (as found in the client
  * context), with a WC abspath.
  */
-static svn_error_t *
-notify_merge_begin(merge_cmd_baton_t *merge_b,
+static void
+notify_merge_begin(struct notify_begin_state_t *notify_begin_state,
                    const char *local_abspath,
                    svn_boolean_t delete_action,
                    apr_pool_t *scratch_pool)
 {
+  merge_cmd_baton_t *merge_b = notify_begin_state->merge_b;
   svn_wc_notify_t *notify;
   svn_merge_range_t n_range =
     {SVN_INVALID_REVNUM, SVN_INVALID_REVNUM, TRUE};
   const char *notify_abspath;
 
-  if (! merge_b->ctx->notify_func2)
-    return SVN_NO_ERROR;
+  if (! notify_begin_state->notify_func2)
+    return;
 
   /* If our merge sources are ancestors of one another... */
   if (merge_b->merge_source.ancestral)
     {
       const svn_client__merge_path_t *child;
-      /* Find NOTIFY->PATH's nearest ancestor in
-         NOTIFY->CHILDREN_WITH_MERGEINFO.  Normally we consider a child in
-         NOTIFY->CHILDREN_WITH_MERGEINFO representing PATH to be an
+      /* Find LOCAL_ABSPATH's nearest ancestor in
+         CHILDREN_WITH_MERGEINFO.  Normally we consider a child in
+         CHILDREN_WITH_MERGEINFO representing PATH to be an
          ancestor of PATH, but if this is a deletion of PATH then the
          notification must be for a proper ancestor of PATH.  This ensures
          we don't get notifications like:
@@ -3692,47 +3722,47 @@ notify_merge_begin(merge_cmd_baton_t *me
 
       child = find_nearest_ancestor_with_intersecting_ranges(
         &(n_range.start), &(n_range.end),
-        merge_b->notify_begin.nodes_with_mergeinfo,
+        merge_b->children_with_mergeinfo,
         ! delete_action, local_abspath);
 
       if (!child && delete_action)
         {
           /* Triggered by file replace in single-file-merge */
-          child = 
find_nearest_ancestor(merge_b->notify_begin.nodes_with_mergeinfo,
+          child = find_nearest_ancestor(merge_b->children_with_mergeinfo,
                                         TRUE, local_abspath);
         }
 
       assert(child != NULL); /* Should always find the merge anchor */
 
       if (! child)
-        return SVN_NO_ERROR;
+        return;
 
-      if (merge_b->notify_begin.last_abspath != NULL
-          && strcmp(child->abspath, merge_b->notify_begin.last_abspath) == 0)
+      if (notify_begin_state->last_abspath != NULL
+          && strcmp(child->abspath, notify_begin_state->last_abspath) == 0)
         {
           /* Don't notify the same merge again */
-          return SVN_NO_ERROR;
+          return;
         }
 
-      merge_b->notify_begin.last_abspath = child->abspath;
+      notify_begin_state->last_abspath = child->abspath;
 
       if (child->absent || child->remaining_ranges->nelts == 0
           || !SVN_IS_VALID_REVNUM(n_range.start))
         {
           /* No valid information for an header */
-          return SVN_NO_ERROR;
+          return;
         }
 
       notify_abspath = child->abspath;
     }
   else
     {
-      if (merge_b->notify_begin.last_abspath)
-        return SVN_NO_ERROR; /* already notified */
+      if (notify_begin_state->last_abspath)
+        return; /* already notified */
 
       notify_abspath = merge_b->target->abspath;
       /* Store something in last_abspath. Any value would do */
-      merge_b->notify_begin.last_abspath = merge_b->target->abspath;
+      notify_begin_state->last_abspath = merge_b->target->abspath;
     }
 
   notify = svn_wc_create_notify(notify_abspath,
@@ -3753,10 +3783,23 @@ notify_merge_begin(merge_cmd_baton_t *me
       notify->merge_range = NULL;
     }
 
-  merge_b->ctx->notify_func2(merge_b->ctx->notify_baton2, notify,
-                             scratch_pool);
+  notify_begin_state->notify_func2(notify_begin_state->notify_baton2, notify,
+                                   scratch_pool);
+}
 
-  return SVN_NO_ERROR;
+/* Our notification callback, that adds a 'begin' notification */
+static void
+notify_merging(void *baton,
+               const svn_wc_notify_t *notify,
+               apr_pool_t *pool)
+{
+  struct notify_begin_state_t *b = baton;
+
+  notify_merge_begin(b, notify->path,
+                     notify->action == svn_wc_notify_update_delete,
+                     pool);
+
+  b->notify_func2(b->notify_baton2, notify, pool);
 }
 
 /* Set *OUT_RANGELIST to the intersection of IN_RANGELIST with the simple
@@ -5445,7 +5488,7 @@ record_skips_in_mergeinfo(const char *me
          ### TODO: An empty range is fine if the skipped path doesn't
          ### inherit any mergeinfo from a parent, but if it does
          ### we need to account for that.  See issue #3440
-         ### http://subversion.tigris.org/issues/show_bug.cgi?id=3440. */
+         ### https://issues.apache.org/jira/browse/SVN-3440. */
       svn_hash_sets(merges, skipped_abspath,
                     apr_array_make(scratch_pool, 0,
                                    sizeof(svn_merge_range_t *)));
@@ -5554,7 +5597,7 @@ svn_client__make_merge_conflict_error(sv
    defined in get_mergeinfo_paths().  Remove any paths absent from disk
    or scheduled for deletion from CHILDREN_WITH_MERGEINFO which are equal to
    or are descendants of TARGET_WCPATH by setting those children to NULL. */
-static void
+static svn_error_t *
 remove_absent_children(const char *target_wcpath,
                        apr_array_header_t *children_with_mergeinfo)
 {
@@ -5569,9 +5612,10 @@ remove_absent_children(const char *targe
       if ((child->absent || child->scheduled_for_deletion)
           && svn_dirent_is_ancestor(target_wcpath, child->abspath))
         {
-          svn_sort__array_delete(children_with_mergeinfo, i--, 1);
+          SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1));
         }
     }
+  return SVN_NO_ERROR;
 }
 
 /* Helper for do_directory_merge() to handle the case where a merge editor
@@ -5586,14 +5630,14 @@ remove_absent_children(const char *targe
    MERGE_B->target->abspath, this must always be present in
    CHILDREN_WITH_MERGEINFO so this is never removed by this
    function. */
-static void
+static svn_error_t *
 remove_children_with_deleted_mergeinfo(merge_cmd_baton_t *merge_b,
                                        apr_array_header_t 
*children_with_mergeinfo)
 {
   int i;
 
   if (!merge_b->paths_with_deleted_mergeinfo)
-    return;
+    return SVN_NO_ERROR;
 
   /* CHILDREN_WITH_MERGEINFO[0] is the always the merge target
      so start at the first child. */
@@ -5604,9 +5648,10 @@ remove_children_with_deleted_mergeinfo(m
 
       if (svn_hash_gets(merge_b->paths_with_deleted_mergeinfo, child->abspath))
         {
-          svn_sort__array_delete(children_with_mergeinfo, i--, 1);
+          SVN_ERR(svn_sort__array_delete2(children_with_mergeinfo, i--, 1));
         }
     }
+  return SVN_NO_ERROR;
 }
 
 /* Helper for do_directory_merge().
@@ -5932,7 +5977,7 @@ get_most_inclusive_rev(const apr_array_h
    remaining_ranges is inclusive of END_REV, Slice the first range in
    to two at END_REV. All the allocations are persistent and allocated
    from POOL. */
-static void
+static svn_error_t *
 slice_remaining_ranges(apr_array_header_t *children_with_mergeinfo,
                        svn_boolean_t is_rollback, svn_revnum_t end_rev,
                        apr_pool_t *pool)
@@ -5962,10 +6007,12 @@ slice_remaining_ranges(apr_array_header_
               split_range2->start = end_rev;
               APR_ARRAY_IDX(child->remaining_ranges, 0,
                             svn_merge_range_t *) = split_range1;
-              svn_sort__array_insert(child->remaining_ranges, &split_range2, 
1);
+              SVN_ERR(svn_sort__array_insert2(child->remaining_ranges,
+                                              &split_range2, 1));
             }
         }
     }
+  return SVN_NO_ERROR;
 }
 
 /* Helper for do_directory_merge().
@@ -5977,7 +6024,7 @@ slice_remaining_ranges(apr_array_header_
    If a range is removed from a child's remaining_ranges array, allocate the
    new remaining_ranges array in POOL.
  */
-static void
+static svn_error_t *
 remove_first_range_from_remaining_ranges(svn_revnum_t revision,
                                          apr_array_header_t
                                            *children_with_mergeinfo,
@@ -5998,10 +6045,11 @@ remove_first_range_from_remaining_ranges
             APR_ARRAY_IDX(child->remaining_ranges, 0, svn_merge_range_t *);
           if (first_range->end == revision)
             {
-              svn_sort__array_delete(child->remaining_ranges, 0, 1);
+              SVN_ERR(svn_sort__array_delete2(child->remaining_ranges, 0, 1));
             }
         }
     }
+  return SVN_NO_ERROR;
 }
 
 /* Get a file's content and properties from the repository.
@@ -6087,7 +6135,7 @@ get_child_with_mergeinfo(const apr_array
        out of order and then sort afterwards. (One caller is doing a qsort
        after calling this anyway.)
  */
-static void
+static svn_error_t *
 insert_child_to_merge(apr_array_header_t *children_with_mergeinfo,
                       const svn_client__merge_path_t *insert_element,
                       apr_pool_t *pool)
@@ -6101,7 +6149,9 @@ insert_child_to_merge(apr_array_header_t
                                   compare_merge_path_t_as_paths);
 
   new_element = svn_client__merge_path_dup(insert_element, pool);
-  svn_sort__array_insert(children_with_mergeinfo, &new_element, insert_index);
+  SVN_ERR(svn_sort__array_insert2(children_with_mergeinfo,
+                                  &new_element, insert_index));
+  return SVN_NO_ERROR;
 }
 
 /* Helper for get_mergeinfo_paths().
@@ -6162,7 +6212,7 @@ insert_parent_and_sibs_of_sw_absent_del_
       parent->missing_child = child->absent;
       parent->switched_child = child->switched;
       /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
-      insert_child_to_merge(children_with_mergeinfo, parent, pool);
+      SVN_ERR(insert_child_to_merge(children_with_mergeinfo, parent, pool));
       /* Increment for loop index so we don't process the inserted element. */
       (*curr_index)++;
     } /*(parent == NULL) */
@@ -6199,8 +6249,8 @@ insert_parent_and_sibs_of_sw_absent_del_
 
           sibling_of_missing = svn_client__merge_path_create(child_abspath,
                                                              pool);
-          insert_child_to_merge(children_with_mergeinfo, sibling_of_missing,
-                                pool);
+          SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                        sibling_of_missing, pool));
         }
     }
 
@@ -6541,8 +6591,8 @@ get_mergeinfo_paths(apr_array_header_t *
                svn_client__merge_path_t *switched_child =
                  svn_client__merge_path_create(wc_path, result_pool);
                switched_child->switched = TRUE;
-               insert_child_to_merge(children_with_mergeinfo, switched_child,
-                                     result_pool);
+               SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                             switched_child, result_pool));
              }
         }
     }
@@ -6594,8 +6644,8 @@ get_mergeinfo_paths(apr_array_header_t *
             }
 
           if (new_shallow_child)
-            insert_child_to_merge(children_with_mergeinfo, shallow_child,
-                                  result_pool);
+            SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                          shallow_child, result_pool));
        }
     }
 
@@ -6624,8 +6674,8 @@ get_mergeinfo_paths(apr_array_header_t *
                svn_client__merge_path_t *absent_child =
                  svn_client__merge_path_create(wc_path, result_pool);
                absent_child->absent = TRUE;
-               insert_child_to_merge(children_with_mergeinfo, absent_child,
-                                     result_pool);
+               SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                             absent_child, result_pool));
              }
         }
     }
@@ -6638,8 +6688,8 @@ get_mergeinfo_paths(apr_array_header_t *
       svn_client__merge_path_t *target_child =
         svn_client__merge_path_create(target->abspath,
                                       result_pool);
-      insert_child_to_merge(children_with_mergeinfo, target_child,
-                            result_pool);
+      SVN_ERR(insert_child_to_merge(children_with_mergeinfo, target_child,
+                                    result_pool));
     }
 
   /* Case 8: Path is an immediate *directory* child of
@@ -6682,8 +6732,8 @@ get_mergeinfo_paths(apr_array_header_t *
                       && depth == svn_depth_immediates)
                     immediate_child->immediate_child_dir = TRUE;
 
-                  insert_child_to_merge(children_with_mergeinfo,
-                                        immediate_child, result_pool);
+                  SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                                immediate_child, result_pool));
                 }
             }
         }
@@ -6775,9 +6825,9 @@ get_mergeinfo_paths(apr_array_header_t *
                   child_of_noninheritable =
                     svn_client__merge_path_create(child_abspath, result_pool);
                   child_of_noninheritable->child_of_noninheritable = TRUE;
-                  insert_child_to_merge(children_with_mergeinfo,
-                                        child_of_noninheritable,
-                                        result_pool);
+                  SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                                child_of_noninheritable,
+                                                result_pool));
                   if (!dry_run && same_repos)
                     {
                       svn_mergeinfo_t mergeinfo;
@@ -7201,7 +7251,7 @@ normalize_merge_sources_internal(apr_arr
                   new_segment->path = original_repos_relpath;
                   new_segment->range_start = original_revision;
                   new_segment->range_end = original_revision;
-                  svn_sort__array_insert(segments, &new_segment, 0);
+                  SVN_ERR(svn_sort__array_insert2(segments, &new_segment, 0));
                 }
             }
         }
@@ -7596,16 +7646,15 @@ do_file_merge(svn_mergeinfo_catalog_t re
 
           /* ### Create a fake copy of merge_target as we don't keep
                  remaining_ranges in sync (yet). */
-          target_info = apr_pcalloc(scratch_pool, sizeof(*target_info));
-
-          target_info->abspath = merge_target->abspath;
+          target_info = svn_client__merge_path_create(merge_target->abspath,
+                                                      scratch_pool);
           target_info->remaining_ranges = ranges_to_merge;
 
           APR_ARRAY_PUSH(child_with_mergeinfo, svn_client__merge_path_t *)
                                     = target_info;
 
           /* And store in baton to allow using it from notify_merge_begin() */
-          merge_b->notify_begin.nodes_with_mergeinfo = child_with_mergeinfo;
+          merge_b->children_with_mergeinfo = child_with_mergeinfo;
         }
 
       while (ranges_to_merge->nelts > 0)
@@ -7648,19 +7697,10 @@ do_file_merge(svn_mergeinfo_catalog_t re
              do a text-n-props merge; otherwise, do a delete-n-add merge. */
           if (! (merge_b->diff_ignore_ancestry || sources_related))
             {
-              struct merge_dir_baton_t dir_baton;
+              void *dir_baton = open_dir_for_replace_single_file(iterpool);
               void *file_baton;
               svn_boolean_t skip;
 
-              /* Initialize minimal dir baton to allow calculating 'R'eplace
-                 from 'D'elete + 'A'dd. */
-
-              memset(&dir_baton, 0, sizeof(dir_baton));
-              dir_baton.pool = iterpool;
-              dir_baton.tree_conflict_reason = CONFLICT_REASON_NONE;
-              dir_baton.tree_conflict_action = svn_wc_conflict_action_edit;
-              dir_baton.skip_reason = svn_wc_notify_state_unknown;
-
               /* Delete... */
               file_baton = NULL;
               skip = FALSE;
@@ -7668,7 +7708,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                              left_source,
                                              NULL /* right_source */,
                                              NULL /* copyfrom_source */,
-                                             &dir_baton,
+                                             dir_baton,
                                              processor,
                                              iterpool, iterpool));
               if (! skip)
@@ -7687,7 +7727,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                              NULL /* left_source */,
                                              right_source,
                                              NULL /* copyfrom_source */,
-                                             &dir_baton,
+                                             dir_baton,
                                              processor,
                                              iterpool, iterpool));
               if (! skip)
@@ -7758,7 +7798,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
              (This list is used from notify_merge_begin)
 
             Directory merges use remove_first_range_from_remaining_ranges() */
-          svn_sort__array_delete(ranges_to_merge, 0, 1);
+          SVN_ERR(svn_sort__array_delete2(ranges_to_merge, 0, 1));
         }
       merge_b->notify_begin.last_abspath = NULL;
     } /* !merge_b->record_only */
@@ -7819,7 +7859,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
         }
     }
 
-  merge_b->notify_begin.nodes_with_mergeinfo = NULL;
+  merge_b->children_with_mergeinfo = NULL;
 
   svn_pool_destroy(iterpool);
 
@@ -7878,7 +7918,7 @@ process_children_with_new_mergeinfo(merg
          was added (with preexisting mergeinfo) by the merge.  That's actually
          more correct, since the inherited mergeinfo likely describes
          non-existent or unrelated merge history, but it's not quite so simple
-         as that, see http://subversion.tigris.org/issues/show_bug.cgi?id=4309
+         as that, see https://issues.apache.org/jira/browse/SVN-4309
          */
 
       /* Get the path's new explicit mergeinfo... */
@@ -7945,7 +7985,8 @@ process_children_with_new_mergeinfo(merg
               /* Set the path's remaining_ranges equal to its parent's. */
               new_child->remaining_ranges = svn_rangelist_dup(
                  parent->remaining_ranges, pool);
-              insert_child_to_merge(children_with_mergeinfo, new_child, pool);
+              SVN_ERR(insert_child_to_merge(children_with_mergeinfo,
+                                            new_child, pool));
             }
         }
     }
@@ -8269,7 +8310,7 @@ flag_subtrees_needing_mergeinfo(svn_bool
       merge_b->target->abspath, depth, merge_b->ctx->wc_ctx,
       merge_b->ra_session1, scratch_pool, iterpool));
 
-  /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
+  /* Issue #4056: Walk CHILDREN_WITH_MERGEINFO reverse depth-first
      order.  This way each child knows if it has operative missing/switched
      children which necessitates non-inheritable mergeinfo. */
   for (i = children_with_mergeinfo->nelts - 1; i >= 0; i--)
@@ -8432,7 +8473,7 @@ flag_subtrees_needing_mergeinfo(svn_bool
         }
       else /* child->record_mergeinfo */
         {
-          /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
+          /* If CHILD is in CHILDREN_WITH_MERGEINFO simply
              because it had no explicit mergeinfo of its own at the
              start of the merge but is the child of of some path with
              non-inheritable mergeinfo, then the explicit mergeinfo it
@@ -8457,7 +8498,7 @@ flag_subtrees_needing_mergeinfo(svn_bool
    If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
    MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
    MERGEINFO_FSPATH to the merge target (and possibly its subtrees) described
-   by NOTIFY_B->CHILDREN_WITH_MERGEINFO -- see the global comment
+   by CHILDREN_WITH_MERGEINFO -- see the global comment
    'THE CHILDREN_WITH_MERGEINFO ARRAY'.  Obviously this should only
    be called if recording mergeinfo -- see doc string for RECORD_MERGEINFO().
 
@@ -8508,10 +8549,10 @@ record_mergeinfo_for_dir_merge(svn_merge
     range.inheritable = TRUE;
 
   /* Remove absent children at or under MERGE_B->target->abspath from
-     NOTIFY_B->CHILDREN_WITH_MERGEINFO
+     CHILDREN_WITH_MERGEINFO
      before we calculate the merges performed. */
-  remove_absent_children(merge_b->target->abspath,
-                         children_with_mergeinfo);
+  SVN_ERR(remove_absent_children(merge_b->target->abspath,
+                                 children_with_mergeinfo));
 
   /* Determine which subtrees of interest need mergeinfo recorded... */
   SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
@@ -9334,7 +9375,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
   /* Point our RA_SESSION to the URL of our youngest merge source side. */
   ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2;
 
-  /* Fill NOTIFY_B->CHILDREN_WITH_MERGEINFO with child paths (const
+  /* Fill CHILDREN_WITH_MERGEINFO with child paths (const
      svn_client__merge_path_t *) which might have intersecting merges
      because they meet one or more of the criteria described in
      get_mergeinfo_paths(). Here the paths are arranged in a depth
@@ -9344,13 +9385,13 @@ do_mergeinfo_aware_dir_merge(svn_mergein
                               merge_b->dry_run, merge_b->same_repos,
                               merge_b->ctx, scratch_pool, scratch_pool));
 
-  /* The first item from the NOTIFY_B->CHILDREN_WITH_MERGEINFO is always
+  /* The first item from the CHILDREN_WITH_MERGEINFO is always
      the target thanks to depth-first ordering. */
   target_merge_path = APR_ARRAY_IDX(children_with_mergeinfo, 0,
                                     svn_client__merge_path_t *);
 
   /* If we are honoring mergeinfo, then for each item in
-     NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
+     CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be
      merged, and then merge it.  Otherwise, we just merge what we were asked
      to merge across the whole tree.  */
   SVN_ERR(populate_remaining_ranges(children_with_mergeinfo,
@@ -9370,7 +9411,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
 
       /* The merge target TARGET_ABSPATH and/or its subtrees may not need all
          of SOURCE->rev1:rev2 applied.  So examine
-         NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest starting
+         CHILDREN_WITH_MERGEINFO to find the oldest starting
          revision that actually needs to be merged (for reverse merges this is
          the youngest starting revision).
 
@@ -9408,7 +9449,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
       /* Is there anything to merge? */
       if (SVN_IS_VALID_REVNUM(start_rev))
         {
-          /* Now examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the oldest
+          /* Now examine CHILDREN_WITH_MERGEINFO to find the oldest
              ending revision that actually needs to be merged (for reverse
              merges this is the youngest ending revision). */
            svn_revnum_t end_rev =
@@ -9417,7 +9458,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
 
           /* While END_REV is valid, do the following:
 
-             1. Tweak each NOTIFY_B->CHILDREN_WITH_MERGEINFO element so that
+             1. Tweak each CHILDREN_WITH_MERGEINFO element so that
                 the element's remaining_ranges member has as its first element
                 a range that ends with end_rev.
 
@@ -9425,17 +9466,17 @@ do_mergeinfo_aware_dir_merge(svn_mergein
                 on MERGE_B->target->abspath for start_rev:end_rev.
 
              3. Remove the first element from each
-                NOTIFY_B->CHILDREN_WITH_MERGEINFO element's remaining_ranges
+                CHILDREN_WITH_MERGEINFO element's remaining_ranges
                 member.
 
-             4. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the 
most
+             4. Again examine CHILDREN_WITH_MERGEINFO to find the most
                 inclusive starting revision that actually needs to be merged 
and
                 update start_rev.  This prevents us from needlessly contacting 
the
                 repository and doing a diff where we describe the entire target
                 tree as *not* needing any of the requested range.  This can 
happen
                 whenever we have mergeinfo with gaps in it for the merge 
source.
 
-             5. Again examine NOTIFY_B->CHILDREN_WITH_MERGEINFO to find the 
most
+             5. Again examine CHILDREN_WITH_MERGEINFO to find the most
                 inclusive ending revision that actually needs to be merged and
                 update end_rev.
 
@@ -9477,8 +9518,9 @@ do_mergeinfo_aware_dir_merge(svn_mergein
 
               svn_pool_clear(iterpool);
 
-              slice_remaining_ranges(children_with_mergeinfo,
-                                     is_rollback, end_rev, scratch_pool);
+              SVN_ERR(slice_remaining_ranges(children_with_mergeinfo,
+                                             is_rollback, end_rev,
+                                             scratch_pool));
 
               /* Reset variables that must be reset for every drive */
               merge_b->notify_begin.last_abspath = NULL;
@@ -9496,23 +9538,23 @@ do_mergeinfo_aware_dir_merge(svn_mergein
               /* If any paths picked up explicit mergeinfo as a result of
                  the merge we need to make sure any mergeinfo those paths
                  inherited is recorded and then add these paths to
-                 NOTIFY_B->CHILDREN_WITH_MERGEINFO.*/
+                 CHILDREN_WITH_MERGEINFO.*/
               SVN_ERR(process_children_with_new_mergeinfo(
                         merge_b, children_with_mergeinfo,
                         scratch_pool));
 
               /* If any subtrees had their explicit mergeinfo deleted as a
                  result of the merge then remove these paths from
-                 NOTIFY_B->CHILDREN_WITH_MERGEINFO since there is no need
+                 CHILDREN_WITH_MERGEINFO since there is no need
                  to consider these subtrees for subsequent editor drives
                  nor do we want to record mergeinfo on them describing
                  the merge itself. */
-              remove_children_with_deleted_mergeinfo(
-                merge_b, children_with_mergeinfo);
+              SVN_ERR(remove_children_with_deleted_mergeinfo(
+                        merge_b, children_with_mergeinfo));
 
               /* Prepare for the next iteration (if any). */
-              remove_first_range_from_remaining_ranges(
-                end_rev, children_with_mergeinfo, scratch_pool);
+              SVN_ERR(remove_first_range_from_remaining_ranges(
+                        end_rev, children_with_mergeinfo, scratch_pool));
 
               /* If we raised any conflicts, break out and report how much
                  we have merged. */
@@ -9634,7 +9676,7 @@ do_directory_merge(svn_mergeinfo_catalog
     apr_array_make(scratch_pool, 16, sizeof(svn_client__merge_path_t *));
 
   /* And make it read-only accessible from the baton */
-  merge_b->notify_begin.nodes_with_mergeinfo = children_with_mergeinfo;
+  merge_b->children_with_mergeinfo = children_with_mergeinfo;
 
   /* If we are not honoring mergeinfo we can skip right to the
      business of merging changes! */
@@ -9652,7 +9694,7 @@ do_directory_merge(svn_mergeinfo_catalog
                                            processor, depth,
                                            merge_b, result_pool, 
scratch_pool));
 
-  merge_b->notify_begin.nodes_with_mergeinfo = NULL;
+  merge_b->children_with_mergeinfo = NULL;
 
   return SVN_NO_ERROR;
 }
@@ -9889,28 +9931,13 @@ do_merge(apr_hash_t **modified_subtrees,
   merge_cmd_baton.added_abspaths = apr_hash_make(result_pool);
   merge_cmd_baton.tree_conflicted_abspaths = apr_hash_make(result_pool);
 
-  {
-    svn_diff_tree_processor_t *merge_processor;
-
-    merge_processor = svn_diff__tree_processor_create(&merge_cmd_baton,
-                                                      scratch_pool);
-
-    merge_processor->dir_opened   = merge_dir_opened;
-    merge_processor->dir_changed  = merge_dir_changed;
-    merge_processor->dir_added    = merge_dir_added;
-    merge_processor->dir_deleted  = merge_dir_deleted;
-    merge_processor->dir_closed   = merge_dir_closed;
-
-    merge_processor->file_opened  = merge_file_opened;
-    merge_processor->file_changed = merge_file_changed;
-    merge_processor->file_added   = merge_file_added;
-    merge_processor->file_deleted = merge_file_deleted;
-    /* Not interested in file_closed() */
-
-    merge_processor->node_absent = merge_node_absent;
+  merge_cmd_baton.notify_func = notify_merging;
+  merge_cmd_baton.notify_baton = &merge_cmd_baton.notify_begin;
+  merge_cmd_baton.notify_begin.merge_b = &merge_cmd_baton;
+  merge_cmd_baton.notify_begin.notify_func2 = ctx->notify_func2;
+  merge_cmd_baton.notify_begin.notify_baton2 = ctx->notify_baton2;
 
-    processor = merge_processor;
-  }
+  processor = merge_apply_processor(&merge_cmd_baton, scratch_pool);
 
   if (src_session)
     {

Modified: subversion/branches/addremove/subversion/libsvn_client/mergeinfo.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/mergeinfo.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/mergeinfo.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_client/mergeinfo.c Sat May 
23 14:16:56 2020
@@ -1749,7 +1749,7 @@ svn_client__mergeinfo_log(svn_boolean_t
       if (*target_mergeinfo_catalog)
         {
           /* The caller provided the mergeinfo catalog for
-             TARGET_PATH_OR_URL, so we don't need to accquire
+             TARGET_PATH_OR_URL, so we don't need to acquire
              it ourselves.  We do need to get the repos_root
              though, because get_mergeinfo() won't do it for us. */
           target_mergeinfo_cat = *target_mergeinfo_catalog;

Modified: subversion/branches/addremove/subversion/libsvn_client/mergeinfo.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/mergeinfo.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/mergeinfo.h 
(original)
+++ subversion/branches/addremove/subversion/libsvn_client/mergeinfo.h Sat May 
23 14:16:56 2020
@@ -316,7 +316,7 @@ svn_client__get_history_as_mergeinfo(svn
 
 /* Parse any explicit mergeinfo on LOCAL_ABSPATH and store it in
    *MERGEINFO.  If no record of any mergeinfo exists, set *MERGEINFO to NULL.
-   Does not acount for inherited mergeinfo.
+   Does not account for inherited mergeinfo.
 
    Allocate the result deeply in @a result_pool. */
 svn_error_t *

Modified: subversion/branches/addremove/subversion/libsvn_client/mtcc.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/mtcc.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/mtcc.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/mtcc.c Sat May 23 
14:16:56 2020
@@ -453,7 +453,8 @@ mtcc_verify_create(svn_client__mtcc_t *m
 
       if (op)
         return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
-                                 _("Path '%s' already exists"),
+                                 _("Path '%s' already exists, or was created "
+                                   "by an earlier operation"),
                                  new_relpath);
 
       SVN_ERR(mtcc_op_find(&op, NULL, new_relpath, mtcc->root_op, TRUE, TRUE,
@@ -604,7 +605,7 @@ mtcc_op_contains_non_delete(const mtcc_o
 static svn_error_t *
 mtcc_add_delete(const char *relpath,
                 svn_boolean_t for_move,
-                svn_client__mtcc_t *mtcc,                
+                svn_client__mtcc_t *mtcc,
                 apr_pool_t *scratch_pool)
 {
   mtcc_op_t *op;
@@ -636,7 +637,7 @@ mtcc_add_delete(const char *relpath,
         {
           /* Allow deleting directories, that are unmodified except for
               one or more deleted descendants */
-          
+
           SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, TRUE,
                   FALSE, FALSE, mtcc->pool, scratch_pool));
 

Modified: subversion/branches/addremove/subversion/libsvn_client/patch.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/patch.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/patch.c Sat May 23 
14:16:56 2020
@@ -343,7 +343,9 @@ strip_path(const char **result, const ch
   components = svn_path_decompose(path, scratch_pool);
   if (strip_count > components->nelts)
     return svn_error_createf(SVN_ERR_CLIENT_PATCH_BAD_STRIP_COUNT, NULL,
-                             _("Cannot strip %u components from '%s'"),
+                             Q_("Cannot strip %u component from '%s'",
+                                "Cannot strip %u components from '%s'",
+                                strip_count),
                              strip_count,
                              svn_dirent_local_style(path, scratch_pool));
 
@@ -1018,6 +1020,7 @@ init_patch_target(patch_target_t **patch
   target_content_t *content;
   svn_boolean_t has_text_changes = FALSE;
   svn_boolean_t follow_moves;
+  const char *tempdir_abspath;
 
   has_text_changes = ((patch->hunks && patch->hunks->nelts > 0)
                       || patch->binary_patch);
@@ -1223,8 +1226,10 @@ init_patch_target(patch_target_t **patch
         }
 
       /* Open a temporary file to write the patched result to. */
+      SVN_ERR(svn_wc__get_tmpdir(&tempdir_abspath, wc_ctx,
+          target->local_abspath, scratch_pool, scratch_pool));
       SVN_ERR(svn_io_open_unique_file3(&target->patched_file,
-                                       &target->patched_path, NULL,
+                                       &target->patched_path, tempdir_abspath,
                                        remove_tempfiles ?
                                          svn_io_file_del_on_pool_cleanup :
                                          svn_io_file_del_none,
@@ -1236,7 +1241,7 @@ init_patch_target(patch_target_t **patch
 
       /* Open a temporary stream to write rejected hunks to. */
       SVN_ERR(svn_stream_open_unique(&target->reject_stream,
-                                     &target->reject_path, NULL,
+                                     &target->reject_path, tempdir_abspath,
                                      remove_tempfiles ?
                                          svn_io_file_del_on_pool_cleanup :
                                          svn_io_file_del_none,
@@ -2145,8 +2150,8 @@ reject_hunk(patch_target_t *target, targ
   if (prop_name)
     {
       /* ### Print 'Added', 'Deleted' or 'Modified' instead of 'Property'. */
-      svn_stream_printf(target->reject_stream,
-                        pool, "Property: %s" APR_EOL_STR, prop_name);
+      SVN_ERR(svn_stream_printf(target->reject_stream,
+                                pool, "Property: %s" APR_EOL_STR, prop_name));
       atat = prop_atat;
     }
   else
@@ -2465,7 +2470,7 @@ send_patch_notification(const patch_targ
 
 /* Implements the callback for svn_sort__array.  Puts hunks that match
    before hunks that do not match, puts hunks that match in order
-   based on postion matched, puts hunks that do not match in order
+   based on position matched, puts hunks that do not match in order
    based on original position. */
 static int
 sort_matched_hunks(const void *a, const void *b)
@@ -2511,7 +2516,8 @@ sort_matched_hunks(const void *a, const
  * in RESULT_POOL. Use WC_CTX as the working copy context.
  * STRIP_COUNT specifies the number of leading path components
  * which should be stripped from target paths in the patch.
- * REMOVE_TEMPFILES, PATCH_FUNC, and PATCH_BATON as in svn_client_patch().
+ * REMOVE_TEMPFILES is as in svn_client_patch().
+ * TARGETS_INFO is for preserving info across calls.
  * IGNORE_WHITESPACE tells whether whitespace should be considered when
  * doing the matching.
  * Call cancel CANCEL_FUNC with baton CANCEL_BATON to trigger cancellation.

Modified: subversion/branches/addremove/subversion/libsvn_client/ra.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/ra.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/ra.c Sat May 23 
14:16:56 2020
@@ -402,8 +402,7 @@ svn_client__open_ra_session_internal(svn
         }
     }
 
-  /* If the caller allows for auto-following redirections, and the
-     RA->open() call above reveals a CORRECTED_URL, try the new URL.
+  /* If the caller allows for auto-following redirections, try the new URL.
      We'll do this in a loop up to some maximum number follow-and-retry
      attempts.  */
   if (corrected_url)
@@ -414,12 +413,14 @@ svn_client__open_ra_session_internal(svn
       *corrected_url = NULL;
       while (attempts_left--)
         {
-          const char *corrected = NULL;
+          const char *corrected = NULL; /* canonicalized version */
+          const char *redirect_url = NULL; /* non-canonicalized version */
 
           /* Try to open the RA session.  If this is our last attempt,
              don't accept corrected URLs from the RA provider. */
-          SVN_ERR(svn_ra_open4(ra_session,
+          SVN_ERR(svn_ra_open5(ra_session,
                                attempts_left == 0 ? NULL : &corrected,
+                               attempts_left == 0 ? NULL : &redirect_url,
                                base_url, uuid, cbtable, cb, ctx->config,
                                result_pool));
 
@@ -441,19 +442,28 @@ svn_client__open_ra_session_internal(svn
           *corrected_url = corrected;
 
           /* Make sure we've not attempted this URL before. */
-          if (svn_hash_gets(attempted, corrected))
+          if (svn_hash_gets(attempted, redirect_url))
             return svn_error_createf(SVN_ERR_CLIENT_CYCLE_DETECTED, NULL,
                                      _("Redirect cycle detected for URL '%s'"),
-                                     corrected);
+                                     redirect_url);
+
+          /*
+           * Remember this redirect URL so we don't wind up in a loop.
+           *
+           * Store the non-canonicalized version of the URL. The canonicalized
+           * version is insufficient for loop detection because we might not 
get
+           * an exact match against URLs used by the RA protocol-layer (the URL
+           * used by the protocol may contain trailing slashes, for example,
+           * which are stripped during canonicalization).
+           */
+          svn_hash_sets(attempted, redirect_url, (void *)1);
 
-          /* Remember this CORRECTED_URL so we don't wind up in a loop. */
-          svn_hash_sets(attempted, corrected, (void *)1);
           base_url = corrected;
         }
     }
   else
     {
-      SVN_ERR(svn_ra_open4(ra_session, NULL, base_url,
+      SVN_ERR(svn_ra_open5(ra_session, NULL, NULL, base_url,
                            uuid, cbtable, cb, ctx->config, result_pool));
     }
 

Modified: subversion/branches/addremove/subversion/libsvn_client/repos_diff.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/repos_diff.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/repos_diff.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_client/repos_diff.c Sat May 
23 14:16:56 2020
@@ -51,6 +51,7 @@
 #include "private/svn_subr_private.h"
 #include "private/svn_wc_private.h"
 #include "private/svn_editor.h"
+#include "private/svn_sorts_private.h"
 
 /* Overall crawler editor baton.  */
 struct edit_baton {
@@ -380,10 +381,10 @@ get_file_from_ra(struct file_baton *fb,
      way.  Hence this little hack:  We populate FILE_BATON->PROPCHANGES only
      with *actual* property changes.
 
-     See http://subversion.tigris.org/issues/show_bug.cgi?id=3657#desc9 and
+     See https://issues.apache.org/jira/browse/SVN-3657#desc9 and
      http://svn.haxx.se/dev/archive-2010-08/0351.shtml for more details.
  */
-static void
+static svn_error_t *
 remove_non_prop_changes(apr_hash_t *pristine_props,
                         apr_array_header_t *changes)
 {
@@ -391,7 +392,7 @@ remove_non_prop_changes(apr_hash_t *pris
 
   /* For added nodes, there is nothing to filter. */
   if (apr_hash_count(pristine_props) == 0)
-    return;
+    return SVN_NO_ERROR;
 
   for (i = 0; i < changes->nelts; i++)
     {
@@ -404,18 +405,13 @@ remove_non_prop_changes(apr_hash_t *pris
 
           if (old_val && svn_string_compare(old_val, change->value))
             {
-              int j;
-
-              /* Remove the matching change by shifting the rest */
-              for (j = i; j < changes->nelts - 1; j++)
-                {
-                  APR_ARRAY_IDX(changes, j, svn_prop_t)
-                       = APR_ARRAY_IDX(changes, j+1, svn_prop_t);
-                }
-              changes->nelts--;
+              /* Remove the matching change and re-check the current index */
+              SVN_ERR(svn_sort__array_delete2(changes, i, 1));
+              i--;
             }
         }
     }
+  return SVN_NO_ERROR;
 }
 
 /* Get the empty file associated with the edit baton. This is cached so
@@ -1015,7 +1011,7 @@ close_file(void *file_baton,
         }
 
       if (fb->pristine_props)
-        remove_non_prop_changes(fb->pristine_props, fb->propchanges);
+        SVN_ERR(remove_non_prop_changes(fb->pristine_props, fb->propchanges));
 
       right_props = svn_prop__patch(fb->pristine_props, fb->propchanges,
                                     fb->pool);
@@ -1088,7 +1084,7 @@ close_directory(void *dir_baton,
 
       if (db->propchanges->nelts > 0)
         {
-          remove_non_prop_changes(pristine_props, db->propchanges);
+          SVN_ERR(remove_non_prop_changes(pristine_props, db->propchanges));
         }
 
       if (db->propchanges->nelts > 0 || db->added)

Modified: subversion/branches/addremove/subversion/libsvn_client/revert.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/revert.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/revert.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/revert.c Sat May 23 
14:16:56 2020
@@ -51,42 +51,32 @@ struct revert_with_write_lock_baton {
   const apr_array_header_t *changelists;
   svn_boolean_t clear_changelists;
   svn_boolean_t metadata_only;
+  svn_boolean_t added_keep_local;
   svn_client_ctx_t *ctx;
 };
 
 /* (Note: All arguments are in the baton above.)
 
-   Attempt to revert LOCAL_ABSPATH.
+   Attempt to revert LOCAL_ABSPATH by calling svn_wc_revert6(), which
+   see for further details.
 
-   If DEPTH is svn_depth_empty, revert just the properties on the
-   directory; else if svn_depth_files, revert the properties and any
-   files immediately under the directory; else if
-   svn_depth_immediates, revert all of the preceding plus properties
-   on immediate subdirectories; else if svn_depth_infinity, revert
-   path and everything under it fully recursively.
-
-   CHANGELISTS is an array of const char * changelist names, used as a
-   restrictive filter on items reverted; that is, don't revert any
-   item unless it's a member of one of those changelists.  If
-   CHANGELISTS is empty (or altogether NULL), no changelist filtering occurs.
-
-   Consult CTX to determine whether or not to revert timestamp to the
-   time of last commit ('use-commit-times = yes').
-
-   If PATH is unversioned, return SVN_ERR_UNVERSIONED_RESOURCE. */
+   If the target isn't versioned, send a 'skip' notification and return
+   no error.
+ */
 static svn_error_t *
 revert(void *baton, apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
   struct revert_with_write_lock_baton *b = baton;
   svn_error_t *err;
 
-  err = svn_wc_revert5(b->ctx->wc_ctx,
+  err = svn_wc_revert6(b->ctx->wc_ctx,
                        b->local_abspath,
                        b->depth,
                        b->use_commit_times,
                        b->changelists,
                        b->clear_changelists,
                        b->metadata_only,
+                       b->added_keep_local,
                        b->ctx->cancel_func, b->ctx->cancel_baton,
                        b->ctx->notify_func2, b->ctx->notify_baton2,
                        scratch_pool);
@@ -123,11 +113,12 @@ revert(void *baton, apr_pool_t *result_p
 
 
 svn_error_t *
-svn_client_revert3(const apr_array_header_t *paths,
+svn_client_revert4(const apr_array_header_t *paths,
                    svn_depth_t depth,
                    const apr_array_header_t *changelists,
                    svn_boolean_t clear_changelists,
                    svn_boolean_t metadata_only,
+                   svn_boolean_t added_keep_local,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *pool)
 {
@@ -183,6 +174,7 @@ svn_client_revert3(const apr_array_heade
       baton.changelists = changelists;
       baton.clear_changelists = clear_changelists;
       baton.metadata_only = metadata_only;
+      baton.added_keep_local = added_keep_local;
       baton.ctx = ctx;
 
       err = svn_wc__is_wcroot(&wc_root, ctx->wc_ctx, local_abspath, iterpool);

Modified: subversion/branches/addremove/subversion/libsvn_client/revisions.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/revisions.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/revisions.c 
(original)
+++ subversion/branches/addremove/subversion/libsvn_client/revisions.c Sat May 
23 14:16:56 2020
@@ -146,7 +146,14 @@ svn_client__get_revision_number(svn_revn
                                                           scratch_pool));
 
         if (revision->kind == svn_opt_revision_previous)
-          (*revnum)--;
+          {
+            if (*revnum == 0)
+              return svn_error_createf(
+                  SVN_ERR_CLIENT_BAD_REVISION, NULL,
+                  _("Path '%s' has no previous revision"),
+                  svn_dirent_local_style(local_abspath, scratch_pool));
+            --(*revnum);
+          }
       }
       break;
 

Modified: subversion/branches/addremove/subversion/libsvn_client/status.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/status.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/status.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/status.c Sat May 23 
14:16:56 2020
@@ -23,6 +23,9 @@
 
 /* ==================================================================== */
 
+/* We define this here to remove any further warnings about the usage of
+   experimental functions in this file. */
+#define SVN_EXPERIMENTAL
 
 
 /*** Includes. ***/
@@ -41,6 +44,7 @@
 #include "svn_error.h"
 #include "svn_hash.h"
 
+#include "private/svn_client_shelf.h"
 #include "private/svn_client_private.h"
 #include "private/svn_sorts_private.h"
 #include "private/svn_wc_private.h"
@@ -329,6 +333,79 @@ do_external_status(svn_client_ctx_t *ctx
 
   return SVN_NO_ERROR;
 }
+
+/* Run status on shelf SHELF_NAME, if it exists.
+ */
+static svn_error_t *
+shelf_status(const char *shelf_name,
+             const char *target_abspath,
+             svn_wc_status_func4_t status_func,
+             void *status_baton,
+             svn_client_ctx_t *ctx,
+             apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  svn_client__shelf_t *shelf;
+  svn_client__shelf_version_t *shelf_version;
+  const char *wc_relpath;
+
+  err = svn_client__shelf_open_existing(&shelf,
+                                       shelf_name, target_abspath,
+                                       ctx, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_ILLEGAL_TARGET)
+    {
+      svn_error_clear(err);
+      return SVN_NO_ERROR;
+    }
+  else
+    SVN_ERR(err);
+
+  SVN_ERR(svn_client__shelf_version_open(&shelf_version,
+                                        shelf, shelf->max_version,
+                                        scratch_pool, scratch_pool));
+  wc_relpath = svn_dirent_skip_ancestor(shelf->wc_root_abspath, 
target_abspath);
+  SVN_ERR(svn_client__shelf_version_status_walk(shelf_version, wc_relpath,
+                                               status_func, status_baton,
+                                               scratch_pool));
+  SVN_ERR(svn_client__shelf_close(shelf, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Run status on all shelves named in CHANGELISTS by a changelist name
+ * of the form "svn:shelf:SHELF_NAME", if they exist.
+ */
+static svn_error_t *
+shelves_status(const apr_array_header_t *changelists,
+               const char *target_abspath,
+               svn_wc_status_func4_t status_func,
+               void *status_baton,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *scratch_pool)
+{
+  static const char PREFIX[] = "svn:shelf:";
+  static const int PREFIX_LEN = 10;
+  int i;
+
+  if (! changelists)
+    return SVN_NO_ERROR;
+  for (i = 0; i < changelists->nelts; i++)
+    {
+      const char *cl = APR_ARRAY_IDX(changelists, i, const char *);
+
+      if (strncmp(cl, PREFIX, PREFIX_LEN) == 0)
+        {
+          const char *shelf_name = cl + PREFIX_LEN;
+
+          SVN_ERR(shelf_status(shelf_name, target_abspath,
+                               status_func, status_baton,
+                               ctx, scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** Public Interface. ***/
 
@@ -586,6 +663,9 @@ svn_client_status6(svn_revnum_t *result_
     }
   else
     {
+      SVN_ERR(shelves_status(changelists, target_abspath,
+                             tweak_status, &sb,
+                             ctx, pool));
       err = svn_wc_walk_status(ctx->wc_ctx, target_abspath,
                                depth, get_all, no_ignore, FALSE, ignores,
                                tweak_status, &sb,

Modified: subversion/branches/addremove/subversion/libsvn_client/switch.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/switch.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/switch.c Sat May 23 
14:16:56 2020
@@ -216,7 +216,7 @@ switch_internal(svn_revnum_t *result_rev
                              anchor_url, switch_loc->repos_root_url);
 
   /* If we're not ignoring ancestry, then error out if the switch
-     source and target don't have a common ancestory.
+     source and target don't have a common ancestry.
 
      ### We're acting on the anchor here, not the target.  Is that
      ### okay? */
@@ -279,7 +279,7 @@ switch_internal(svn_revnum_t *result_rev
 
           /* If LOCAL_ABSPATH will be unswitched relative to its parent, then
              it doesn't need an iprop cache.  Note: It doesn't matter if
-             LOCAL_ABSPATH is withing a switched subtree, only if it's the
+             LOCAL_ABSPATH is within a switched subtree, only if it's the
              *root* of a switched subtree.*/
           if (strcmp(unswitched_url, switch_loc->url) == 0)
             needs_iprop_cache = FALSE;

Modified: subversion/branches/addremove/subversion/libsvn_client/update.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/update.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/update.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/update.c Sat May 23 
14:16:56 2020
@@ -96,7 +96,7 @@ svn_client__dirent_fetcher(void *baton,
    folder. ANCHOR_ABSPATH is the w/c root and LOCAL_ABSPATH will still
    be considered empty, if it is equal to ANCHOR_ABSPATH and only
    contains the admin sub-folder.
-   If the w/c folder already exists but cannot be openend, we return
+   If the w/c folder already exists but cannot be opened, we return
    "unclean" - just in case. Most likely, the caller will have to bail
    out later due to the same error we got here.
  */
@@ -182,6 +182,88 @@ record_conflict(svn_wc_conflict_result_t
   return SVN_NO_ERROR;
 }
 
+/* Perform post-update processing of externals defined below LOCAL_ABSPATH. */
+static svn_error_t *
+handle_externals(svn_boolean_t *timestamp_sleep,
+                 const char *local_abspath,
+                 svn_depth_t depth,
+                 const char *repos_root_url,
+                 svn_ra_session_t *ra_session,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *scratch_pool)
+{
+  apr_hash_t *new_externals;
+  apr_hash_t *new_depths;
+
+  SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
+                                               &new_depths,
+                                               ctx->wc_ctx, local_abspath,
+                                               depth,
+                                               scratch_pool, scratch_pool));
+
+  SVN_ERR(svn_client__handle_externals(new_externals,
+                                       new_depths,
+                                       repos_root_url, local_abspath,
+                                       depth, timestamp_sleep, ra_session,
+                                       ctx, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Try to reuse the RA session by reparenting it to the anchor_url.
+ * This code is probably overly cautious since we only use this
+ * currently when parents are missing and so all the anchor_urls
+ * have to be in the same repo.
+ * Note that ra_session_p is an (optional) input parameter as well
+ * as an output parameter. */
+static svn_error_t *
+reuse_ra_session(svn_ra_session_t **ra_session_p,
+                 const char **corrected_url,
+                 const char *anchor_url,
+                 const char *anchor_abspath,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  svn_ra_session_t *ra_session = *ra_session_p;
+
+  if (ra_session)
+    {
+      svn_error_t *err = svn_ra_reparent(ra_session, anchor_url, scratch_pool);
+      if (err)
+        {
+          if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
+            {
+            /* session changed repos, can't reuse it */
+              svn_error_clear(err);
+              ra_session = NULL;
+            }
+          else
+            {
+              return svn_error_trace(err);
+            }
+        }
+      else
+        {
+          *corrected_url = NULL;
+        }
+    }
+
+  /* Open an RA session for the URL if one isn't already available */
+  if (!ra_session)
+    {
+      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, corrected_url,
+                                                   anchor_url,
+                                                   anchor_abspath, NULL,
+                                                   TRUE /* write_dav_props */,
+                                                   TRUE /* read_dav_props */,
+                                                   ctx,
+                                                   result_pool, scratch_pool));
+      *ra_session_p = ra_session;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* This is a helper for svn_client__update_internal(), which see for
    an explanation of most of these parameters.  Some stuff that's
    unique is as follows:
@@ -320,6 +402,18 @@ update_internal(svn_revnum_t *result_rev
                                  ctx->notify_func2, ctx->notify_baton2,
                                  scratch_pool));
 
+          if (!ignore_externals)
+            {
+              /* We may now be able to remove externals below LOCAL_ABSPATH. */
+              SVN_ERR(reuse_ra_session(ra_session_p, &corrected_url,
+                                       anchor_url, anchor_abspath,
+                                       ctx, result_pool, scratch_pool));
+              ra_session = *ra_session_p;
+              SVN_ERR(handle_externals(timestamp_sleep, local_abspath, depth,
+                                       repos_root_url, ra_session, ctx,
+                                       scratch_pool));
+            }
+
           /* Target excluded, we are done now */
           return SVN_NO_ERROR;
         }
@@ -373,44 +467,9 @@ update_internal(svn_revnum_t *result_rev
       ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
     }
 
-  /* Try to reuse the RA session by reparenting it to the anchor_url.
-   * This code is probably overly cautious since we only use this
-   * currently when parents are missing and so all the anchor_urls
-   * have to be in the same repo. */
-  if (ra_session)
-    {
-      svn_error_t *err = svn_ra_reparent(ra_session, anchor_url, scratch_pool);
-      if (err)
-        {
-          if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL)
-            {
-            /* session changed repos, can't reuse it */
-              svn_error_clear(err);
-              ra_session = NULL;
-            }
-          else
-            {
-              return svn_error_trace(err);
-            }
-        }
-      else
-        {
-          corrected_url = NULL;
-        }
-    }
-
-  /* Open an RA session for the URL if one isn't already available */
-  if (!ra_session)
-    {
-      SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
-                                                   anchor_url,
-                                                   anchor_abspath, NULL,
-                                                   TRUE /* write_dav_props */,
-                                                   TRUE /* read_dav_props */,
-                                                   ctx,
-                                                   result_pool, scratch_pool));
-      *ra_session_p = ra_session;
-    }
+  SVN_ERR(reuse_ra_session(ra_session_p, &corrected_url, anchor_url,
+                           anchor_abspath, ctx, result_pool, scratch_pool));
+  ra_session = *ra_session_p;
 
   /* If we got a corrected URL from the RA subsystem, we'll need to
      relocate our working copy first. */
@@ -513,19 +572,8 @@ update_internal(svn_revnum_t *result_rev
   if ((SVN_DEPTH_IS_RECURSIVE(depth) || cropping_target)
       && (! ignore_externals))
     {
-      apr_hash_t *new_externals;
-      apr_hash_t *new_depths;
-      SVN_ERR(svn_wc__externals_gather_definitions(&new_externals,
-                                                   &new_depths,
-                                                   ctx->wc_ctx, local_abspath,
-                                                   depth,
-                                                   scratch_pool, 
scratch_pool));
-
-      SVN_ERR(svn_client__handle_externals(new_externals,
-                                           new_depths,
-                                           repos_root_url, local_abspath,
-                                           depth, timestamp_sleep, ra_session,
-                                           ctx, scratch_pool));
+      SVN_ERR(handle_externals(timestamp_sleep, local_abspath, depth,
+                               repos_root_url, ra_session, ctx, scratch_pool));
     }
 
   /* Let everyone know we're finished here (unless we're asked not to). */
@@ -567,7 +615,7 @@ svn_client__update_internal(svn_revnum_t
 {
   const char *anchor_abspath, *lockroot_abspath;
   svn_error_t *err;
-  svn_opt_revision_t peg_revision = *revision;
+  svn_opt_revision_t opt_rev = *revision;  /* operative revision */
   apr_hash_t *conflicted_paths
     = ctx->conflict_func2 ? apr_hash_make(pool) : NULL;
 
@@ -620,7 +668,7 @@ svn_client__update_internal(svn_revnum_t
 
           err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
                                 &ra_session, missing_parent,
-                                anchor_abspath, &peg_revision, svn_depth_empty,
+                                anchor_abspath, &opt_rev, svn_depth_empty,
                                 FALSE, ignore_externals,
                                 allow_unver_obstructions, adds_as_modification,
                                 FALSE, ctx, pool, iterpool);
@@ -631,8 +679,8 @@ svn_client__update_internal(svn_revnum_t
           /* If we successfully updated a missing parent, let's re-use
              the returned revision number for future updates for the
              sake of consistency. */
-          peg_revision.kind = svn_opt_revision_number;
-          peg_revision.value.number = *result_rev;
+          opt_rev.kind = svn_opt_revision_number;
+          opt_rev.value.number = *result_rev;
         }
 
       svn_pool_destroy(iterpool);
@@ -648,7 +696,7 @@ svn_client__update_internal(svn_revnum_t
   err = update_internal(result_rev, timestamp_sleep, conflicted_paths,
                         &ra_session,
                         local_abspath, anchor_abspath,
-                        &peg_revision, depth, depth_is_sticky,
+                        &opt_rev, depth, depth_is_sticky,
                         ignore_externals, allow_unver_obstructions,
                         adds_as_modification,
                         TRUE, ctx, pool, pool);

Modified: subversion/branches/addremove/subversion/libsvn_client/upgrade.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/upgrade.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/upgrade.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/upgrade.c Sat May 23 
14:16:56 2020
@@ -303,7 +303,7 @@ upgrade_externals_from_properties(svn_cl
 {
   apr_hash_index_t *hi;
   apr_pool_t *iterpool;
-  apr_pool_t *iterpool2;
+  apr_pool_t *inner_iterpool;
   apr_hash_t *externals;
   svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
 
@@ -317,7 +317,7 @@ upgrade_externals_from_properties(svn_cl
                               scratch_pool, scratch_pool));
 
   iterpool = svn_pool_create(scratch_pool);
-  iterpool2 = svn_pool_create(scratch_pool);
+  inner_iterpool = svn_pool_create(scratch_pool);
 
   for (hi = apr_hash_first(scratch_pool, externals); hi;
        hi = apr_hash_next(hi))
@@ -351,14 +351,12 @@ upgrade_externals_from_properties(svn_cl
                                         iterpool, iterpool);
 
       if (!err)
-        externals_parent_url = svn_path_url_add_component2(
-                                    externals_parent_repos_root_url,
-                                    externals_parent_repos_relpath,
-                                    iterpool);
-      if (!err)
-        err = svn_wc_parse_externals_description3(
-                  &externals_p, svn_dirent_dirname(local_abspath, iterpool),
-                  external_desc->data, FALSE, iterpool);
+        {
+          err = svn_wc_parse_externals_description3(
+              &externals_p, svn_dirent_dirname(local_abspath, iterpool),
+              external_desc->data, FALSE, iterpool);
+        }
+
       if (err)
         {
           svn_wc_notify_t *notify =
@@ -376,24 +374,29 @@ upgrade_externals_from_properties(svn_cl
           continue;
         }
 
+      externals_parent_url = svn_path_url_add_component2(
+          externals_parent_repos_root_url,
+          externals_parent_repos_relpath,
+          iterpool);
+
       for (i = 0; i < externals_p->nelts; i++)
         {
           svn_wc_external_item2_t *item;
 
           item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);
 
-          svn_pool_clear(iterpool2);
+          svn_pool_clear(inner_iterpool);
           err = upgrade_external_item(ctx, externals_parent_abspath,
                                       externals_parent_url,
                                       externals_parent_repos_root_url,
-                                      item, info_baton, iterpool2);
+                                      item, info_baton, inner_iterpool);
 
           if (err)
             {
               svn_wc_notify_t *notify =
                   
svn_wc_create_notify(svn_dirent_join(externals_parent_abspath,
                                                        item->target_dir,
-                                                       iterpool2),
+                                                       inner_iterpool),
                                        svn_wc_notify_failed_external,
                                        scratch_pool);
               notify->err = err;
@@ -405,8 +408,8 @@ upgrade_externals_from_properties(svn_cl
         }
     }
 
+  svn_pool_destroy(inner_iterpool);
   svn_pool_destroy(iterpool);
-  svn_pool_destroy(iterpool2);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/addremove/subversion/libsvn_client/util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_client/util.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_client/util.c (original)
+++ subversion/branches/addremove/subversion/libsvn_client/util.c Sat May 23 
14:16:56 2020
@@ -93,6 +93,7 @@ svn_client__pathrev_create_with_session(
   pathrev->rev = rev;
   pathrev->url = apr_pstrdup(result_pool, url);
   *pathrev_p = pathrev;
+  SVN_ERR_ASSERT(svn_uri__is_ancestor(pathrev->repos_root_url, url));
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/addremove/subversion/libsvn_delta/branch.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/libsvn_delta/branch.c?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/libsvn_delta/branch.c (original)
+++ subversion/branches/addremove/subversion/libsvn_delta/branch.c Sat May 23 
14:16:56 2020
@@ -157,7 +157,7 @@ branch_txn_delete_branch(svn_branch__txn
 
       if (strcmp(b->bid, bid) == 0)
         {
-          svn_sort__array_delete(txn->priv->branches, i, 1);
+          SVN_ERR(svn_sort__array_delete2(txn->priv->branches, i, 1));
           break;
         }
     }


Reply via email to