Split up the reintegrate merge API so that the caller can find out the
equivalent two-URL merge before performing it.  Use this in 'svn' to tell
the user what the equivalent two-URL merge command would be (or that there
is nothing to merge).

* subversion/include/svn_client.h
  (svn_client_merge_two_url,
   svn_client_find_reintegrate_merge): New functions.

* subversion/libsvn_client/merge.c
  (find_reintegrate_merge): New function, extracted ...
  (merge_reintegrate_locked): ... from here.
  (svn_client_merge_two_url,
   svn_client_find_reintegrate_merge): New wrapper functions.

* subversion/svn/merge-cmd.c
  (merge_reintegrate): New function, implementing the reintegrate merge in
   terms of the new libsvn_client API functions.
  (svn_cl__merge): Call merge_reintegrate() instead of
    svn_client_merge_reintegrate().
--This line, and those below, will be ignored--

Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h	(revision 1213025)
+++ subversion/include/svn_client.h	(working copy)
@@ -3435,6 +3435,37 @@ svn_client_merge(const char *source1,
                  apr_pool_t *pool);
 
 
+/**
+ * Determine the URLs and revisions needed to perform a reintegrate merge
+ * from @a source_path_or_url at @a source_peg_revision into the working
+ * copy at @a target_abspath.
+ *
+ * Set @a *url1_p, @a *rev1_p, @a *url2_p and @a *rev2_p to the target and
+ * source URLs and revisions.
+ *
+ * If no merge should be performed, set @a *url1_p to NULL and @a *rev1_p
+ * to #SVN_INVALID_REVNUM.
+ *
+ * The authentication baton cached in @a ctx is used to communicate with the
+ * repository.
+ *
+ * Allocate all the results in @a result_pool.  Use @a scratch_pool for
+ * temporary allocations.
+ *
+ * @since New in 1.8.
+ */
+svn_error_t *
+svn_client_find_reintegrate_merge(const char **url1_p,
+                                  svn_revnum_t *rev1_p,
+                                  const char **url2_p,
+                                  svn_revnum_t *rev2_p,
+                                  /* inputs */
+                                  const char *source_path_or_url,
+                                  const svn_opt_revision_t *source_peg_revision,
+                                  const char *target_abspath,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool);
 
 /**
  * Perform a reintegration merge of @a source_path_or_url at @a source_peg_revision
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1213025)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -10449,14 +10449,15 @@ calculate_left_hand_side(const char **ur
   return SVN_NO_ERROR;
 }
 
+/* The body of svn_client_find_reintegrate_merge(), which see for details. */
 static svn_error_t *
-merge_reintegrate_locked(const char *source_path_or_url,
-                         const svn_opt_revision_t *source_peg_revision,
-                         const char *target_abspath,
-                         svn_boolean_t dry_run,
-                         const apr_array_header_t *merge_options,
-                         svn_client_ctx_t *ctx,
-                         apr_pool_t *scratch_pool)
+find_reintegrate_merge(merge_source_t **source_p,
+                       const char *source_path_or_url,
+                       const svn_opt_revision_t *source_peg_revision,
+                       const char *target_abspath,
+                       svn_client_ctx_t *ctx,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
   url_uuid_t wc_repos_root, source_repos_root;
   svn_ra_session_t *target_ra_session;
@@ -10467,7 +10468,6 @@ merge_reintegrate_locked(const char *sou
   merge_source_t source;
   svn_mergeinfo_t unmerged_to_source_mergeinfo_catalog;
   svn_mergeinfo_t merged_to_source_mergeinfo_catalog;
-  svn_boolean_t use_sleep = FALSE;
   svn_error_t *err;
   apr_hash_t *subtrees_with_mergeinfo;
   const char *target_url;
@@ -10543,7 +10543,7 @@ merge_reintegrate_locked(const char *sou
   SVN_ERR(svn_client__ra_session_from_path(&source_ra_session, &source.rev2, &source.url2,
                                            source.url2, NULL, source_peg_revision,
                                            source_peg_revision,
-                                           ctx, scratch_pool));
+                                           ctx, result_pool));
   SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, target_abspath,
                                scratch_pool, scratch_pool));
   SVN_ERR(svn_client__open_ra_session_internal(&target_ra_session, NULL,
@@ -10564,12 +10564,15 @@ merge_reintegrate_locked(const char *sou
                                    source_ra_session,
                                    target_ra_session,
                                    ctx,
-                                   scratch_pool, scratch_pool));
+                                   result_pool, scratch_pool));
 
   /* Did calculate_left_hand_side() decide that there was no merge to
      be performed here?  */
   if (! source.url1)
-    return SVN_NO_ERROR;
+    {
+      *source_p = NULL;
+      return SVN_NO_ERROR;
+    }
 
   /* If the target was moved after the source was branched from it,
      it is possible that the left URL differs from the target's current
@@ -10628,31 +10631,76 @@ merge_reintegrate_locked(const char *sou
 
   /* Left side: trunk@youngest-trunk-rev-merged-to-branch-at-specified-peg-rev
    * Right side: branch@specified-peg-revision */
+  *source_p = apr_pmemdup(result_pool, &source, sizeof(source));
+  return SVN_NO_ERROR;
+}
 
-  /* Do the real merge! */
-  /* ### TODO(reint): Make sure that one isn't the same line ancestor
-     ### of the other (what's erroneously referred to as "ancestrally
-     ### related" in this source file).  We can merge to trunk without
-     ### implementing this. */
-  err = merge_cousins_and_supplement_mergeinfo(target_abspath,
-                                               target_ra_session,
-                                               source_ra_session,
-                                               &source, yc_ancestor_rev,
-                                               TRUE /* same_repos */,
-                                               svn_depth_infinity,
-                                               FALSE /* ignore_ancestry */,
-                                               FALSE /* force */,
-                                               FALSE /* record_only */,
-                                               dry_run,
-                                               merge_options, &use_sleep,
-                                               ctx, scratch_pool);
+svn_error_t *
+svn_client_find_reintegrate_merge(const char **url1_p,
+                                  svn_revnum_t *rev1_p,
+                                  const char **url2_p,
+                                  svn_revnum_t *rev2_p,
+                                  const char *source_path_or_url,
+                                  const svn_opt_revision_t *source_peg_revision,
+                                  const char *target_abspath,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  merge_source_t *source;
+
+  SVN_ERR(find_reintegrate_merge(&source,
+                                 source_path_or_url, source_peg_revision,
+                                 target_abspath,
+                                 ctx, result_pool, scratch_pool));
+  if (source)
+    {
+      *url1_p = source->url1;
+      *rev1_p = source->rev1;
+      *url2_p = source->url2;
+      *rev2_p = source->rev2;
+    }
+  else
+    {
+      *url1_p = NULL;
+      *rev1_p = SVN_INVALID_REVNUM;
+      *url2_p = NULL;
+      *rev2_p = SVN_INVALID_REVNUM;
+    }
+  return SVN_NO_ERROR;
+}
 
-  if (use_sleep)
-    svn_io_sleep_for_timestamps(target_abspath, scratch_pool);
+/* The body of svn_client_merge_reintegrate(), which see for details. */
+static svn_error_t *
+merge_reintegrate_locked(const char *source_path_or_url,
+                         const svn_opt_revision_t *source_peg_revision,
+                         const char *target_abspath,
+                         svn_boolean_t dry_run,
+                         const apr_array_header_t *merge_options,
+                         svn_client_ctx_t *ctx,
+                         apr_pool_t *scratch_pool)
+{
+  merge_source_t *source;
 
-  if (err)
-    return svn_error_trace(err);
+  SVN_ERR(find_reintegrate_merge(&source,
+                                 source_path_or_url, source_peg_revision,
+                                 target_abspath,
+                                 ctx, scratch_pool, scratch_pool));
 
+  if (source->url1)
+    {
+      svn_opt_revision_t revision1
+        = { svn_opt_revision_number, { source->rev1 } };
+      svn_opt_revision_t revision2
+        = { svn_opt_revision_number, { source->rev2 } };
+
+      SVN_ERR(merge_locked(source->url1, &revision1, source->url2, &revision2,
+                           target_abspath,
+                           svn_depth_infinity, FALSE /* ignore_ancestry */,
+                           FALSE /* force */, FALSE /* record_only */,
+                           dry_run, FALSE /* allow_mixed_rev */,
+                           merge_options, ctx, scratch_pool));
+    }
   return SVN_NO_ERROR;
 }
 
Index: subversion/svn/merge-cmd.c
===================================================================
--- subversion/svn/merge-cmd.c	(revision 1213025)
+++ subversion/svn/merge-cmd.c	(working copy)
@@ -39,6 +39,59 @@
 
 /*** 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,
+                  svn_boolean_t quiet,
+                  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 } };
+
+      if (! quiet)
+        {
+          printf(_("The reintegrate merge will be equivalent to:\n"
+                   "  svn merge %s@%ld %s@%ld %s\n"),
+                 url1, rev1, url2, rev2,
+                 svn_path_local_style(target_wcpath, scratch_pool));
+        }
+
+      SVN_ERR(svn_client_merge4(url1, &revision1, url2, &revision2,
+                                target_wcpath, svn_depth_infinity,
+                                FALSE /* ignore_ancestry */,
+                                FALSE /* force */,
+                                FALSE /* record_only */,
+                                dry_run, FALSE /* allow_mixed_rev */,
+                                merge_options, ctx, scratch_pool));
+    }
+  else
+    {
+      if (! quiet)
+        {
+          printf(_("There is nothing to reintegrate from '%s' into '%s'\n"),
+                 source_path_or_url,
+                 svn_path_local_style(target_wcpath, scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
 
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
@@ -303,11 +356,9 @@ svn_cl__merge(apr_getopt_t *os,
 
   if (opt_state->reintegrate)
     {
-      err = svn_client_merge_reintegrate(sourcepath1,
-                                         &peg_revision1,
-                                         targetpath,
-                                         opt_state->dry_run,
-                                         options, ctx, pool);
+      err = merge_reintegrate(sourcepath1, &peg_revision1, targetpath,
+                              opt_state->dry_run, opt_state->quiet,
+                              options, ctx, pool);
     }
   else if (! two_sources_specified)
     {
