You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2018/11/07 12:30:11 UTC

svn commit: r1846002 [9/44] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/swig/ build/generator/templates/ build/generator/util/ build/win32/ contrib/client-side/ contrib/client-side/svn_load_dirs/ contri...

Modified: subversion/branches/ra-git/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/export.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/export.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/export.c Wed Nov  7 12:30:06 2018
@@ -453,12 +453,12 @@ export_node(void *baton,
  * If PATH exists but is a file, then error with SVN_ERR_WC_NOT_WORKING_COPY.
  *
  * If PATH is a already a directory, then error with
- * SVN_ERR_WC_OBSTRUCTED_UPDATE, unless FORCE, in which case just
+ * SVN_ERR_WC_OBSTRUCTED_UPDATE, unless OVERWRITE, in which case just
  * export into PATH with no error.
  */
 static svn_error_t *
 open_root_internal(const char *path,
-                   svn_boolean_t force,
+                   svn_boolean_t overwrite,
                    svn_wc_notify_func2_t notify_func,
                    void *notify_baton,
                    apr_pool_t *pool)
@@ -472,7 +472,7 @@ open_root_internal(const char *path,
     return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                              _("'%s' exists and is not a directory"),
                              svn_dirent_local_style(path, pool));
-  else if ((kind != svn_node_dir) || (! force))
+  else if ((kind != svn_node_dir) || (! overwrite))
     return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                              _("'%s' already exists"),
                              svn_dirent_local_style(path, pool));
@@ -501,7 +501,7 @@ struct edit_baton
   const char *repos_root_url;
   const char *root_path;
   const char *root_url;
-  svn_boolean_t force;
+  svn_boolean_t overwrite;
   svn_revnum_t *target_revision;
   apr_hash_t *externals;
   const char *native_eol;
@@ -587,7 +587,7 @@ open_root(void *edit_baton,
   struct edit_baton *eb = edit_baton;
   struct dir_baton *db = apr_pcalloc(pool, sizeof(*db));
 
-  SVN_ERR(open_root_internal(eb->root_path, eb->force,
+  SVN_ERR(open_root_internal(eb->root_path, eb->overwrite,
                              eb->notify_func, eb->notify_baton, pool));
 
   /* Build our dir baton. */
@@ -621,7 +621,7 @@ add_directory(const char *path,
     return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                              _("'%s' exists and is not a directory"),
                              svn_dirent_local_style(full_path, pool));
-  else if (! (kind == svn_node_dir && eb->force))
+  else if (! (kind == svn_node_dir && eb->overwrite))
     return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                              _("'%s' already exists"),
                              svn_dirent_local_style(full_path, pool));
@@ -1077,7 +1077,7 @@ add_directory_ev2(void *baton,
     return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                              _("'%s' exists and is not a directory"),
                              svn_dirent_local_style(full_path, scratch_pool));
-  else if (! (kind == svn_node_dir && eb->force))
+  else if (! (kind == svn_node_dir && eb->overwrite))
     return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
                              _("'%s' already exists"),
                              svn_dirent_local_style(full_path, scratch_pool));
@@ -1141,45 +1141,42 @@ get_editor_ev2(const svn_delta_editor_t
                                        exb, result_pool));
 
   /* Create the root of the export. */
-  SVN_ERR(open_root_internal(eb->root_path, eb->force, eb->notify_func,
+  SVN_ERR(open_root_internal(eb->root_path, eb->overwrite, eb->notify_func,
                              eb->notify_baton, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
-export_file_ev2(const char *from_path_or_url,
+export_file_ev2(const char *from_url,
                 const char *to_path,
                 struct edit_baton *eb,
                 svn_client__pathrev_t *loc,
                 svn_ra_session_t *ra_session,
-                svn_boolean_t overwrite,
                 apr_pool_t *scratch_pool)
 {
-  svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
   apr_hash_t *props;
   svn_stream_t *tmp_stream;
   svn_node_kind_t to_kind;
 
+  SVN_ERR_ASSERT(svn_path_is_url(from_url));
+
   if (svn_path_is_empty(to_path))
     {
-      if (from_is_url)
-        to_path = svn_uri_basename(from_path_or_url, scratch_pool);
-      else
-        to_path = svn_dirent_basename(from_path_or_url, NULL);
+      to_path = svn_uri_basename(from_url, scratch_pool);
       eb->root_path = to_path;
     }
   else
     {
-      SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
-                                     from_is_url, scratch_pool));
+      SVN_ERR(append_basename_if_dir(&to_path, from_url,
+                                     TRUE, scratch_pool));
       eb->root_path = to_path;
     }
 
   SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
 
   if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
-      ! overwrite)
+      ! eb->overwrite)
     return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                              _("Destination file '%s' exists, and "
                                "will not be overwritten unless forced"),
@@ -1204,39 +1201,36 @@ export_file_ev2(const char *from_path_or
 }
 
 static svn_error_t *
-export_file(const char *from_path_or_url,
+export_file(const char *from_url,
             const char *to_path,
             struct edit_baton *eb,
             svn_client__pathrev_t *loc,
             svn_ra_session_t *ra_session,
-            svn_boolean_t overwrite,
             apr_pool_t *scratch_pool)
 {
   apr_hash_t *props;
   apr_hash_index_t *hi;
   struct file_baton *fb = apr_pcalloc(scratch_pool, sizeof(*fb));
   svn_node_kind_t to_kind;
-  svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
+
+  SVN_ERR_ASSERT(svn_path_is_url(from_url));
 
   if (svn_path_is_empty(to_path))
     {
-      if (from_is_url)
-        to_path = svn_uri_basename(from_path_or_url, scratch_pool);
-      else
-        to_path = svn_dirent_basename(from_path_or_url, NULL);
+      to_path = svn_uri_basename(from_url, scratch_pool);
       eb->root_path = to_path;
     }
   else
     {
-      SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
-                                     from_is_url, scratch_pool));
+      SVN_ERR(append_basename_if_dir(&to_path, from_url,
+                                     TRUE, scratch_pool));
       eb->root_path = to_path;
     }
 
   SVN_ERR(svn_io_check_path(to_path, &to_kind, scratch_pool));
 
   if ((to_kind == svn_node_file || to_kind == svn_node_unknown) &&
-      ! overwrite)
+      ! eb->overwrite)
     return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
                              _("Destination file '%s' exists, and "
                                "will not be overwritten unless forced"),
@@ -1288,12 +1282,11 @@ export_file(const char *from_path_or_url
 }
 
 static svn_error_t *
-export_directory(const char *from_path_or_url,
+export_directory(const char *from_url,
                  const char *to_path,
                  struct edit_baton *eb,
                  svn_client__pathrev_t *loc,
                  svn_ra_session_t *ra_session,
-                 svn_boolean_t overwrite,
                  svn_boolean_t ignore_externals,
                  svn_boolean_t ignore_keywords,
                  svn_depth_t depth,
@@ -1307,6 +1300,8 @@ export_directory(const char *from_path_o
   void *report_baton;
   svn_node_kind_t kind;
 
+  SVN_ERR_ASSERT(svn_path_is_url(from_url));
+
   if (!ENABLE_EV2_IMPL)
     SVN_ERR(get_editor_ev1(&export_editor, &edit_baton, eb, ctx,
                            scratch_pool, scratch_pool));
@@ -1346,7 +1341,7 @@ export_directory(const char *from_path_o
   SVN_ERR(svn_io_check_path(to_path, &kind, scratch_pool));
   if (kind == svn_node_none)
     SVN_ERR(open_root_internal
-            (to_path, overwrite, ctx->notify_func2,
+            (to_path, eb->overwrite, ctx->notify_func2,
              ctx->notify_baton2, scratch_pool));
 
   if (! ignore_externals && depth == svn_depth_infinity)
@@ -1355,7 +1350,7 @@ export_directory(const char *from_path_o
 
       SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, scratch_pool));
       SVN_ERR(svn_client__export_externals(eb->externals,
-                                           from_path_or_url,
+                                           from_url,
                                            to_abspath, eb->repos_root_url,
                                            depth, native_eol,
                                            ignore_keywords,
@@ -1402,8 +1397,12 @@ svn_client_export5(svn_revnum_t *result_
       svn_client__pathrev_t *loc;
       svn_ra_session_t *ra_session;
       svn_node_kind_t kind;
+      const char *from_url;
       struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
 
+      SVN_ERR(svn_client_url_from_path2(&from_url, from_path_or_url,
+                                        ctx, pool, pool));
+
       /* Get the RA connection. */
       SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                                                 from_path_or_url, NULL,
@@ -1413,7 +1412,7 @@ svn_client_export5(svn_revnum_t *result_
       SVN_ERR(svn_ra_get_repos_root2(ra_session, &eb->repos_root_url, pool));
       eb->root_path = to_path;
       eb->root_url = loc->url;
-      eb->force = overwrite;
+      eb->overwrite = overwrite;
       eb->target_revision = &edit_revision;
       eb->externals = apr_hash_make(pool);
       eb->native_eol = native_eol;
@@ -1428,16 +1427,16 @@ svn_client_export5(svn_revnum_t *result_
       if (kind == svn_node_file)
         {
           if (!ENABLE_EV2_IMPL)
-            SVN_ERR(export_file(from_path_or_url, to_path, eb, loc, ra_session,
-                                overwrite, pool));
+            SVN_ERR(export_file(from_url, to_path, eb, loc, ra_session,
+                                pool));
           else
-            SVN_ERR(export_file_ev2(from_path_or_url, to_path, eb, loc,
-                                    ra_session, overwrite, pool));
+            SVN_ERR(export_file_ev2(from_url, to_path, eb, loc,
+                                    ra_session, pool));
         }
       else if (kind == svn_node_dir)
         {
-          SVN_ERR(export_directory(from_path_or_url, to_path,
-                                   eb, loc, ra_session, overwrite,
+          SVN_ERR(export_directory(from_url, to_path,
+                                   eb, loc, ra_session,
                                    ignore_externals, ignore_keywords, depth,
                                    native_eol, ctx, pool));
         }

Modified: subversion/branches/ra-git/subversion/libsvn_client/import.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/import.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/import.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/import.c Wed Nov  7 12:30:06 2018
@@ -73,32 +73,59 @@ typedef struct import_ctx_t
   apr_hash_t *autoprops;
 } import_ctx_t;
 
+typedef struct open_txdelta_stream_baton_t
+{
+  svn_boolean_t need_reset;
+  svn_stream_t *stream;
+} open_txdelta_stream_baton_t;
+
+/* Implements svn_txdelta_stream_open_func_t */
+static svn_error_t *
+open_txdelta_stream(svn_txdelta_stream_t **txdelta_stream_p,
+                    void *baton,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  open_txdelta_stream_baton_t *b = baton;
+
+  if (b->need_reset)
+    {
+      /* Under rare circumstances, we can be restarted and would need to
+       * supply the delta stream again.  In this case, reset the base
+       * stream. */
+      SVN_ERR(svn_stream_reset(b->stream));
+    }
+
+  /* Get the delta stream (delta against the empty string). */
+  svn_txdelta2(txdelta_stream_p, svn_stream_empty(result_pool),
+               b->stream, FALSE, result_pool);
+  b->need_reset = TRUE;
+  return SVN_NO_ERROR;
+}
 
 /* Apply LOCAL_ABSPATH's contents (as a delta against the empty string) to
    FILE_BATON in EDITOR.  Use POOL for any temporary allocation.
    PROPERTIES is the set of node properties set on this file.
 
-   Fill DIGEST with the md5 checksum of the sent file; DIGEST must be
-   at least APR_MD5_DIGESTSIZE bytes long. */
+   Return the resulting checksum in *RESULT_MD5_CHECKSUM_P. */
 
 /* ### how does this compare against svn_wc_transmit_text_deltas2() ??? */
 
 static svn_error_t *
-send_file_contents(const char *local_abspath,
+send_file_contents(svn_checksum_t **result_md5_checksum_p,
+                   const char *local_abspath,
                    void *file_baton,
                    const svn_delta_editor_t *editor,
                    apr_hash_t *properties,
-                   unsigned char *digest,
                    apr_pool_t *pool)
 {
   svn_stream_t *contents;
-  svn_txdelta_window_handler_t handler;
-  void *handler_baton;
   const svn_string_t *eol_style_val = NULL, *keywords_val = NULL;
   svn_boolean_t special = FALSE;
   svn_subst_eol_style_t eol_style;
   const char *eol;
   apr_hash_t *keywords;
+  open_txdelta_stream_baton_t baton = { 0 };
 
   /* If there are properties, look for EOL-style and keywords ones. */
   if (properties)
@@ -111,10 +138,6 @@ send_file_contents(const char *local_abs
         special = TRUE;
     }
 
-  /* Get an editor func that wants to consume the delta stream. */
-  SVN_ERR(editor->apply_textdelta(file_baton, NULL, pool,
-                                  &handler, &handler_baton));
-
   if (eol_style_val)
     svn_subst_eol_style_from_value(&eol_style, &eol, eol_style_val->data);
   else
@@ -168,10 +191,17 @@ send_file_contents(const char *local_abs
         }
     }
 
-  /* Send the file's contents to the delta-window handler. */
-  return svn_error_trace(svn_txdelta_send_stream(contents, handler,
-                                                 handler_baton, digest,
-                                                 pool));
+  /* Arrange the stream to calculate the resulting MD5. */
+  contents = svn_stream_checksummed2(contents, result_md5_checksum_p, NULL,
+                                     svn_checksum_md5, TRUE, pool);
+  /* Send the contents. */
+  baton.need_reset = FALSE;
+  baton.stream = svn_stream_disown(contents, pool);
+  SVN_ERR(editor->apply_textdelta_stream(editor, file_baton, NULL,
+                                         open_txdelta_stream, &baton, pool));
+  SVN_ERR(svn_stream_close(contents));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -198,7 +228,7 @@ import_file(const svn_delta_editor_t *ed
 {
   void *file_baton;
   const char *mimetype = NULL;
-  unsigned char digest[APR_MD5_DIGESTSIZE];
+  svn_checksum_t *result_md5_checksum;
   const char *text_checksum;
   apr_hash_t* properties;
   apr_hash_index_t *hi;
@@ -262,13 +292,11 @@ import_file(const svn_delta_editor_t *ed
     }
 
   /* Now, transmit the file contents. */
-  SVN_ERR(send_file_contents(local_abspath, file_baton, editor,
-                             properties, digest, pool));
+  SVN_ERR(send_file_contents(&result_md5_checksum, local_abspath,
+                             file_baton, editor, properties, pool));
 
   /* Finally, close the file. */
-  text_checksum =
-    svn_checksum_to_cstring(svn_checksum__from_digest_md5(digest, pool), pool);
-
+  text_checksum = svn_checksum_to_cstring(result_md5_checksum, pool);
   return svn_error_trace(editor->close_file(file_baton, text_checksum, pool));
 }
 
@@ -577,26 +605,26 @@ import_dir(const svn_delta_editor_t *edi
 }
 
 
-/* Recursively import PATH to a repository using EDITOR and
- * EDIT_BATON.  PATH can be a file or directory.
+/* Recursively import LOCAL_ABSPATH to a repository using EDITOR and
+ * EDIT_BATON.  LOCAL_ABSPATH can be a file or directory.
  *
  * Sets *UPDATED_REPOSITORY to TRUE when the repository was modified by
  * a successfull commit, otherwise to FALSE.
  *
- * DEPTH is the depth at which to import PATH; it behaves as for
- * svn_client_import4().
+ * DEPTH is the depth at which to import LOCAL_ABSPATH; it behaves as for
+ * svn_client_import5().
  *
  * BASE_REV is the revision to use for the root of the commit. We
  * checked the preconditions against this revision.
  *
  * NEW_ENTRIES is an ordered array of path components that must be
  * created in the repository (where the ordering direction is
- * parent-to-child).  If PATH is a directory, NEW_ENTRIES may be empty
+ * parent-to-child).  If LOCAL_ABSPATH is a directory, NEW_ENTRIES may be empty
  * -- the result is an import which creates as many new entries in the
  * top repository target directory as there are importable entries in
- * the top of PATH; but if NEW_ENTRIES is not empty, its last item is
+ * the top of LOCAL_ABSPATH; but if NEW_ENTRIES is not empty, its last item is
  * the name of a new subdirectory in the repository to hold the
- * import.  If PATH is a file, NEW_ENTRIES may not be empty, and its
+ * import.  If LOCAL_ABSPATH is a file, NEW_ENTRIES may not be empty, and its
  * last item is the name used for the file in the repository.  If
  * NEW_ENTRIES contains more than one item, all but the last item are
  * the names of intermediate directories that are created before the
@@ -624,6 +652,8 @@ import_dir(const svn_delta_editor_t *edi
  * If CTX->NOTIFY_FUNC is non-null, invoke it with CTX->NOTIFY_BATON for
  * each imported path, passing actions svn_wc_notify_commit_added.
  *
+ * URL is used only in the 'commit_finalizing' notification.
+ *
  * Use POOL for any temporary allocation.
  *
  * Note: the repository directory receiving the import was specified

Modified: subversion/branches/ra-git/subversion/libsvn_client/info.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/info.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/info.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/info.c Wed Nov  7 12:30:06 2018
@@ -253,17 +253,17 @@ same_resource_in_head(svn_boolean_t *sam
                       apr_pool_t *pool)
 {
   svn_error_t *err;
-  svn_opt_revision_t start_rev, peg_rev;
+  svn_opt_revision_t operative_rev, peg_rev;
   const char *head_url;
 
-  start_rev.kind = svn_opt_revision_head;
-  peg_rev.kind = svn_opt_revision_number;
-  peg_rev.value.number = rev;
+  peg_rev.kind = svn_opt_revision_head;
+  operative_rev.kind = svn_opt_revision_number;
+  operative_rev.value.number = rev;
 
   err = svn_client__repos_locations(&head_url, NULL, NULL, NULL,
                                     ra_session,
                                     url, &peg_rev,
-                                    &start_rev, NULL,
+                                    &operative_rev, NULL,
                                     ctx, pool);
   if (err &&
       ((err->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES) ||

Modified: subversion/branches/ra-git/subversion/libsvn_client/list.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/list.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/list.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/list.c Wed Nov  7 12:30:06 2018
@@ -37,13 +37,14 @@
 #include "private/svn_fspath.h"
 #include "private/svn_ra_private.h"
 #include "private/svn_sorts_private.h"
+#include "private/svn_utf_private.h"
 #include "private/svn_wc_private.h"
 #include "svn_private_config.h"
 
 /* Prototypes for referencing before declaration */
 static svn_error_t *
 list_externals(apr_hash_t *externals,
-               apr_array_header_t *patterns,
+               const apr_array_header_t *patterns,
                svn_depth_t depth,
                apr_uint32_t dirent_fields,
                svn_boolean_t fetch_locks,
@@ -56,7 +57,7 @@ static svn_error_t *
 list_internal(const char *path_or_url,
               const svn_opt_revision_t *peg_revision,
               const svn_opt_revision_t *revision,
-              apr_array_header_t *patterns,
+              const apr_array_header_t *patterns,
               svn_depth_t depth,
               apr_uint32_t dirent_fields,
               svn_boolean_t fetch_locks,
@@ -69,23 +70,16 @@ list_internal(const char *path_or_url,
               apr_pool_t *pool);
 
 /* Return TRUE if S matches any of the const char * in PATTERNS.
- * Note that any S will match if PATTERNS is empty. */
+ * Note that any S will match if PATTERNS is empty.
+ * Use SCRATCH_BUFFER for temporary string contents. */
 static svn_boolean_t
 match_patterns(const char *s,
-               apr_array_header_t *patterns)
+               const apr_array_header_t *patterns,
+               svn_membuf_t *scratch_buffer)
 {
-  int i;
-  if (!patterns)
-    return TRUE;
-
-  for (i = 0; i < patterns->nelts; ++i)
-    {
-      const char *pattern = APR_ARRAY_IDX(patterns, i, const char *);
-      if (apr_fnmatch(pattern, s, APR_FNM_PERIOD) == APR_SUCCESS)
-        return TRUE;
-    }
-
-  return FALSE;
+  return patterns
+       ? svn_utf__fuzzy_glob_match(s, patterns, scratch_buffer)
+       : TRUE;
 }
 
 /* Get the directory entries of DIR at REV (relative to the root of
@@ -113,6 +107,8 @@ match_patterns(const char *s,
 
    EXTERNAL_PARENT_URL and EXTERNAL_TARGET are set when external items
    are listed, otherwise both are set to NULL by the caller.
+
+   Use SCRATCH_BUFFER for temporary string contents.
 */
 static svn_error_t *
 get_dir_contents(apr_uint32_t dirent_fields,
@@ -121,7 +117,7 @@ get_dir_contents(apr_uint32_t dirent_fie
                  svn_ra_session_t *ra_session,
                  apr_hash_t *locks,
                  const char *fs_path,
-                 apr_array_header_t *patterns,
+                 const apr_array_header_t *patterns,
                  svn_depth_t depth,
                  svn_client_ctx_t *ctx,
                  apr_hash_t *externals,
@@ -129,6 +125,7 @@ get_dir_contents(apr_uint32_t dirent_fie
                  const char *external_target,
                  svn_client_list_func2_t list_func,
                  void *baton,
+                 svn_membuf_t *scratch_buffer,
                  apr_pool_t *result_pool,
                  apr_pool_t *scratch_pool)
 {
@@ -203,7 +200,7 @@ get_dir_contents(apr_uint32_t dirent_fie
       if (the_ent->kind == svn_node_file
           || depth == svn_depth_immediates
           || depth == svn_depth_infinity)
-        if (match_patterns(item->key, patterns))
+        if (match_patterns(item->key, patterns, scratch_buffer))
           SVN_ERR(list_func(baton, path, the_ent, lock, fs_path,
                             external_parent_url, external_target, iterpool));
 
@@ -214,7 +211,7 @@ get_dir_contents(apr_uint32_t dirent_fie
                                  locks, fs_path, patterns, depth, ctx,
                                  externals, external_parent_url,
                                  external_target, list_func, baton,
-                                 result_pool, iterpool));
+                                 scratch_buffer, result_pool, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -310,7 +307,7 @@ static svn_error_t *
 list_internal(const char *path_or_url,
               const svn_opt_revision_t *peg_revision,
               const svn_opt_revision_t *revision,
-              apr_array_header_t *patterns,
+              const apr_array_header_t *patterns,
               svn_depth_t depth,
               apr_uint32_t dirent_fields,
               svn_boolean_t fetch_locks,
@@ -329,6 +326,7 @@ list_internal(const char *path_or_url,
   svn_error_t *err;
   apr_hash_t *locks;
   apr_hash_t *externals;
+  svn_membuf_t scratch_buffer;
 
   if (include_externals)
     externals = apr_hash_make(pool);
@@ -391,8 +389,13 @@ list_internal(const char *path_or_url,
                              _("URL '%s' non-existent in revision %ld"),
                              loc->url, loc->rev);
 
+  /* We need a scratch buffer for temporary string data.
+   * Create one with a reasonable initial size. */
+  svn_membuf__create(&scratch_buffer, 256, pool);
+
   /* Report the dirent for the target. */
-  if (match_patterns(svn_dirent_dirname(fs_path, pool), patterns))
+  if (match_patterns(svn_dirent_basename(fs_path, pool), patterns,
+                     &scratch_buffer))
     SVN_ERR(list_func(baton, "", dirent, locks
                       ? (svn_hash_gets(locks, fs_path))
                       : NULL, fs_path, external_parent_url,
@@ -405,7 +408,7 @@ list_internal(const char *path_or_url,
     SVN_ERR(get_dir_contents(dirent_fields, "", loc->rev, ra_session, locks,
                              fs_path, patterns, depth, ctx, externals,
                              external_parent_url, external_target, list_func,
-                             baton, pool, pool));
+                             baton, &scratch_buffer, pool, pool));
 
   /* We handle externals after listing entries under path_or_url, so that
      handling external items (and any errors therefrom) doesn't delay
@@ -451,7 +454,7 @@ wrap_list_error(const svn_client_ctx_t *
 static svn_error_t *
 list_external_items(apr_array_header_t *external_items,
                     const char *externals_parent_url,
-                    apr_array_header_t *patterns,
+                    const apr_array_header_t *patterns,
                     svn_depth_t depth,
                     apr_uint32_t dirent_fields,
                     svn_boolean_t fetch_locks,
@@ -515,7 +518,7 @@ list_external_items(apr_array_header_t *
    passed to svn_client_list(). */
 static svn_error_t *
 list_externals(apr_hash_t *externals,
-               apr_array_header_t *patterns,
+               const apr_array_header_t *patterns,
                svn_depth_t depth,
                apr_uint32_t dirent_fields,
                svn_boolean_t fetch_locks,
@@ -561,7 +564,7 @@ svn_error_t *
 svn_client_list4(const char *path_or_url,
                  const svn_opt_revision_t *peg_revision,
                  const svn_opt_revision_t *revision,
-                 apr_array_header_t *patterns,
+                 const apr_array_header_t *patterns,
                  svn_depth_t depth,
                  apr_uint32_t dirent_fields,
                  svn_boolean_t fetch_locks,

Modified: subversion/branches/ra-git/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/merge.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/merge.c Wed Nov  7 12:30:06 2018
@@ -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
@@ -2240,13 +2237,9 @@ merge_file_added(const char *relpath,
          Otherwise, we'll use a pure add. */
       if (merge_b->same_repos)
         {
-          const char *child =
-            svn_dirent_skip_ancestor(merge_b->target->abspath,
-                                     local_abspath);
-          SVN_ERR_ASSERT(child != NULL);
           copyfrom_url = svn_path_url_add_component2(
                                        merge_b->merge_source.loc2->url,
-                                       child, scratch_pool);
+                                       relpath, scratch_pool);
           copyfrom_rev = right_source->revision;
           SVN_ERR(check_repos_match(merge_b->target, local_abspath,
                                     copyfrom_url, scratch_pool));
@@ -3417,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 ***/
@@ -3612,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).
@@ -3660,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:
@@ -3696,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,
@@ -3757,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
@@ -5449,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 *)));
@@ -6425,6 +6464,7 @@ get_mergeinfo_paths(apr_array_header_t *
 {
   int i;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_pool_t *swmi_pool;
   apr_hash_t *subtrees_with_mergeinfo;
   apr_hash_t *excluded_subtrees;
   apr_hash_t *switched_subtrees;
@@ -6433,10 +6473,13 @@ get_mergeinfo_paths(apr_array_header_t *
   struct pre_merge_status_baton_t pre_merge_status_baton;
 
   /* Case 1: Subtrees with explicit mergeinfo. */
+  /* Use a subpool for subtrees_with_mergeinfo, as it can be very large
+     and is temporary. */
+  swmi_pool = svn_pool_create(scratch_pool);
   SVN_ERR(get_wc_explicit_mergeinfo_catalog(&subtrees_with_mergeinfo,
                                             target->abspath,
                                             depth, ctx,
-                                            result_pool, scratch_pool));
+                                            swmi_pool, swmi_pool));
   if (subtrees_with_mergeinfo)
     {
       apr_hash_index_t *hi;
@@ -6470,6 +6513,7 @@ get_mergeinfo_paths(apr_array_header_t *
          children with insert_child_to_merge() require this ordering. */
       svn_sort__array(children_with_mergeinfo, compare_merge_path_t_as_paths);
     }
+  svn_pool_destroy(swmi_pool);
 
   /* Case 2: Switched subtrees
      Case 10: Paths at depths of 'empty' or 'files'
@@ -7595,16 +7639,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)
@@ -7647,19 +7690,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;
@@ -7667,7 +7701,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)
@@ -7686,7 +7720,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)
@@ -7818,7 +7852,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);
 
@@ -7877,7 +7911,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... */
@@ -8268,7 +8302,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--)
@@ -8431,7 +8465,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
@@ -8456,7 +8490,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().
 
@@ -8507,7 +8541,7 @@ 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);
@@ -9333,7 +9367,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
@@ -9343,13 +9377,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,
@@ -9369,7 +9403,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).
 
@@ -9407,7 +9441,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 =
@@ -9416,7 +9450,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.
 
@@ -9424,17 +9458,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.
 
@@ -9495,14 +9529,14 @@ 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. */
@@ -9633,7 +9667,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! */
@@ -9651,7 +9685,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;
 }
@@ -9888,28 +9922,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_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;
 
-    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;
-
-    processor = merge_processor;
-  }
+  processor = merge_apply_processor(&merge_cmd_baton, scratch_pool);
 
   if (src_session)
     {
@@ -12304,6 +12323,10 @@ find_last_merged_location(svn_client__pa
   svn_revnum_t youngest_merged_rev = SVN_INVALID_REVNUM;
   svn_mergeinfo_catalog_t target_mergeinfo_cat = NULL;
 
+  /* Using a local subpool for 'target_mergeinfo_cat' can make a big
+     reduction in overall memory usage. */
+  apr_pool_t *tmic_pool = svn_pool_create(scratch_pool);
+
   source_peg_rev.kind = svn_opt_revision_number;
   source_peg_rev.value.number = source_branch->tip->rev;
   source_start_rev.kind = svn_opt_revision_number;
@@ -12324,7 +12347,7 @@ find_last_merged_location(svn_client__pa
                                       operative_rev_receiver,
                                       &youngest_merged_rev,
                                       ctx, ra_session,
-                                      result_pool, scratch_pool));
+                                      tmic_pool, tmic_pool));
 
   if (!SVN_IS_VALID_REVNUM(youngest_merged_rev))
     {
@@ -12360,7 +12383,7 @@ find_last_merged_location(svn_client__pa
                                           operative_rev_receiver,
                                           &oldest_eligible_rev,
                                           ctx, ra_session,
-                                          scratch_pool, scratch_pool));
+                                          tmic_pool, tmic_pool));
 
       /* If there are revisions eligible for merging, use the oldest one
          to calculate the base.  Otherwise there are no operative revisions
@@ -12382,6 +12405,7 @@ find_last_merged_location(svn_client__pa
                                            result_pool, scratch_pool));
     }
 
+  svn_pool_destroy(tmic_pool);
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ra-git/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/mergeinfo.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/mergeinfo.c Wed Nov  7 12:30:06 2018
@@ -1946,12 +1946,12 @@ svn_client__mergeinfo_log(svn_boolean_t
 
           SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
             &subtree_source_history, source_history,
-            subtree_rel_path, scratch_pool, scratch_pool));
+            subtree_rel_path, scratch_pool, iterpool));
 
           if (!finding_merged)
             SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
                     &subtree_history, target_history,
-                    subtree_rel_path, scratch_pool, scratch_pool));
+                    subtree_rel_path, scratch_pool, iterpool));
         }
       else
         {
@@ -1969,7 +1969,7 @@ svn_client__mergeinfo_log(svn_boolean_t
                                            scratch_pool, iterpool));
           SVN_ERR(svn_mergeinfo_merge2(subtree_mergeinfo,
                                        merged_via_history,
-                                       scratch_pool, scratch_pool));
+                                       scratch_pool, iterpool));
         }
 
       SVN_ERR(svn_mergeinfo_inheritable2(&subtree_inheritable_mergeinfo,
@@ -1995,7 +1995,7 @@ svn_client__mergeinfo_log(svn_boolean_t
                                        subtree_source_history, FALSE,
                                        scratch_pool, iterpool));
       svn_mergeinfo__set_inheritance(merged_noninheritable, FALSE,
-                                     scratch_pool);
+                                     iterpool);
 
       /* Keep track of all ranges partially merged to any and all
          subtrees. */

Modified: subversion/branches/ra-git/subversion/libsvn_client/mtcc.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/mtcc.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/mtcc.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/mtcc.c Wed Nov  7 12:30:06 2018
@@ -568,10 +568,44 @@ svn_client__mtcc_add_copy(const char *sr
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_client__mtcc_add_delete(const char *relpath,
-                            svn_client__mtcc_t *mtcc,
-                            apr_pool_t *scratch_pool)
+/* Check if this operation contains at least one change that is not a
+   plain delete */
+static svn_boolean_t
+mtcc_op_contains_non_delete(const mtcc_op_t *op)
+{
+  if (op->kind != OP_OPEN_DIR && op->kind != OP_OPEN_FILE
+      && op->kind != OP_DELETE)
+    {
+      return TRUE;
+    }
+
+  if (op->prop_mods && op->prop_mods->nelts)
+    return TRUE;
+
+  if (op->src_stream)
+    return TRUE;
+
+  if (op->children)
+    {
+      int i;
+
+      for (i = 0; i < op->children->nelts; i++)
+        {
+          const mtcc_op_t *c_op = APR_ARRAY_IDX(op->children, i,
+                                                const mtcc_op_t *);
+
+          if (mtcc_op_contains_non_delete(c_op))
+            return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+static svn_error_t *
+mtcc_add_delete(const char *relpath,
+                svn_boolean_t for_move,
+                svn_client__mtcc_t *mtcc,                
+                apr_pool_t *scratch_pool)
 {
   mtcc_op_t *op;
   svn_boolean_t created;
@@ -598,6 +632,20 @@ svn_client__mtcc_add_delete(const char *
       SVN_ERR(mtcc_op_find(&op, &created, relpath, mtcc->root_op, FALSE, TRUE,
                            TRUE, mtcc->pool, scratch_pool));
 
+      if (!for_move && !op && !created)
+        {
+          /* 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));
+
+          if (op && mtcc_op_contains_non_delete(op))
+            op = NULL;
+          else
+            created = TRUE;
+        }
+
       if (!op || !created)
         {
           return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
@@ -614,6 +662,14 @@ svn_client__mtcc_add_delete(const char *
 }
 
 svn_error_t *
+svn_client__mtcc_add_delete(const char *relpath,
+                            svn_client__mtcc_t *mtcc,
+                            apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(mtcc_add_delete(relpath, FALSE, mtcc, scratch_pool));
+}
+
+svn_error_t *
 svn_client__mtcc_add_mkdir(const char *relpath,
                            svn_client__mtcc_t *mtcc,
                            apr_pool_t *scratch_pool)
@@ -662,7 +718,7 @@ svn_client__mtcc_add_move(const char *sr
 
   SVN_ERR(svn_client__mtcc_add_copy(src_relpath, mtcc->base_revision,
                                     dst_relpath, mtcc, scratch_pool));
-  SVN_ERR(svn_client__mtcc_add_delete(src_relpath, mtcc, scratch_pool));
+  SVN_ERR(mtcc_add_delete(src_relpath, TRUE, mtcc, scratch_pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/patch.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/patch.c Wed Nov  7 12:30:06 2018
@@ -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));
 
@@ -2145,8 +2147,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
@@ -2511,7 +2513,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/ra-git/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/repos_diff.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/repos_diff.c Wed Nov  7 12:30:06 2018
@@ -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,7 +381,7 @@ 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
@@ -404,15 +405,9 @@ 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_sort__array_delete(changes, i, 1);
+              i--;
             }
         }
     }

Modified: subversion/branches/ra-git/subversion/libsvn_client/revert.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/revert.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/revert.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/revert.c Wed Nov  7 12:30:06 2018
@@ -51,6 +51,7 @@ 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;
 };
 
@@ -80,13 +81,14 @@ revert(void *baton, apr_pool_t *result_p
   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 +125,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 +186,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/ra-git/subversion/libsvn_client/revisions.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/revisions.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/revisions.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/revisions.c Wed Nov  7 12:30:06 2018
@@ -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/ra-git/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/status.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/status.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/status.c Wed Nov  7 12:30:06 2018
@@ -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. ***/
@@ -329,6 +332,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 +662,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/ra-git/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_client/update.c?rev=1846002&r1=1846001&r2=1846002&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_client/update.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_client/update.c Wed Nov  7 12:30:06 2018
@@ -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);