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

svn commit: r1220893 [14/19] - in /subversion/branches/fs-py: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ subversion/bindings/javahl/native/ s...

Modified: subversion/branches/fs-py/subversion/svn/add-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/add-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/add-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/add-cmd.c Mon Dec 19 18:49:34 2011
@@ -51,7 +51,7 @@ svn_cl__add(apr_getopt_t *os,
   apr_array_header_t *targets;
   int i;
   apr_pool_t *iterpool;
-  svn_boolean_t seen_nonexistent_target = FALSE;
+  apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -71,7 +71,6 @@ svn_cl__add(apr_getopt_t *os,
   for (i = 0; i < targets->nelts; i++)
     {
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
-      svn_boolean_t success;
 
       svn_pool_clear(iterpool);
       SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
@@ -80,21 +79,34 @@ svn_cl__add(apr_getopt_t *os,
                                opt_state->depth,
                                opt_state->force, opt_state->no_ignore,
                                opt_state->parents, ctx, iterpool),
-               &success, opt_state->quiet,
+               errors, opt_state->quiet,
                SVN_ERR_ENTRY_EXISTS,
                SVN_ERR_WC_PATH_NOT_FOUND,
                SVN_NO_ERROR));
-
-      if (! success)
-        seen_nonexistent_target = TRUE;
     }
 
   svn_pool_destroy(iterpool);
 
-  if (seen_nonexistent_target)
-    return svn_error_create(
-      SVN_ERR_ILLEGAL_TARGET, NULL,
-      _("Could not add all targets because some targets don't exist"));
-  else
-    return SVN_NO_ERROR;
+  if (errors->nelts > 0)
+    {
+      svn_error_t *err;
+
+      err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
+      for (i = 0; i < errors->nelts; i++)
+        {
+          apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
+          if (status == SVN_ERR_WC_PATH_NOT_FOUND)
+            err = svn_error_quick_wrap(err,
+                                       _("Could not add all targets because "
+                                         "some targets don't exist"));
+          else if (status == SVN_ERR_ENTRY_EXISTS)
+            err = svn_error_quick_wrap(err,
+                                       _("Could not add all targets because "
+                                         "some targets are already versioned"));
+        }
+
+      return svn_error_trace(err);
+    }
+
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/fs-py/subversion/svn/blame-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/blame-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/blame-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/blame-cmd.c Mon Dec 19 18:49:34 2011
@@ -283,7 +283,7 @@ svn_cl__blame(apr_getopt_t *os,
   if (! opt_state->xml)
     SVN_ERR(svn_stream_for_stdout(&bl.out, pool));
   else
-    bl.sbuf = svn_stringbuf_create("", pool);
+    bl.sbuf = svn_stringbuf_create_empty(pool);
 
   bl.opt_state = opt_state;
 

Modified: subversion/branches/fs-py/subversion/svn/cat-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/cat-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/cat-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/cat-cmd.c Mon Dec 19 18:49:34 2011
@@ -50,7 +50,8 @@ svn_cl__cat(apr_getopt_t *os,
   int i;
   svn_stream_t *out;
   apr_pool_t *subpool = svn_pool_create(pool);
-  svn_boolean_t seen_nonexistent_target = FALSE;
+  apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
+  svn_error_t *err;
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -67,7 +68,6 @@ svn_cl__cat(apr_getopt_t *os,
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
       const char *truepath;
       svn_opt_revision_t peg_revision;
-      svn_boolean_t success;
 
       svn_pool_clear(subpool);
       SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
@@ -79,21 +79,40 @@ svn_cl__cat(apr_getopt_t *os,
       SVN_ERR(svn_cl__try(svn_client_cat2(out, truepath, &peg_revision,
                                           &(opt_state->start_revision),
                                           ctx, subpool),
-                           &success, opt_state->quiet,
+                           errors, opt_state->quiet,
                            SVN_ERR_UNVERSIONED_RESOURCE,
                            SVN_ERR_ENTRY_NOT_FOUND,
                            SVN_ERR_CLIENT_IS_DIRECTORY,
                            SVN_ERR_FS_NOT_FOUND,
                            SVN_NO_ERROR));
-      if (! success)
-        seen_nonexistent_target = TRUE;
     }
   svn_pool_destroy(subpool);
 
-  if (seen_nonexistent_target)
-    return svn_error_create(
-      SVN_ERR_ILLEGAL_TARGET, NULL,
-      _("Could not cat all targets because some targets don't exist"));
-  else
-    return SVN_NO_ERROR;
+  if (errors->nelts > 0)
+    {
+      err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
+
+      for (i = 0; i < errors->nelts; i++)
+        {
+          apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
+
+          if (status == SVN_ERR_ENTRY_NOT_FOUND ||
+              status == SVN_ERR_FS_NOT_FOUND)
+            err = svn_error_quick_wrap(err, 
+                                       _("Could not cat all targets because "
+                                         "some targets don't exist"));
+          else if (status == SVN_ERR_UNVERSIONED_RESOURCE)
+            err = svn_error_quick_wrap(err,
+                                       _("Could not cat all targets because "
+                                         "some targets are not versioned"));
+          else if (status == SVN_ERR_CLIENT_IS_DIRECTORY)
+            err = svn_error_quick_wrap(err,
+                                       _("Could not cat all targets because "
+                                         "some targets are directories"));
+        }
+
+      return svn_error_trace(err);
+    }
+  
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/fs-py/subversion/svn/changelist-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/changelist-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/changelist-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/changelist-cmd.c Mon Dec 19 18:49:34 2011
@@ -45,7 +45,7 @@ svn_cl__changelist(apr_getopt_t *os,
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
   svn_depth_t depth = opt_state->depth;
-  svn_boolean_t success = TRUE;
+  apr_array_header_t *errors = apr_array_make(pool, 0, sizeof(apr_status_t));
 
   /* If we're not removing changelists, then our first argument should
      be the name of a changelist. */
@@ -103,7 +103,7 @@ svn_cl__changelist(apr_getopt_t *os,
                svn_client_add_to_changelist(targets, changelist_name,
                                             depth, opt_state->changelists,
                                             ctx, pool),
-               &success, opt_state->quiet,
+               errors, opt_state->quiet,
                SVN_ERR_UNVERSIONED_RESOURCE,
                SVN_ERR_WC_PATH_NOT_FOUND,
                SVN_NO_ERROR));
@@ -114,16 +114,36 @@ svn_cl__changelist(apr_getopt_t *os,
                svn_client_remove_from_changelists(targets, depth,
                                                   opt_state->changelists,
                                                   ctx, pool),
-               &success, opt_state->quiet,
+               errors, opt_state->quiet,
                SVN_ERR_UNVERSIONED_RESOURCE,
                SVN_ERR_WC_PATH_NOT_FOUND,
                SVN_NO_ERROR));
     }
 
-  if (!success)
-    return svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL,
-                            _("Could not display info for all targets because "
-                              "some targets don't exist"));
-  else
-    return SVN_NO_ERROR;
+  if (errors->nelts > 0)
+    {
+      int i;
+      svn_error_t *err;
+
+      err = svn_error_create(SVN_ERR_ILLEGAL_TARGET, NULL, NULL);
+      for (i = 0; i < errors->nelts; i++)
+        {
+          apr_status_t status = APR_ARRAY_IDX(errors, i, apr_status_t);
+
+          if (status == SVN_ERR_WC_PATH_NOT_FOUND)
+            err = svn_error_quick_wrap(err,
+                                       _("Could not set changelists on "
+                                         "all targets because some targets "
+                                         "don't exist"));
+          else if (status == SVN_ERR_UNVERSIONED_RESOURCE)
+            err = svn_error_quick_wrap(err,
+                                       _("Could not set changelists on "
+                                         "all targets because some targets "
+                                         "are not versioned"));
+        }
+
+      return svn_error_trace(err);
+    }
+
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/fs-py/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/cl.h?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/cl.h (original)
+++ subversion/branches/fs-py/subversion/svn/cl.h Mon Dec 19 18:49:34 2011
@@ -230,6 +230,7 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t internal_diff;    /* override diff_cmd in config file */
   svn_boolean_t use_git_diff_format; /* Use git's extended diff format */
   svn_boolean_t allow_mixed_rev; /* Allow operation on mixed-revision WC */
+  svn_boolean_t include_externals; /* Recurses (in)to file & dir externals */
 } svn_cl__opt_state_t;
 
 
@@ -294,15 +295,14 @@ extern const apr_getopt_option_t svn_cl_
  * invoked on an unversioned, nonexistent, or otherwise innocuously
  * errorful resource.  Meant to be wrapped with SVN_ERR().
  *
- * If ERR is null, return SVN_NO_ERROR, setting *SUCCESS to TRUE
- * if SUCCESS is not NULL.
+ * If ERR is null, return SVN_NO_ERROR.
  *
  * Else if ERR->apr_err is one of the error codes supplied in varargs,
  * then handle ERR as a warning (unless QUIET is true), clear ERR, and
- * return SVN_NO_ERROR, setting *SUCCESS to FALSE if SUCCESS is not
- * NULL.
+ * return SVN_NO_ERROR, and push the value of ERR->apr_err into the
+ * ERRORS_SEEN array, if ERRORS_SEEN is not NULL.
  *
- * Else return ERR, setting *SUCCESS to FALSE if SUCCESS is not NULL.
+ * Else return ERR.
  *
  * Typically, error codes like SVN_ERR_UNVERSIONED_RESOURCE,
  * SVN_ERR_ENTRY_NOT_FOUND, etc, are supplied in varargs.  Don't
@@ -310,7 +310,7 @@ extern const apr_getopt_option_t svn_cl_
  */
 svn_error_t *
 svn_cl__try(svn_error_t *err,
-            svn_boolean_t *success,
+            apr_array_header_t *errors_seen,
             svn_boolean_t quiet,
             ...);
 
@@ -382,6 +382,9 @@ svn_cl__time_cstring_to_human_cstring(co
 /* Print STATUS for PATH to stdout for human consumption.  Prints in
    abbreviated format by default, or DETAILED format if flag is set.
 
+   When SUPPRESS_EXTERNALS_PLACEHOLDERS is set, avoid printing
+   externals placeholder lines ("X lines").
+
    When DETAILED is set, use SHOW_LAST_COMMITTED to toggle display of
    the last-committed-revision and last-committed-author.
 
@@ -393,10 +396,16 @@ svn_cl__time_cstring_to_human_cstring(co
 
    Increment *TEXT_CONFLICTS, *PROP_CONFLICTS, or *TREE_CONFLICTS if
    a conflict was encountered.
-   */
+
+   Use CWD_ABSPATH -- the absolute path of the current working
+   directory -- to shorten PATH into something relative to that
+   directory as necessary.
+*/
 svn_error_t *
-svn_cl__print_status(const char *path,
+svn_cl__print_status(const char *cwd_abspath,
+                     const char *path,
                      const svn_client_status_t *status,
+                     svn_boolean_t suppress_externals_placeholders,
                      svn_boolean_t detailed,
                      svn_boolean_t show_last_committed,
                      svn_boolean_t skip_unrecognized,
@@ -409,9 +418,15 @@ svn_cl__print_status(const char *path,
 
 
 /* Print STATUS for PATH in XML to stdout.  Use POOL for temporary
-   allocations. */
+   allocations.
+
+   Use CWD_ABSPATH -- the absolute path of the current working
+   directory -- to shorten PATH into something relative to that
+   directory as necessary.
+ */
 svn_error_t *
-svn_cl__print_status_xml(const char *path,
+svn_cl__print_status_xml(const char *cwd_abspath,
+                         const char *path,
                          const svn_client_status_t *status,
                          svn_client_ctx_t *ctx,
                          apr_pool_t *pool);
@@ -553,14 +568,10 @@ svn_cl__merge_file_externally(const char
 
 /* Set *NOTIFY_FUNC_P and *NOTIFY_BATON_P to a notifier/baton for all
  * operations, allocated in POOL.
- *
- * If don't want a summary line at the end of notifications, set
- * SUPPRESS_FINAL_LINE.
  */
 svn_error_t *
 svn_cl__get_notifier(svn_wc_notify_func2_t *notify_func_p,
                      void **notify_baton_p,
-                     svn_boolean_t suppress_final_line,
                      apr_pool_t *pool);
 
 /* Make the notifier for use with BATON print the appropriate summary
@@ -767,42 +778,19 @@ svn_cl__node_description(const svn_wc_co
                          const char *wc_repos_root_URL,
                          apr_pool_t *pool);
 
-/* Return, in @a *true_targets_p, a copy of @a targets with peg revision
- * specifiers snipped off the end of each element.
- *
- * ### JAF TODO: This function is not good because it does not allow the
- * ### caller to detect if an invalid peg revision was specified.
- * ###
- * ### Callers should never have a need to silently *discard* all peg
- * ### revisions, even if they are doing this *after* saving any peg
- * ### revisions that might be of interest on certain arguments: I don't
- * ### think it can ever be correct to silently ignore a peg revision that
- * ### is specified, whether it makes semantic sense or not.
- * ###
- * ### Instead, callers should parse all the arguments and silently
- * ### ignore an *empty* peg revision part (just an "@", which can be
- * ### used to escape an earlier "@" in the argument) on any argument,
- * ### even an argument on which a peg revision does not make sense,
- * ### but should not silently ignore a non-empty peg when it does not
- * ### make sense.
- * ###
- * ### Something like:
- * ###   For each (URL-like?) argument that doesn't accept a peg rev:
- * ###     Parse into peg-rev and true-path parts;
- * ###     If (peg rev != unspecified)
- * ###       Error("This arg doesn't accept a peg rev.").
- * ###     Use the true-path part.
+/* Return, in @a *true_targets_p, a shallow copy of @a targets with any
+ * empty peg revision specifier snipped off the end of each element.  If any
+ * target has a non-empty peg revision specifier, throw an error.  The user
+ * may have specified a peg revision where it doesn't make sense to do so,
+ * or may have forgotten to escape an '@' character in a filename.
  *
  * This function is useful for subcommands for which peg revisions
- * do not make any sense. Such subcommands still need to allow peg
- * revisions to be specified on the command line so that users of
+ * do not make any sense. Such subcommands still need to allow an empty
+ * peg revision to be specified on the command line so that users of
  * the command line client can consistently escape '@' characters
  * in filenames by appending an '@' character, regardless of the
  * subcommand being used.
  *
- * If a peg revision is present but cannot be parsed, an error is thrown.
- * The user has likely forgotten to escape an '@' character in a filename.
- *
  * It is safe to pass the address of @a targets as @a true_targets_p.
  *
  * Do all allocations in @a pool. */
@@ -834,6 +822,23 @@ svn_cl__local_style_skip_ancestor(const 
                                   const char *path,
                                   apr_pool_t *pool);
 
+/* Check that PATH_OR_URL1@REVISION1 is related to PATH_OR_URL2@REVISION2.
+ * Raise an error if not.
+ *
+ * ### Ideally we would also check that they are on different lines of
+ * history.  That is easy in common cases, but to give a correct answer in
+ * general we need to know the operative revision(s) as well.  For example,
+ * when one location is the branch point from which the other branch was
+ * copied.
+ */
+svn_error_t *
+svn_cl__check_related_source_and_target(const char *path_or_url1,
+                                        const svn_opt_revision_t *revision1,
+                                        const char *path_or_url2,
+                                        const svn_opt_revision_t *revision2,
+                                        svn_client_ctx_t *ctx,
+                                        apr_pool_t *pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/branches/fs-py/subversion/svn/commit-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/commit-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/commit-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/commit-cmd.c Mon Dec 19 18:49:34 2011
@@ -166,15 +166,17 @@ svn_cl__commit(apr_getopt_t *os,
     }
 
   /* Commit. */
-  err = svn_client_commit5(targets,
+  err = svn_client_commit6(targets,
                            opt_state->depth,
                            no_unlock,
                            opt_state->keep_changelists,
                            TRUE /* commit_as_operations */,
+                           opt_state->include_externals, /* file externals */
+                           opt_state->include_externals, /* dir externals */
                            opt_state->changelists,
                            opt_state->revprop_table,
-                           ! opt_state->quiet
-                                ? svn_cl__print_commit_info : NULL,
+                           (opt_state->quiet
+                            ? NULL : svn_cl__print_commit_info),
                            NULL,
                            ctx,
                            pool);

Modified: subversion/branches/fs-py/subversion/svn/copy-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/copy-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/copy-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/copy-cmd.c Mon Dec 19 18:49:34 2011
@@ -76,7 +76,18 @@ svn_cl__copy(apr_getopt_t *os,
       APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = source;
     }
 
-  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
+  /* Get DST_PATH (the target path or URL) and check that no peg revision is
+   * specified for it. */
+  {
+    const char *tgt = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *);
+    svn_opt_revision_t peg;
+
+    SVN_ERR(svn_opt_parse_path(&peg, &dst_path, tgt, pool));
+    if (peg.kind != svn_opt_revision_unspecified)
+      return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
+                               _("'%s': a peg revision is not allowed here"),
+                               tgt);
+  }
 
   /* Figure out which type of notification to use.
      (There is no need to check that the src paths are homogeneous;
@@ -84,8 +95,6 @@ svn_cl__copy(apr_getopt_t *os,
      error if they are not.) */
   src_path = APR_ARRAY_IDX(targets, 0, const char *);
   srcs_are_urls = svn_path_is_url(src_path);
-  dst_path = APR_ARRAY_IDX(targets, targets->nelts - 1, const char *);
-  apr_array_pop(targets);
   dst_is_url = svn_path_is_url(dst_path);
 
   if ((! srcs_are_urls) && (! dst_is_url))
@@ -127,7 +136,8 @@ svn_cl__copy(apr_getopt_t *os,
   err = svn_client_copy6(sources, dst_path, TRUE,
                          opt_state->parents, opt_state->ignore_externals,
                          opt_state->revprop_table,
-                         svn_cl__print_commit_info, NULL,
+                         (opt_state->quiet ? NULL : svn_cl__print_commit_info),
+                         NULL,
                          ctx, pool);
 
   if (ctx->log_msg_func3)

Modified: subversion/branches/fs-py/subversion/svn/delete-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/delete-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/delete-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/delete-cmd.c Mon Dec 19 18:49:34 2011
@@ -79,7 +79,9 @@ svn_cl__delete(apr_getopt_t *os,
   SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));
 
   err = svn_client_delete4(targets, opt_state->force, opt_state->keep_local,
-                           opt_state->revprop_table, svn_cl__print_commit_info,
+                           opt_state->revprop_table,
+                           (opt_state->quiet
+                            ? NULL : svn_cl__print_commit_info),
                            NULL, ctx, pool);
   if (err)
     err = svn_cl__may_need_force(err);

Modified: subversion/branches/fs-py/subversion/svn/diff-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/diff-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/diff-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/diff-cmd.c Mon Dec 19 18:49:34 2011
@@ -89,7 +89,7 @@ summarize_xml(const svn_client_diff_summ
   /* Full path to the object being diffed.  This is created by taking the
    * baton, and appending the target's relative path. */
   const char *path = *(const char **)baton;
-  svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+  svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
 
   /* Tack on the target path, so we can differentiate between different parts
    * of the output when we're given multiple targets. */
@@ -197,7 +197,7 @@ svn_cl__diff(apr_getopt_t *os,
 
       SVN_ERR(svn_cl__xml_print_header("diff", pool));
 
-      sb = svn_stringbuf_create("", pool);
+      sb = svn_stringbuf_create_empty(pool);
       svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "paths", NULL);
       SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
     }
@@ -419,7 +419,7 @@ svn_cl__diff(apr_getopt_t *os,
 
   if (opt_state->xml)
     {
-      svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+      svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
       svn_xml_make_close_tag(&sb, pool, "paths");
       SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
       SVN_ERR(svn_cl__xml_print_footer("diff", pool));

Modified: subversion/branches/fs-py/subversion/svn/import-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/import-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/import-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/import-cmd.c Mon Dec 19 18:49:34 2011
@@ -120,7 +120,8 @@ svn_cl__import(apr_getopt_t *os,
                               opt_state->no_ignore,
                               opt_state->force,
                               opt_state->revprop_table,
-                              svn_cl__print_commit_info,
+                              (opt_state->quiet
+                               ? NULL : svn_cl__print_commit_info),
                               NULL,
                               ctx,
                               pool), pool));

Modified: subversion/branches/fs-py/subversion/svn/info-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/info-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/info-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/info-cmd.c Mon Dec 19 18:49:34 2011
@@ -85,7 +85,7 @@ print_info_xml(void *baton,
                const svn_client_info2_t *info,
                apr_pool_t *pool)
 {
-  svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+  svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
   const char *rev_str;
   const char *path_prefix = baton;
 

Modified: subversion/branches/fs-py/subversion/svn/list-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/list-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/list-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/list-cmd.c Mon Dec 19 18:49:34 2011
@@ -156,7 +156,7 @@ print_dirent_xml(void *baton,
   if (pb->ctx->cancel_func)
     SVN_ERR(pb->ctx->cancel_func(pb->ctx->cancel_baton));
 
-  sb = svn_stringbuf_create("", pool);
+  sb = svn_stringbuf_create_empty(pool);
 
   svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "entry",
                         "kind", svn_cl__node_kind_str_xml(dirent->kind),
@@ -276,7 +276,7 @@ svn_cl__list(apr_getopt_t *os,
 
       if (opt_state->xml)
         {
-          svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+          svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
           svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "list",
                                 "path", truepath[0] == '\0' ? "." : truepath,
                                 NULL);
@@ -308,7 +308,7 @@ svn_cl__list(apr_getopt_t *os,
 
       if (opt_state->xml)
         {
-          svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+          svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
           svn_xml_make_close_tag(&sb, pool, "list");
           SVN_ERR(svn_cl__error_checked_fputs(sb->data, stdout));
         }

Modified: subversion/branches/fs-py/subversion/svn/log-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/log-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/log-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/log-cmd.c Mon Dec 19 18:49:34 2011
@@ -51,8 +51,9 @@ struct log_receiver_baton
   /* Client context. */
   svn_client_ctx_t *ctx;
 
-  /* The URL target of the log operation. */
-  const char *target_url;
+  /* The target of the log operation. */
+  const char *target_path_or_url;
+  svn_opt_revision_t target_peg_revision;
 
   /* Don't print log message body nor its line count. */
   svn_boolean_t omit_log_message;
@@ -227,8 +228,7 @@ log_entry_receiver(void *baton,
           svn_sort__item_t *item = &(APR_ARRAY_IDX(sorted_paths, i,
                                                    svn_sort__item_t));
           const char *path = item->key;
-          svn_log_changed_path2_t *log_item
-            = apr_hash_get(log_entry->changed_paths2, item->key, item->klen);
+          svn_log_changed_path2_t *log_item = item->value;
           const char *copy_data = "";
 
           if (lb->ctx->cancel_func)
@@ -274,6 +274,9 @@ log_entry_receiver(void *baton,
       SVN_ERR(svn_cmdline_printf(pool, "\n%s\n", message));
     }
 
+  SVN_ERR(svn_cmdline_fflush(stdout));
+  SVN_ERR(svn_cmdline_fflush(stderr));
+
   /* Print a diff if requested. */
   if (lb->show_diff)
     {
@@ -282,7 +285,6 @@ log_entry_receiver(void *baton,
       apr_array_header_t *diff_options;
       svn_opt_revision_t start_revision;
       svn_opt_revision_t end_revision;
-      svn_error_t *err;
 
       SVN_ERR(svn_stream_for_stdout(&outstream, pool));
       SVN_ERR(svn_stream_for_stderr(&errstream, pool));
@@ -299,89 +301,28 @@ log_entry_receiver(void *baton,
       end_revision.kind = svn_opt_revision_number;
       end_revision.value.number = log_entry->revision;
 
-      SVN_ERR(svn_cmdline_printf(pool, _("\n")));
-      err = svn_client_diff6(diff_options,
-                             lb->target_url,
-                             &start_revision,
-                             lb->target_url,
-                             &end_revision,
-                             NULL,
-                             lb->depth,
-                             FALSE, /* ignore ancestry */
-                             TRUE, /* no diff deleted */
-                             FALSE, /* show copies as adds */
-                             FALSE, /* ignore content type */
-                             FALSE, /* use git diff format */
-                             svn_cmdline_output_encoding(pool),
-                             outstream,
-                             errstream,
-                             NULL,
-                             lb->ctx, pool);
-      if (err)
-        {
-          /* We get a "path not found" error in case the revision created
-           * lb->target_url. Try to show a diff from the parent instead. */
-          if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
-            {
-              const char *parent;
-              apr_pool_t *iterpool;
-
-              svn_error_clear(err);
-
-              parent = svn_uri_dirname(lb->target_url, pool);
-              iterpool = svn_pool_create(pool);
-              while (strcmp(parent, lb->target_url) != 0)
-                {
-                  svn_pool_clear(iterpool);
-                  err = svn_client_diff6(diff_options,
-                                         parent,
-                                         &start_revision,
-                                         parent,
-                                         &end_revision,
-                                         NULL,
-                                         lb->depth,
-                                         FALSE, /* ignore ancestry */
-                                         TRUE, /* no diff deleted */
-                                         FALSE, /* show copies as adds */
-                                         FALSE, /* ignore content type */
-                                         FALSE, /* use git diff format */
-                                         svn_cmdline_output_encoding(iterpool),
-                                         outstream,
-                                         errstream,
-                                         NULL,
-                                         lb->ctx, iterpool);
-                  if (err == SVN_NO_ERROR)
-                    break;
-                  else
-                    {
-                      if (err->apr_err == SVN_ERR_FS_NOT_FOUND)
-                        {
-                          svn_error_clear(err);
-                          parent = svn_uri_dirname(parent, pool);
-                          continue;
-                        }
-                      if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL ||
-                          err->apr_err == SVN_ERR_AUTHZ_UNREADABLE ||
-                          err->apr_err == SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED)
-                        {
-                          svn_error_clear(err);
-                          break;
-                        }
-                      return svn_error_trace(err);
-                    }
-                }
-              svn_pool_destroy(iterpool);
-            }
-          else
-            return svn_error_trace(err);
-        }
-
-      SVN_ERR(svn_cmdline_printf(pool, _("\n")));
+      SVN_ERR(svn_stream_printf(outstream, pool, _("\n")));
+      SVN_ERR(svn_client_diff_peg6(diff_options,
+                                   lb->target_path_or_url,
+                                   &lb->target_peg_revision,
+                                   &start_revision, &end_revision,
+                                   NULL,
+                                   lb->depth,
+                                   FALSE, /* ignore ancestry */
+                                   TRUE, /* no diff deleted */
+                                   FALSE, /* show copies as adds */
+                                   FALSE, /* ignore content type */
+                                   FALSE, /* use git diff format */
+                                   svn_cmdline_output_encoding(pool),
+                                   outstream,
+                                   errstream,
+                                   NULL,
+                                   lb->ctx, pool));
+      SVN_ERR(svn_stream_printf(outstream, pool, _("\n")));
+      SVN_ERR(svn_stream_close(outstream));
+      SVN_ERR(svn_stream_close(errstream));
     }
 
-  SVN_ERR(svn_cmdline_fflush(stdout));
-  SVN_ERR(svn_cmdline_fflush(stderr));
-
   if (log_entry->has_children)
     APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
 
@@ -432,7 +373,7 @@ log_entry_receiver_xml(void *baton,
 {
   struct log_receiver_baton *lb = baton;
   /* Collate whole log message into sb before printing. */
-  svn_stringbuf_t *sb = svn_stringbuf_create("", pool);
+  svn_stringbuf_t *sb = svn_stringbuf_create_empty(pool);
   char *revstr;
   const char *author;
   const char *date;
@@ -568,8 +509,6 @@ svn_cl__log(apr_getopt_t *os,
   struct log_receiver_baton lb;
   const char *target;
   int i;
-  svn_opt_revision_t peg_revision;
-  const char *true_path;
   apr_array_header_t *revprops;
 
   if (!opt_state->xml)
@@ -623,8 +562,6 @@ svn_cl__log(apr_getopt_t *os,
   /* Add "." if user passed 0 arguments */
   svn_opt_push_implicit_dot_target(targets, pool);
 
-  target = APR_ARRAY_IDX(targets, 0, const char *);
-
   /* Determine if they really want a two-revision range. */
   if (opt_state->used_change_arg)
     {
@@ -646,9 +583,15 @@ svn_cl__log(apr_getopt_t *os,
         }
     }
 
-  /* Strip peg revision. */
-  SVN_ERR(svn_opt_parse_path(&peg_revision, &true_path, target, pool));
-  APR_ARRAY_IDX(targets, 0, const char *) = true_path;
+  /* Parse the first target into path-or-url and peg revision. */
+  target = APR_ARRAY_IDX(targets, 0, const char *);
+  SVN_ERR(svn_opt_parse_path(&lb.target_peg_revision, &lb.target_path_or_url,
+                             target, pool));
+  if (lb.target_peg_revision.kind == svn_opt_revision_unspecified)
+    lb.target_peg_revision.kind = (svn_path_is_url(target)
+                                     ? svn_opt_revision_head
+                                     : svn_opt_revision_working);
+  APR_ARRAY_IDX(targets, 0, const char *) = lb.target_path_or_url;
 
   if (svn_path_is_url(target))
     {
@@ -667,8 +610,6 @@ svn_cl__log(apr_getopt_t *os,
 
   lb.ctx = ctx;
   lb.omit_log_message = opt_state->quiet;
-  SVN_ERR(svn_client_url_from_path2(&lb.target_url, true_path, ctx,
-                                    pool, pool));
   lb.show_diff = opt_state->show_diff;
   lb.depth = opt_state->depth == svn_depth_unknown ? svn_depth_infinity
                                                    : opt_state->depth;
@@ -719,7 +660,7 @@ svn_cl__log(apr_getopt_t *os,
             APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
         }
       SVN_ERR(svn_client_log5(targets,
-                              &peg_revision,
+                              &lb.target_peg_revision,
                               opt_state->revision_ranges,
                               opt_state->limit,
                               opt_state->verbose,
@@ -742,7 +683,7 @@ svn_cl__log(apr_getopt_t *os,
       if (!opt_state->quiet)
         APR_ARRAY_PUSH(revprops, const char *) = SVN_PROP_REVISION_LOG;
       SVN_ERR(svn_client_log5(targets,
-                              &peg_revision,
+                              &lb.target_peg_revision,
                               opt_state->revision_ranges,
                               opt_state->limit,
                               opt_state->verbose,

Modified: subversion/branches/fs-py/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/main.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/main.c (original)
+++ subversion/branches/fs-py/subversion/svn/main.c Mon Dec 19 18:49:34 2011
@@ -54,7 +54,7 @@
 #include "svn_version.h"
 #include "cl.h"
 
-#include "private/svn_wc_private.h"
+#include "private/svn_opt_private.h"
 #include "private/svn_cmdline_private.h"
 
 #include "svn_private_config.h"
@@ -124,6 +124,7 @@ typedef enum svn_cl__longopt_t {
   opt_internal_diff,
   opt_use_git_diff_format,
   opt_allow_mixed_revisions,
+  opt_include_externals,
 } svn_cl__longopt_t;
 
 
@@ -145,7 +146,11 @@ const apr_getopt_option_t svn_cl__option
   {"change",        'c', 1,
                     N_("the change made by revision ARG (like -r ARG-1:ARG)\n"
                        "                             "
-                       "If ARG is negative this is like -r ARG:ARG-1")},
+                       "If ARG is negative this is like -r ARG:ARG-1\n"
+                       "                             "
+                       "If ARG is of the form ARG1-ARG2 then this is like\n"
+                       "                             "
+                       "ARG1:ARG2, where ARG1 is inclusive")},
   {"revision",      'r', 1,
                     N_("ARG (some commands also take ARG1:ARG2 range)\n"
                        "                             "
@@ -295,11 +300,14 @@ const apr_getopt_option_t svn_cl__option
   {"accept",        opt_accept, 1,
                     N_("specify automatic conflict resolution action\n"
                        "                             "
-                       "('postpone', 'base', 'mine-conflict',\n"
+                       "('postpone', 'working', 'base', 'mine-conflict',\n"
                        "                             "
                        "'theirs-conflict', 'mine-full', 'theirs-full',\n"
                        "                             "
-                       "'edit', 'launch')")},
+                       "'edit', 'launch')\n"
+                       "                             "
+                       "(shorthand: 'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l')"
+                       )},
   {"show-revs",     opt_show_revs, 1,
                     N_("specify which collection of revisions to display\n"
                        "                             "
@@ -341,6 +349,12 @@ const apr_getopt_option_t svn_cl__option
                        "Use of this option is not recommended!\n"
                        "                             "
                        "Please run 'svn update' instead.")},
+  {"include-externals", opt_include_externals, 0,
+                       N_("Also commit file and dir externals reached by\n"
+                       "                             "
+                       "recursion. This does not include externals with a\n"
+                       "                             "
+                       "fixed revision. (See the svn:externals property)")},
 
   /* Long-opt Aliases
    *
@@ -459,7 +473,7 @@ const svn_opt_subcommand_desc2_t svn_cl_
        "  If any targets are (or contain) locked items, those will be\n"
        "  unlocked after a successful commit.\n"),
     {'q', 'N', opt_depth, opt_targets, opt_no_unlock, SVN_CL__LOG_MSG_OPTIONS,
-     opt_changelist, opt_keep_changelists} },
+     opt_changelist, opt_keep_changelists, opt_include_externals} },
 
   { "copy", svn_cl__copy, {"cp"}, N_
     ("Duplicate something in working copy or repository, remembering\n"
@@ -651,7 +665,11 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "    svn log bar.c@42\n"
      "    svn log http://www.example.com/repo/project/foo.c\n"
      "    svn log http://www.example.com/repo/project foo.c bar.c\n"
-     "    svn log http://www.example.com/repo/project@50 foo.c bar.c\n"),
+     "    svn log http://www.example.com/repo/project@50 foo.c bar.c\n"
+     "\n"
+     "    This command shows the log entry for the revision the branch\n"
+     "    ^/branches/foo was created in:\n"
+     "      svn log --stop-on-copy --limit 1 -r0:HEAD ^/branches/foo\n"),
     {'r', 'q', 'v', 'g', 'c', opt_targets, opt_stop_on_copy, opt_incremental,
      opt_xml, 'l', opt_with_all_revprops, opt_with_no_revprops, opt_with_revprop,
      opt_depth, opt_diff, opt_diff_cmd, opt_internal_diff, 'x'},
@@ -659,267 +677,330 @@ const svn_opt_subcommand_desc2_t svn_cl_
      {'c', N_("the change made in revision ARG")}} },
 
   { "merge", svn_cl__merge, {0}, N_
-    ("Apply the differences between two sources to a working copy path.\n"
-     "usage: 1. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
-     "       2. merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
-     "       3. merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
-     "\n"
-     "  1. The first form is called a \"sync\", or \"cherry-pick\", merge:\n"
-     "     svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
-     "\n"
-     "     A sync merge is used to merge into a branch any unmerged changes\n"
-     "     made on its immediate ancestor branch.\n"
-     "\n"
-     "     A cherry-picking merge is used to merge specific revisions from\n"
-     "     one branch to another.\n"
-     "\n"
-     "     SOURCE is usually a URL. The source of a cherry-picking merge can\n"
-     "     also be a working copy path, in which case the corresponding URL\n"
-     "     of the path is used.\n"
-     "\n"
-     "     If REV is specified, it is used as the peg revision for SOURCE,\n"
-     "     i.e. SOURCE is looked up in the repository at revision REV.\n"
-     "     If REV is not specified, the HEAD revision is assumed.\n"
-     "\n"
-     "     TARGET_WCPATH is a working copy of the branch the changes will\n"
-     "     be applied to.\n"
-     "\n"
-     "     '-r N:M' specifies a revision range to be merged. The difference\n"
-     "     between SOURCE@REV as it existed at revision N, and SOURCE@REV at\n"
-     "     it existed at revision M, is merged into TARGET_WCPATH.  If no\n"
-     "     revision range is specified, the default range of 0:REV is used.\n"
-     "     \n"
-     "     If mergeinfo within TARGET_WCPATH indicates that revisions within\n"
-     "     the range were already merged, changes made in those revisions\n"
-     "     are not merged again. If needed, the range is broken into multiple\n"
-     "     sub-ranges, and each sub-range is merged separately.\n"
-     "\n"
-     "     If N is greater than M, the range is a \"reverse range\".\n"
-     "     A reverse range can be used to undo changes made to SOURCE\n"
-     "     between revisions N and M.\n"
-     "\n"
-     "     '-c M' is equivalent to the range '-r <M-1>:M'.\n"
-     "     '-c -M' does the reverse: '-r M:<M-1>'.\n"
-     "     \n"
-     "     Multiple '-c' and/or '-r' options may be specified and mixing of\n"
-     "     forward and reverse ranges is allowed.\n"
-     "\n"
-     "       - Sync Merge Example -\n"
-     "\n"
-     "     A feature is being developed on a branch called \"feature\".\n"
-     "     The feature branch is regularly synced with trunk to keep up with\n"
-     "     changes made there.\n"
-     "\n"
-     "                 feature  +------------------------o-----\n"
-     "                         /                         ^\n"
-     "                        /                         /\n"
-     "                       /          .............../\n"
-     "         trunk ------+------------L--------------R------\n"
-     "                                r100           r200\n"
-     "     \n"
-     "     In the above diagram, L marks the \"left\" side of the merge\n"
-     "     (trunk@100), and R marks the \"right\" side of the merge (trunk@200).\n"
-     "     The difference between the left and right side is merged into the target.\n"
-     "\n"
-     "     To perform the merge, check out a working copy of the feature\n"
-     "     branch and run the following command in the top-level directory\n"
-     "     of the working copy:\n"
-     "\n"
-     "         svn merge ^/trunk\n"
-     "\n"
-     "     The default revision range is -r0:HEAD, so any unmerged changes\n"
-     "     will be merged.\n"
-     "\n"
-     "       - Cherry-picking Merge Example -\n"
-     "\n"
-     "     A bug has been fixed on trunk on revision 50. This fix needs to\n"
-     "     be merged from the trunk into the release branch.\n"
-     "\n"
-     "            1.x-release  +-----------------------o-----\n"
-     "                        /                        ^\n"
-     "                       /                         |\n"
-     "                      /                          |\n"
-     "         trunk ------+--------------------------LR-----\n"
-     "                                                r50\n"
-     "     \n"
-     "     In the above diagram, L marks the left side of the merge (trunk@49)\n"
-     "     and R marks the right side of the merge (trunk@50).\n"
-     "     The difference between the left and right side is merged into the target.\n"
-     "\n"
-     "     To perform the merge, check out a working copy of the release\n"
-     "     branch and run the following command in the top-level directory\n"
-     "     of the working copy:\n"
-     "\n"
-     "         svn merge -c50 ^/trunk\n"
-     "\n"
-     "     If several commits to trunk were related to the fix, multiple\n"
-     "     revisions can be merged:\n"
-     "\n"
-     "         svn merge -c50,54,60 ^/trunk\n"
-     "\n"
-     "\n"
-     "  2. The second form is called a \"reintegrate merge\":\n"
-     "     svn merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
-     "\n"
-     "     SOURCE is the URL of a branch to be merged back into (usually) its\n"
-     "     immediate ancestor branch.  If REV is specified, it is used a\n"
-     "     the peg revision for SOURCE, i.e. SOURCE is looked up in the\n"
-     "     repository at revision REV.  If REV is not specified, the HEAD\n"
-     "     revision is assumed.\n"
-     "\n"
-     "     TARGET_WCPATH is a working copy of the branch the changes will\n"
-     "     be applied to.\n"
-     "\n"
-     "       - Reintegrate Merge Example -\n"
-     "\n"
-     "     A feature has been developed on a branch called \"feature\".\n"
-     "     The feature branch started as a copy of trunk@W. Work on the\n"
-     "     feature has completed and it should be merged back into the trunk.\n"
-     "     \n"
-     "     The feature branch was last synced with its immediate ancestor,\n"
-     "     the trunk, in revision X. So the difference between trunk@X and\n"
-     "     feature@HEAD contains the complete set of changes that implement\n"
-     "     the feature, and no other changes. These changes are applied to\n"
-     "     the trunk.\n"
-     "\n"
-     "                 feature  +-------------------------------R\n"
-     "                         /                               . \\\n"
-     "                        /                  ..............   \\\n"
-     "                       /                  .                  v\n"
-     "         trunk ------+--------------------L------------------o\n"
-     "                    rW                   rX\n"
-     "\n"
-     "     In the diagram above, L marks the left side of the merge (trunk@X),\n"
-     "     and R marks the right side of the merge (feature@HEAD). The difference\n"
-     "     between the left and right side is merged into the target.\n"
-     "\n"
-     "     To perform the merge, check out a working copy of the trunk, and run\n"
-     "     the following command in the top-level directory of the working copy:\n"
-     "\n"
-     "         svn merge --reintegrate ^/feature\n"
-     "\n"
-     "     To prevent unnecessary merge conflicts, reintegrate merges require\n"
-     "     that TARGET_WCPATH is not a mixed-revision working copy, has no\n"
-     "     local modifications, and has no switched subtrees.\n"
-     "\n"
-     "     Reintegrate merges also require that the reintegrate source be fully\n"
-     "     synced with the target since their common branch point.\n"
-     "     In the above example this means that all of the changes made\n"
-     "     on trunk between revision W and revision X are fully merged to\n"
-     "     the feature branch before it can be reintegrated back to trunk.\n"
-     "\n"
-     "     After the reintegrate merge, the feature branch cannot be synced\n"
-     "     to the trunk again without merge conflicts. If further work must\n"
-     "     be done on the feature branch, it should be deleted and then re-created.\n"
-     "\n"
-     "\n"
-     "  3. The third form is called a \"2-URL merge\":\n"
-     "     svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
-     "\n"
-     "     Two source URLs are specified, together with two revisions N and M.\n"
-     "     The two sources to be compared at the specified revisions, and the\n"
-     "     difference is applied to TARGET_WCPATH, which is a path to a working\n"
-     "     copy of another branch.\n"
-     "\n"
-     "     The revisions default to HEAD if omitted.\n"
-     "\n"
-     "     If TARGET_WCPATH is omitted, a default value of '.' is assumed,\n"
-     "     unless the sources have identical basenames that match a file\n"
-     "     within '.'; In which case, the differences will be applied to\n"
-     "     that file.\n"
-     "\n"
-     "     The sources can also be specified as working copy paths, in which\n"
-     "     case the URLs of the merge sources are derived from the working copies.\n"
-     "\n"
-     "     This is the most flexible type of merge, but also the most difficult\n"
-     "     to use. It can be used to merge the differences between two (possibly\n"
-     "     ancestrally unrelated) branches into a working copy of another branch.\n"
-     "     This type of merge should be used very carefully because the probability\n"
-     "     of merge conflicts is quite high. In most use cases, a sync, cherry-pick,\n"
-     "     or reintegrate merge is sufficient and reduces the chances of mistakes.\n"
-     "\n"
-     "       - 2-URL Merge Example -\n"
-     "\n"
-     "     A feature has been developed on a branch called \"feature\".\n"
-     "     Development for the upcoming 3.0 release has happened in parallel on\n"
-     "     the \"3.x-release\" branch. The work on the feature branch must be\n"
-     "     merged to the 3.x-release branch. However, the feature branch and\n"
-     "     the 3.x-release branch are not directly related, so a 2-URL merge\n"
-     "     is needed.\n"
-     "     The feature branch was last synced with its immediate ancestor,\n"
-     "     the trunk, up to revision 500. So the difference between trunk@500\n"
-     "     and feature@HEAD contains the complete set of changes related to\n"
-     "     the feature, and no other changes. These changes are applied to\n"
-     "     the 3.x-release branch.\n"
-     "\n"
-     "                   3.x-release  +-----------------------------------o\n"
-     "                               /                                    ^\n"
-     "                              /                                    /\n"
-     "                             /              r500                  /\n"
-     "         trunk ------+------+-----------------L--------->        /\n"
-     "                      \\                         .               /\n"
-     "                       \\                         ...........   /\n"
-     "                        \\                                   . /\n"
-     "                feature  +-----------------------------------R\n"
-     "\n"
-     "     In the diagram above, L marks the left side of the merge (trunk@500),\n"
-     "     and R marks the right side of the merge is (feature@HEAD).\n"
-     "     The difference between the left and right side is merged into the target.\n"
-     "\n"
-     "     To perform the merge, check out a working copy of the 3.x-release\n"
-     "     branch and run the following command in the top-level directory\n"
-     "     of the working copy:\n"
-     "       \n"
-     "         svn merge ^/trunk@500 ^/feature\n"
-     "\n"
-     "     Before performing a 2-URL merge, it is a good idea to preview the\n"
-     "     changes which will be merged, because there is no guarantee that\n"
-     "     the merge will be free of conflicts. The preview can be done with\n"
-     "     the svn diff command:\n"
-     "\n"
-     "         svn diff ^/trunk@500 ^/feature@HEAD\n"
-     "\n"
-     "     Note that a 2-URL merge can also merge from foreign repositories.\n"
-     "     While SOURCE1 and SOURCE2 must both come from the same repository,\n"
-     "     TARGET_WCPATH may come from a different repository than the sources.\n"
-     "     However, there are some caveats. Most notably, copies made in the\n"
-     "     merge source will be transformed into plain additions in the merge\n"
-     "     target. Also, merge-tracking is not supported.\n"
-     "\n"
-     "\n"
-     "  The following applies to all types of merges:\n"
-     "\n"
-     "  To prevent unnecessary merge conflicts, svn merge requires that\n"
-     "  TARGET_WCPATH is not a mixed-revision working copy.\n"
-     "  Running 'svn update' before starting a merge ensures that all\n"
-     "  items in the working copy are based on the same revision.\n"
-     "\n"
-     "  For each merged item a line will be printed with characters reporting\n"
-     "  the action taken. These characters have the following meaning:\n"
-     "\n"
-     "    A  Added\n"
-     "    D  Deleted\n"
-     "    U  Updated\n"
-     "    C  Conflict\n"
-     "    G  Merged\n"
-     "    E  Existed\n"
-     "    R  Replaced\n"
-     "\n"
-     "  Characters in the first column report about the item itself.\n"
-     "  Characters in the second column report about properties of the item.\n"
-     "  A 'C' in the third column indicates a tree conflict, while a 'C' in\n"
-     "  the first and second columns indicate textual conflicts in files\n"
-     "  and in property values, respectively.\n"
-     "\n"
-     "  NOTE:  Subversion uses the svn:mergeinfo property to track merge\n"
-     "  history.  This property is considered at the start of a merge to\n"
-     "  determine what to merge and it is updated at the conclusion of the\n"
-     "  merge to describe the merge that took place.  Mergeinfo is used only\n"
-     "  if the two sources are on the same line of history -- if the first\n"
-     "  source is an ancestor of the second, or vice-versa.  This is guaranteed\n"
-     "  to be the case when using sync merges and reintegrate merges.\n"
-     "  The --ignore-ancestry option prevents merge tracking and thus\n"
-     "  ignores mergeinfo, neither considering it nor recording it.\n"),
+    ( /* For this large section, let's keep it unindented for easier
+       * viewing/editing. It has been vim-treated with a textwidth=75 and 'gw'
+       * (with quotes and newlines removed). */
+"Merge changes into a working copy.\n"
+"usage: 1. merge SOURCE[@REV] [TARGET_WCPATH]\n"
+"          (the 'sync' merge)\n"
+"       2. merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
+"          (the 'cherry-pick' merge)\n"
+"       3. merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
+"          (the 'reintegrate' merge)\n"
+"       4. merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
+"          (the '2-URL' merge)\n"
+"\n"
+"  1. This form is called a 'sync' (or 'catch-up') merge:\n"
+"\n"
+"       svn merge SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+"     A sync merge is used to fetch all the latest changes made on a parent\n"
+"     branch. In other words, the target branch has originally been created\n"
+"     by copying the source branch, and any changes committed on the source\n"
+"     branch since branching are applied to the target branch. This uses\n"
+"     merge tracking to skip all those revisions that have already been\n"
+"     merged, so a sync merge can be repeated periodically to stay up-to-\n"
+"     date with the source branch.\n"
+"\n"
+"     SOURCE specifies the branch from where the changes will be pulled, and\n"
+"     TARGET_WCPATH specifies a working copy of the target branch to which\n"
+"     the changes will be applied. Normally SOURCE and TARGET_WCPATH should\n"
+"     each correspond to the root of a branch. (If you want to merge only a\n"
+"     subtree, then the subtree path must be included in both SOURCE and\n"
+"     TARGET_WCPATH; this is discouraged, to avoid subtree mergeinfo.)\n"
+"\n"
+"     SOURCE is usually a URL. The optional '@REV' specifies both the peg\n"
+"     revision of the URL and the latest revision that will be considered\n"
+"     for merging; if REV is not specified, the HEAD revision is assumed. If\n"
+"     SOURCE is a working copy path, the corresponding URL of the path is\n"
+"     used, and the default value of 'REV' is the base revision (usually the\n"
+"     revision last updated to).\n"
+"\n"
+"     TARGET_WCPATH is a working copy path; if omitted, '.' is assumed.\n"
+"\n"
+"       - Sync Merge Example -\n"
+"\n"
+"     A feature is being developed on a branch called 'feature', which has\n"
+"     originally been a copy of trunk. The feature branch has been regularly\n"
+"     synced with trunk to keep up with the changes made there. The previous\n"
+"     sync merges are not shown on this diagram, and the last of them was\n"
+"     done when HEAD was r100. Currently, HEAD is r200.\n"
+"\n"
+"                feature  +------------------------o-----\n"
+"                        /                         ^\n"
+"                       /            ............  |\n"
+"                      /            .            . /\n"
+"         trunk ------+------------L--------------R------\n"
+"                                r100           r200\n"
+"\n"
+"     Subversion will locate all the changes on 'trunk' that have not yet\n"
+"     been merged into the 'feature' branch. In this case that is a single\n"
+"     range, r100:200. In the diagram above, L marks the left side\n"
+"     (trunk@100) and R marks the right side (trunk@200) of the merge. The\n"
+"     difference between L and R will be applied to the target working copy\n"
+"     path. In this case, the working copy is a clean checkout of the entire\n"
+"     'feature' branch.\n"
+"\n"
+"     To perform this sync merge, have a clean working copy of the feature\n"
+"     branch and run the following command in its top-level directory:\n"
+"\n"
+"         svn merge ^/trunk\n"
+"\n"
+"     Note that the merge is now only in your local working copy and still\n"
+"     needs to be committed to the repository so that it can be seen by\n"
+"     others. You can review the changes and you may have to resolve\n"
+"     conflicts before you commit the merge.\n"
+"\n"
+"\n"
+"  2. This form is called a 'cherry-pick' merge:\n"
+"\n"
+"       svn merge [-c M[,N...] | -r N:M ...] SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+"     A cherry-pick merge is used to merge specific revisions (or revision\n"
+"     ranges) from one branch to another. By default, this uses merge\n"
+"     tracking to automatically skip any revisions that have already been\n"
+"     merged to the target; you can use the --ignore-ancestry option to\n"
+"     disable such skipping.\n"
+"\n"
+"     SOURCE is usually a URL. The optional '@REV' specifies only the peg\n"
+"     revision of the URL and does not affect the merge range; if REV is not\n"
+"     specified, the HEAD revision is assumed. If SOURCE is a working copy\n"
+"     path, the corresponding URL of the path is used, and the default value\n"
+"     of 'REV' is the base revision (usually the revision last updated to).\n"
+"\n"
+"     TARGET_WCPATH is a working copy path; if omitted, '.' is assumed.\n"
+"\n"
+"     The revision ranges to be merged are specified by the '-r' and/or '-c'\n"
+"     options. '-r N:M' refers to the difference in the history of the\n"
+"     source branch between revisions N and M. You can use '-c M' to merge\n"
+"     single revisions: '-c M' is equivalent to '-r <M-1>:M'. Each such\n"
+"     difference is applied to TARGET_WCPATH.\n"
+"\n"
+"     If the mergeinfo in TARGET_WCPATH indicates that revisions within the\n"
+"     range were already merged, changes made in those revisions are not\n"
+"     merged again. If needed, the range is broken into multiple sub-ranges,\n"
+"     and each sub-range is merged separately.\n"
+"\n"
+"     A 'reverse range' can be used to undo changes. For example, when\n"
+"     source and target refer to the same branch, a previously committed\n"
+"     revision can be 'undone'. In a reverse range, N is greater than M in\n"
+"     '-r N:M', or the '-c' option is used with a negative number: '-c -M'\n"
+"     is equivalent to '-r M:<M-1>'.\n"
+"\n"
+"     Multiple '-c' and/or '-r' options may be specified and mixing of\n"
+"     forward and reverse ranges is allowed.\n"
+"\n"
+"       - Cherry-pick Merge Example -\n"
+"\n"
+"     A bug has been fixed on trunk in revision 50. This fix needs to\n"
+"     be merged from trunk onto the release branch.\n"
+"\n"
+"            1.x-release  +-----------------------o-----\n"
+"                        /                        ^\n"
+"                       /                         |\n"
+"                      /                          |\n"
+"         trunk ------+--------------------------LR-----\n"
+"                                                r50\n"
+"\n"
+"     In the above diagram, L marks the left side (trunk@49) and R marks the\n"
+"     right side (trunk@50) of the merge. The difference between the left\n"
+"     and right side is applied to the target working copy path.\n"
+"\n"
+"     Note that the difference between revision 49 and 50 is exactly those\n"
+"     changes that were committed in revision 50, not including changes\n"
+"     committed in revision 49.\n"
+"\n"
+"     To perform the merge, have a clean working copy of the release branch\n"
+"     and run the following command in its top-level directory; remember\n"
+"     that the default target is '.':\n"
+"\n"
+"         svn merge -c50 ^/trunk\n"
+"\n"
+"     You can also cherry-pick several revisions and/or revision ranges:\n"
+"\n"
+"         svn merge -c50,54,60 -r65:68 ^/trunk\n"
+"\n"
+"\n"
+"  3. This form is called a 'reintegrate merge':\n"
+"\n"
+"       svn merge --reintegrate SOURCE[@REV] [TARGET_WCPATH]\n"
+"\n"
+"     In a reintegrate merge, an (e.g. feature) branch is merged back to its\n"
+"     originating branch. In other words, the source branch has originally\n"
+"     been created by copying the target branch, development has concluded\n"
+"     on the source branch and it should now be merged back into the target\n"
+"     branch.\n"
+"     \n"
+"     SOURCE is the URL of a branch to be merged back. If REV is specified,\n"
+"     it is used as the peg revision for SOURCE; if REV is not specified,\n"
+"     the HEAD revision is assumed.\n"
+"\n"
+"     TARGET_WCPATH is a working copy of the branch the changes will be\n"
+"     applied to.\n"
+"\n"
+"       - Reintegrate Merge Example -\n"
+"\n"
+"     A feature has been developed on a branch called 'feature'. The feature\n"
+"     branch started as a copy of trunk@W. Work on the feature has completed\n"
+"     and it should be merged back into the trunk.\n"
+"\n"
+"     The feature branch was last synced with trunk up to revision X. So the\n"
+"     difference between trunk@X and feature@HEAD contains the complete set\n"
+"     of changes that implement the feature, and no other changes. These\n"
+"     changes are applied to trunk.\n"
+"\n"
+"                feature  +--------------------------------R\n"
+"                        /                                . \\\n"
+"                       /                    .............   \\\n"
+"                      /                    .                 v\n"
+"         trunk ------+--------------------L------------------o\n"
+"                    rW                   rX\n"
+"\n"
+"     In the diagram above, L marks the left side (trunk@X) and R marks the\n"
+"     right side (feature@HEAD) of the merge. The difference between the\n"
+"     left and right side is merged into trunk, the target.\n"
+"\n"
+"     To perform the merge, have a clean working copy of trunk and run the\n"
+"     following command in its top-level directory:\n"
+"\n"
+"         svn merge --reintegrate ^/feature\n"
+"\n"
+"     To prevent unnecessary merge conflicts, a reintegrate merge requires\n"
+"     that TARGET_WCPATH is not a mixed-revision working copy, has no local\n"
+"     modifications, and has no switched subtrees.\n"
+"\n"
+"     A reintegrate merge also requires that the source branch is coherently\n"
+"     synced with the target -- in the above example, this means that all\n"
+"     revisions between the branch point W and the last merged revision X\n"
+"     are merged to the feature branch, so that there are no unmerged\n"
+"     revisions in-between.\n"
+"\n"
+"     After the reintegrate merge, the feature branch cannot be synced to\n"
+"     the trunk again without merge conflicts. If further work must be done\n"
+"     on the feature branch, it should be deleted and then re-created.\n"
+"\n"
+"\n"
+"  4. This form is called a '2-URL merge':\n"
+"\n"
+"       svn merge SOURCE1[@N] SOURCE2[@M] [TARGET_WCPATH]\n"
+"\n"
+"     Two source URLs are specified, together with two revisions N and M.\n"
+"     The two sources are compared at the specified revisions, and the\n"
+"     difference is applied to TARGET_WCPATH, which is a path to a working\n"
+"     copy of another branch. The three branches involved can be completely\n"
+"     unrelated.\n"
+"\n"
+"     You should use this merge variant only if the other variants do not\n"
+"     apply to your situation, as this variant can be quite complex to\n"
+"     master.\n"
+"\n"
+"     If TARGET_WCPATH is omitted, a default value of '.' is assumed.\n"
+"     However, in the special case where both sources refer to a file node\n"
+"     with the same basename and a similarly named file is also found within\n"
+"     '.', the differences will be applied to that local file.  The source\n"
+"     revisions default to HEAD if omitted.\n"
+"\n"
+"     The sources can also be specified as working copy paths, in which case\n"
+"     the URLs of the merge sources are derived from the working copies.\n"
+"\n"
+"       - 2-URL Merge Example -\n"
+"\n"
+"     Two features have been developed on separate branches called 'foo' and\n"
+"     'bar'. It has since become clear that 'bar' should be combined with\n"
+"     the 'foo' branch for further development before reintegration.\n"
+"\n"
+"     Although both feature branches originate from trunk, they are not\n"
+"     directly related -- one is not a direct copy of the other. A 2-URL\n"
+"     merge is necessary.\n"
+"\n"
+"     The 'bar' branch has been synced with trunk up to revision 500.\n"
+"     (If this revision number is not known, it can be located using the\n"
+"     'svn log' and/or 'svn mergeinfo' commands.)\n"
+"     The difference between trunk@500 and bar@HEAD contains the complete\n"
+"     set of changes related to feature 'bar', and no other changes. These\n"
+"     changes are applied to the 'foo' branch.\n"
+"\n"
+"                           foo  +-----------------------------------o\n"
+"                               /                                    ^\n"
+"                              /                                    /\n"
+"                             /              r500                  /\n"
+"         trunk ------+------+-----------------L--------->        /\n"
+"                      \\                        .                /\n"
+"                       \\                        ............   /\n"
+"                        \\                                   . /\n"
+"                    bar  +-----------------------------------R\n"
+"\n"
+"     In the diagram above, L marks the left side (trunk@500) and R marks\n"
+"     the right side (bar@HEAD) of the merge. The difference between the\n"
+"     left and right side is applied to the target working copy path, in\n"
+"     this case a working copy of the 'foo' branch.\n"
+"\n"
+"     To perform the merge, have a clean working copy of the 'foo' branch\n"
+"     and run the following command in its top-level directory:\n"
+"\n"
+"         svn merge ^/trunk@500 ^/bar\n"
+"\n"
+"     The exact changes applied by a 2-URL merge can be previewed with svn's\n"
+"     diff command, which is a good idea to verify if you do not have the\n"
+"     luxury of a clean working copy to merge to. In this case:\n"
+"\n"
+"         svn diff ^/trunk@500 ^/bar@HEAD\n"
+"\n"
+"\n"
+"  The following applies to all types of merges:\n"
+"\n"
+"  To prevent unnecessary merge conflicts, svn merge requires that\n"
+"  TARGET_WCPATH is not a mixed-revision working copy. Running 'svn update'\n"
+"  before starting a merge ensures that all items in the working copy are\n"
+"  based on the same revision.\n"
+"\n"
+"  If possible, you should have no local modifications in the merge's target\n"
+"  working copy prior to the merge, to keep things simpler. It will be\n"
+"  easier to revert the merge and to understand the branch's history.\n"
+"\n"
+"  Switched sub-paths should also be avoided during merging, as they may\n"
+"  cause incomplete merges and create subtree mergeinfo.\n"
+"\n"
+"  For each merged item a line will be printed with characters reporting the\n"
+"  action taken. These characters have the following meaning:\n"
+"\n"
+"    A  Added\n"
+"    D  Deleted\n"
+"    U  Updated\n"
+"    C  Conflict\n"
+"    G  Merged\n"
+"    E  Existed\n"
+"    R  Replaced\n"
+"\n"
+"  Characters in the first column report about the item itself.\n"
+"  Characters in the second column report about properties of the item.\n"
+"  A 'C' in the third column indicates a tree conflict, while a 'C' in\n"
+"  the first and second columns indicate textual conflicts in files\n"
+"  and in property values, respectively.\n"
+"\n"
+"    - Merge Tracking -\n"
+"\n"
+"  Subversion uses the svn:mergeinfo property to track merge history. This\n"
+"  property is considered at the start of a merge to determine what to merge\n"
+"  and it is updated at the conclusion of the merge to describe the merge\n"
+"  that took place. Mergeinfo is used only if the two sources are on the\n"
+"  same line of history -- if the first source is an ancestor of the second,\n"
+"  or vice-versa (i.e. if one has originally been created by copying the\n"
+"  other). This is verified and enforced when using sync merges and\n"
+"  reintegrate merges.\n"
+"\n"
+"  The --ignore-ancestry option prevents merge tracking and thus ignores\n"
+"  mergeinfo, neither considering it nor recording it.\n"
+"\n"
+"    - Merging from foreign repositories -\n"
+"\n"
+"  Subversion does support merging from foreign repositories.\n"
+"  While all merge source URLs must point to the same repository, the merge\n"
+"  target working copy may come from a different repository than the source.\n"
+"  However, there are some caveats. Most notably, copies made in the\n"
+"  merge source will be transformed into plain additions in the merge\n"
+"  target. Also, merge-tracking is not supported for merges from foreign\n"
+"  repositories.\n"),
     {'r', 'c', 'N', opt_depth, 'q', opt_force, opt_dry_run, opt_merge_cmd,
      opt_record_only, 'x', opt_ignore_ancestry, opt_accept, opt_reintegrate,
      opt_allow_mixed_revisions} },
@@ -1008,8 +1089,8 @@ const svn_opt_subcommand_desc2_t svn_cl_
      "\n"
      "  Hint: If the patch file was created with Subversion, it will contain\n"
      "        the number of a revision N the patch will cleanly apply to\n"
-     "        (look for lines like \"--- foo/bar.txt        (revision N)\").\n"
-     "        To avoid rejects, first update to the revision N using \n"
+     "        (look for lines like '--- foo/bar.txt        (revision N)').\n"
+     "        To avoid rejects, first update to the revision N using\n"
      "        'svn update -r N', apply the patch, and then update back to the\n"
      "        HEAD revision. This way, conflicts can be resolved interactively.\n"
      ),
@@ -1462,6 +1543,7 @@ main(int argc, const char *argv[])
   svn_config_t *cfg_config;
   svn_boolean_t descend = TRUE;
   svn_boolean_t interactive_conflicts = FALSE;
+  svn_boolean_t use_notifier = TRUE;
   apr_hash_t *changelists;
 
   /* Initialize the app. */
@@ -1590,7 +1672,6 @@ main(int argc, const char *argv[])
             {
               char *end;
               svn_revnum_t changeno, changeno_end;
-              svn_opt_revision_range_t *range;
               const char *change_str =
                 APR_ARRAY_IDX(change_revs, i, const char *);
               const char *s = change_str;
@@ -1662,15 +1743,11 @@ main(int argc, const char *argv[])
                   changeno_end = changeno - 1;
                 }
 
-              range = apr_palloc(pool, sizeof(*range));
-              range->start.value.number = changeno;
-              range->end.value.number = changeno_end;
-
               opt_state.used_change_arg = TRUE;
-              range->start.kind = svn_opt_revision_number;
-              range->end.kind = svn_opt_revision_number;
               APR_ARRAY_PUSH(opt_state.revision_ranges,
-                             svn_opt_revision_range_t *) = range;
+                             svn_opt_revision_range_t *)
+                = svn_opt__revision_range_from_revnums(changeno, changeno_end,
+                                                       pool);
             }
         }
         break;
@@ -2017,6 +2094,9 @@ main(int argc, const char *argv[])
       case opt_allow_mixed_revisions:
         opt_state.allow_mixed_rev = TRUE;
         break;
+      case opt_include_externals:
+        opt_state.include_externals = TRUE;
+        break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */
@@ -2481,12 +2561,21 @@ main(int argc, const char *argv[])
      subcommands will populate the ctx->log_msg_baton3. */
   ctx->log_msg_func3 = svn_cl__get_log_message;
 
-  /* Set up the notifier. */
-  if (((subcommand->cmd_func != svn_cl__status) && !opt_state.quiet)
-        || ((subcommand->cmd_func == svn_cl__status) && !opt_state.xml))
+  /* Set up the notifier.
+
+     In general, we use it any time we aren't in --quiet mode.  'svn
+     status' is unique, though, in that we don't want it in --quiet mode
+     unless we're also in --verbose mode.  When in --xml mode,
+     though, we never want it.  */
+  if (opt_state.quiet)
+    use_notifier = FALSE;
+  if ((subcommand->cmd_func == svn_cl__status) && opt_state.verbose)
+    use_notifier = TRUE;
+  if (opt_state.xml)
+    use_notifier = FALSE;
+  if (use_notifier)
     {
-      err = svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2,
-                                 FALSE, pool);
+      err = svn_cl__get_notifier(&ctx->notify_func2, &ctx->notify_baton2, pool);
       if (err)
         return svn_cmdline_handle_exit_error(err, pool, "svn: ");
     }
@@ -2601,6 +2690,15 @@ main(int argc, const char *argv[])
                                      _("Please see the 'svn upgrade' command"));
         }
 
+      /* Tell the user about 'svn cleanup' if any error on the stack
+         was about locked working copies. */
+      if (svn_error_find_cause(err, SVN_ERR_WC_LOCKED))
+        {
+          err = svn_error_quick_wrap(
+                  err, _("Run 'svn cleanup' to remove locks "
+                         "(type 'svn help cleanup' for details)"));
+        }
+
       /* Issue #3014:
        * Don't print anything on broken pipes. The pipe was likely
        * closed by the process at the other end. We expect that
@@ -2611,14 +2709,6 @@ main(int argc, const char *argv[])
       if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
         svn_handle_error2(err, stderr, FALSE, "svn: ");
 
-      /* Tell the user about 'svn cleanup' if any error on the stack
-         was about locked working copies. */
-      if (svn_error_find_cause(err, SVN_ERR_WC_LOCKED))
-        svn_error_clear(svn_cmdline_fputs(_("svn: run 'svn cleanup' to "
-                                            "remove locks (type 'svn help "
-                                            "cleanup' for details)\n"),
-                                          stderr, pool));
-
       svn_error_clear(err);
       svn_pool_destroy(pool);
       return EXIT_FAILURE;

Modified: subversion/branches/fs-py/subversion/svn/merge-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/merge-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/merge-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/merge-cmd.c Mon Dec 19 18:49:34 2011
@@ -39,6 +39,63 @@
 
 /*** Code. ***/
 
+/* Do a reintegrate merge from SOURCE_PATH_OR_URL@SOURCE_PEG_REVISION into
+ * TARGET_WCPATH.  Do it with a WC write lock unless DRY_RUN is true. */
+static svn_error_t *
+merge_reintegrate(const char *source_path_or_url,
+                  const svn_opt_revision_t *source_peg_revision,
+                  const char *target_wcpath,
+                  svn_boolean_t dry_run,
+                  const apr_array_header_t *merge_options,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  const char *url1, *url2;
+  svn_revnum_t rev1, rev2;
+
+  SVN_ERR(svn_client_find_reintegrate_merge(
+            &url1, &rev1, &url2, &rev2,
+            source_path_or_url, source_peg_revision, target_wcpath,
+            ctx, scratch_pool, scratch_pool));
+
+  if (url1)
+    {
+      svn_opt_revision_t revision1 = { svn_opt_revision_number, { rev1 } };
+      svn_opt_revision_t revision2 = { svn_opt_revision_number, { rev2 } };
+
+      /* Do the merge.  Set 'allow_mixed_rev' to true, not because we want
+       * to allow a mixed-rev WC but simply to bypass the check, as it was
+       * already checked in svn_client_find_reintegrate_merge(). */
+      SVN_ERR(svn_client_merge4(url1, &revision1, url2, &revision2,
+                                target_wcpath, svn_depth_infinity,
+                                FALSE /* ignore_ancestry */,
+                                FALSE /* force */,
+                                FALSE /* record_only */,
+                                dry_run, TRUE /* allow_mixed_rev */,
+                                merge_options, ctx, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Throw an error if PATH_OR_URL is a path and REVISION isn't a repository
+ * revision. */
+static svn_error_t *
+ensure_wc_path_has_repo_revision(const char *path_or_url,
+                                 const svn_opt_revision_t *revision,
+                                 apr_pool_t *scratch_pool)
+{
+  if (revision->kind != svn_opt_revision_number
+      && revision->kind != svn_opt_revision_date
+      && revision->kind != svn_opt_revision_head
+      && ! svn_path_is_url(path_or_url))
+    return svn_error_createf(
+      SVN_ERR_CLIENT_BAD_REVISION, NULL,
+      _("Invalid merge source '%s'; a working copy path can only be "
+        "used with a repository revision (a number, a date, or head)"),
+      svn_dirent_local_style(path_or_url, scratch_pool));
+  return SVN_NO_ERROR;
+}
 
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -55,6 +112,7 @@ svn_cl__merge(apr_getopt_t *os,
   svn_opt_revision_t first_range_start, first_range_end, peg_revision1,
     peg_revision2;
   apr_array_header_t *options, *ranges_to_merge = opt_state->revision_ranges;
+  svn_opt_revision_t unspecified = { svn_opt_revision_unspecified, { 0 } };
 
   /* Merge doesn't support specifying a revision or revision range
      when using --reintegrate. */
@@ -175,28 +233,21 @@ svn_cl__merge(apr_getopt_t *os,
                                 _("Too many arguments given"));
 
       /* Set the default value for unspecified paths and peg revision. */
-      if (targets->nelts == 0)
-        {
-          peg_revision1.kind = svn_opt_revision_head;
-        }
-      else
-        {
-          /* targets->nelts is 1 ("svn merge SOURCE") or 2 ("svn merge
-             SOURCE WCPATH") here. */
-          sourcepath2 = sourcepath1;
-
-          if (peg_revision1.kind == svn_opt_revision_unspecified)
-            peg_revision1.kind = svn_path_is_url(sourcepath1)
-              ? svn_opt_revision_head : svn_opt_revision_working;
+      /* targets->nelts is 1 ("svn merge SOURCE") or 2 ("svn merge
+         SOURCE WCPATH") here. */
+      sourcepath2 = sourcepath1;
+
+      if (peg_revision1.kind == svn_opt_revision_unspecified)
+        peg_revision1.kind = svn_path_is_url(sourcepath1)
+          ? svn_opt_revision_head : svn_opt_revision_working;
 
-          if (targets->nelts == 2)
-            {
-              targetpath = APR_ARRAY_IDX(targets, 1, const char *);
-              if (svn_path_is_url(targetpath))
-                return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                        _("Cannot specify a revision range "
-                                          "with two URLs"));
-            }
+      if (targets->nelts == 2)
+        {
+          targetpath = APR_ARRAY_IDX(targets, 1, const char *);
+          if (svn_path_is_url(targetpath))
+            return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                    _("Cannot specify a revision range "
+                                      "with two URLs"));
         }
     }
   else /* using @rev syntax */
@@ -212,16 +263,13 @@ svn_cl__merge(apr_getopt_t *os,
 
       /* Catch 'svn merge wc_path1 wc_path2 [target]' without explicit
          revisions--since it ignores local modifications it may not do what
-         the user expects.  Forcing the user to specify a repository
+         the user expects.  That is, it doesn't read from the WC itself, it
+         reads from the WC's URL.  Forcing the user to specify a repository
          revision should avoid any confusion. */
-      if ((first_range_start.kind == svn_opt_revision_unspecified
-           && ! svn_path_is_url(sourcepath1))
-          ||
-          (first_range_end.kind == svn_opt_revision_unspecified
-           && ! svn_path_is_url(sourcepath2)))
-        return svn_error_create
-          (SVN_ERR_CLIENT_BAD_REVISION, 0,
-           _("A working copy merge source needs an explicit revision"));
+      SVN_ERR(ensure_wc_path_has_repo_revision(sourcepath1, &first_range_start,
+                                               pool));
+      SVN_ERR(ensure_wc_path_has_repo_revision(sourcepath2, &first_range_end,
+                                               pool));
 
       /* Default peg revisions to each URL's youngest revision. */
       if (first_range_start.kind == svn_opt_revision_unspecified)
@@ -261,11 +309,11 @@ svn_cl__merge(apr_getopt_t *os,
       else if (strcmp(sourcepath1, sourcepath2) == 0)
         {
           svn_node_kind_t kind;
-          const char *decoded_path = svn_path_uri_decode(sourcepath1, pool);
-          SVN_ERR(svn_io_check_path(decoded_path, &kind, pool));
+
+          SVN_ERR(svn_io_check_path(sourcepath1, &kind, pool));
           if (kind == svn_node_file)
             {
-              targetpath = decoded_path;
+              targetpath = sourcepath1;
             }
         }
     }
@@ -298,12 +346,18 @@ svn_cl__merge(apr_getopt_t *os,
                                   "with --reintegrate"));
     }
 
-  if (! two_sources_specified) /* TODO: Switch order of if */
+  if (opt_state->reintegrate)
     {
-      /* If we don't have a source, use the target as the source. */
-      if (! sourcepath1)
-        sourcepath1 = targetpath;
+      SVN_ERR_W(svn_cl__check_related_source_and_target(
+                  sourcepath1, &peg_revision1, targetpath, &unspecified,
+                  ctx, pool),
+                _("Source and target must be different but related branches"));
 
+      err = merge_reintegrate(sourcepath1, &peg_revision1, targetpath,
+                              opt_state->dry_run, options, ctx, pool);
+    }
+  else if (! two_sources_specified)
+    {
       /* If we don't have at least one valid revision range, pick a
          good one that spans the entire set of revisions on our
          source. */
@@ -316,28 +370,27 @@ svn_cl__merge(apr_getopt_t *os,
           range->start.value.number = 1;
           range->end = peg_revision1;
           APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *) = range;
+
+          /* This must be a 'sync' merge so check branch relationship. */
+          SVN_ERR_W(svn_cl__check_related_source_and_target(
+                      sourcepath1, &peg_revision1, targetpath, &unspecified,
+                      ctx, pool),
+                _("Source and target must be different but related branches"));
         }
 
-      if (opt_state->reintegrate)
-        err = svn_client_merge_reintegrate(sourcepath1,
-                                           &peg_revision1,
-                                           targetpath,
-                                           opt_state->dry_run,
-                                           options, ctx, pool);
-      else
-        err = svn_client_merge_peg4(sourcepath1,
-                                    ranges_to_merge,
-                                    &peg_revision1,
-                                    targetpath,
-                                    opt_state->depth,
-                                    opt_state->ignore_ancestry,
-                                    opt_state->force,
-                                    opt_state->record_only,
-                                    opt_state->dry_run,
-                                    opt_state->allow_mixed_rev,
-                                    options,
-                                    ctx,
-                                    pool);
+      err = svn_client_merge_peg4(sourcepath1,
+                                  ranges_to_merge,
+                                  &peg_revision1,
+                                  targetpath,
+                                  opt_state->depth,
+                                  opt_state->ignore_ancestry,
+                                  opt_state->force,
+                                  opt_state->record_only,
+                                  opt_state->dry_run,
+                                  opt_state->allow_mixed_rev,
+                                  options,
+                                  ctx,
+                                  pool);
     }
   else
     {

Modified: subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c (original)
+++ subversion/branches/fs-py/subversion/svn/mergeinfo-cmd.c Mon Dec 19 18:49:34 2011
@@ -67,8 +67,8 @@ svn_cl__mergeinfo(apr_getopt_t *os,
   const char *source, *target;
   svn_opt_revision_t src_peg_revision, tgt_peg_revision;
   /* Default to depth empty. */
-  svn_depth_t depth = opt_state->depth == svn_depth_unknown
-    ? svn_depth_empty : opt_state->depth;
+  svn_depth_t depth = (opt_state->depth == svn_depth_unknown)
+                      ? svn_depth_empty : opt_state->depth;
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
                                                       opt_state->targets,
@@ -114,6 +114,11 @@ svn_cl__mergeinfo(apr_getopt_t *os,
         tgt_peg_revision.kind = svn_opt_revision_base;
     }
 
+  SVN_ERR_W(svn_cl__check_related_source_and_target(source, &src_peg_revision,
+                                                    target, &tgt_peg_revision,
+                                                    ctx, pool),
+            _("Source and target must be different but related branches"));
+
   /* Do the real work, depending on the requested data flavor. */
   if (opt_state->show_revs == svn_cl__show_revs_merged)
     {