A start on making 'svn mergeinfo' print an ASCII-art graph summarizing some
information about the state of merging between the two branches.

* subversion/include/private/svn_client_private.h
  (svn_client__symmetric_merge_t): Add the 'target' location.
  (svn_client__find_symmetric_merge_i): New function to report how a
    symmetric merge would be performed, even if the specified target is a
    repository path rather than a WC.

* subversion/libsvn_client/merge.c
  (svn_client__find_symmetric_merge_i): New function.

* subversion/svn/main.c
  (svn_cl_): Update the help for 'svn mergeinfo'.
  (sub_main): Change the default value of the show-revs option to 'invalid'
    so we can distinguish when the option has not been given.

* subversion/svn/mergeinfo-cmd.c
  (short_loc): New function.
  (mergeinfo_summary): New function.
  (svn_cl__mergeinfo): Call mergeinfo_summary() if no show-revs option was
    given.
--This line, and those below, will be ignored--

Index: subversion/include/private/svn_client_private.h
===================================================================
--- subversion/include/private/svn_client_private.h	(revision 1387221)
+++ subversion/include/private/svn_client_private.h	(working copy)
@@ -182,7 +182,7 @@ svn_client__wc_node_get_origin(svn_clien
 /* Details of a symmetric merge. */
 typedef struct svn_client__symmetric_merge_t
 {
-  svn_client__pathrev_t *yca, *base, *mid, *right;
+  svn_client__pathrev_t *yca, *base, *mid, *right, *target;
   svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees;
 } svn_client__symmetric_merge_t;
 
@@ -205,6 +205,16 @@ svn_client__find_symmetric_merge(svn_cli
                                  svn_client_ctx_t *ctx,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_client__find_symmetric_merge_i(svn_client__symmetric_merge_t **merge_p,
+                                 const char *source_path_or_url,
+                                 const svn_opt_revision_t *source_revision,
+                                 const char *target_path_or_url,
+                                 const svn_opt_revision_t *target_revision,
+                                 svn_client_ctx_t *ctx,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
 
 /* Perform a symmetric merge.
  *
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1387221)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -11546,6 +11546,102 @@ find_symmetric_merge(svn_client__pathrev
 }
 
 svn_error_t *
+svn_client__find_symmetric_merge_i(svn_client__symmetric_merge_t **merge_p,
+                                 const char *source_path_or_url,
+                                 const svn_opt_revision_t *source_revision,
+                                 const char *target_path_or_url,
+                                 const svn_opt_revision_t *target_revision,
+                                 svn_client_ctx_t *ctx,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
+{
+  source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t));
+  svn_client__pathrev_t *target_loc;
+  svn_client__symmetric_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
+  svn_client__pathrev_t *base_on_source, *base_on_target;
+
+  /* Source */
+  SVN_ERR(svn_client__ra_session_from_path2(
+            &s_t->source_ra_session, &s_t->source,
+            source_path_or_url, NULL, source_revision, source_revision,
+            ctx, result_pool));
+
+  /* Target */
+  SVN_ERR(svn_client__ra_session_from_path2(
+            &s_t->target_ra_session, &target_loc,
+            target_path_or_url, NULL, target_revision, target_revision,
+            ctx, result_pool));
+  s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target));
+  s_t->target->loc = *target_loc;
+
+  /* Check source is in same repos as target. */
+  SVN_ERR(check_same_repos(s_t->source, source_path_or_url,
+                           &s_t->target->loc, target_path_or_url,
+                           TRUE /* strict_urls */, scratch_pool));
+
+  /* Fetch mergeinfo of source branch and target branch. */
+  SVN_ERR(svn_client__get_repos_mergeinfo(&s_t->source_mergeinfo,
+                                          s_t->source_ra_session,
+                                          s_t->source->url,
+                                          s_t->source->rev,
+                                          svn_mergeinfo_inherited,
+                                          FALSE /* squelch_incapable */,
+                                          scratch_pool));
+  SVN_ERR(svn_client__get_repos_mergeinfo(&s_t->target_mergeinfo,
+                                          s_t->target_ra_session,
+                                          s_t->target->loc.url,
+                                          s_t->target->loc.rev,
+                                          svn_mergeinfo_inherited,
+                                          FALSE /* squelch_incapable */,
+                                          scratch_pool));
+
+  /* Get the location-history of each branch. */
+  s_t->source_branch.tip = s_t->source;
+  SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &s_t->source_branch.history, &s_t->source_branch.has_r0_history,
+            s_t->source, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+            s_t->source_ra_session, ctx, scratch_pool));
+  s_t->target_branch.tip = &s_t->target->loc;
+  SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &s_t->target_branch.history, &s_t->target_branch.has_r0_history,
+            &s_t->target->loc, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+            s_t->target_ra_session, ctx, scratch_pool));
+
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            &s_t->yca, s_t->source, &s_t->target->loc, s_t->source_ra_session,
+            ctx, result_pool, result_pool));
+
+  /* Choose a base. */
+  SVN_ERR(find_last_merged_location(&base_on_source,
+                                    s_t->yca,
+                                    &s_t->source_branch,
+                                    s_t->target_mergeinfo,
+                                    ctx, result_pool, scratch_pool));
+  SVN_ERR(find_last_merged_location(&base_on_target,
+                                    s_t->yca,
+                                    &s_t->target_branch,
+                                    s_t->source_mergeinfo,
+                                    ctx, result_pool, scratch_pool));
+  if (base_on_source->rev >= base_on_target->rev)
+    {
+      merge->base = base_on_source;
+      merge->mid = NULL;
+    }
+  else
+    {
+      merge->base = base_on_target;
+      merge->mid = base_on_target;  /* ### Wrong! */
+    }
+
+  merge->right = s_t->source;
+  merge->target = &s_t->target->loc;
+  merge->yca = s_t->yca;
+  *merge_p = merge;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_client__find_symmetric_merge(svn_client__symmetric_merge_t **merge_p,
                                  const char *source_path_or_url,
                                  const svn_opt_revision_t *source_revision,
Index: subversion/svn/main.c
===================================================================
--- subversion/svn/main.c	(revision 1387221)
+++ subversion/svn/main.c	(working copy)
@@ -1043,13 +1043,19 @@ const svn_opt_subcommand_desc2_t svn_cl_
 
   { "mergeinfo", svn_cl__mergeinfo, {0}, N_
     ("Display merge-related information.\n"
-     "usage: mergeinfo SOURCE[@REV] [TARGET[@REV]]\n"
-     "\n"
-     "  Display information related to merges (or potential merges) between\n"
-     "  SOURCE and TARGET (default: '.').  Display the type of information\n"
-     "  specified by the --show-revs option.  If --show-revs isn't passed,\n"
-     "  it defaults to --show-revs='merged'.\n"
+     "usage: 1. mergeinfo SOURCE[@REV] [TARGET[@REV]]\n"
+     "       2. mergeinfo --show-revs=merged SOURCE[@REV] [TARGET[@REV]]\n"
+     "       3. mergeinfo --show-revs=eligible SOURCE[@REV] [TARGET[@REV]]\n"
+     "\n"
+     "  1. Display the following information about merges between SOURCE and\n"
+     "     TARGET:\n"
+     "       the youngest common ancestor;\n"
+     "       the latest full merge in either direction, and thus the\n"
+     "         base that will be used for the next full merge.\n"
+     "  2. Print the revision numbers on SOURCE that have been merged to TARGET.\n"
+     "  3. Print the revision numbers on SOURCE that have NOT been merged to TARGET.\n"
      "\n"
+     "  The default TARGET is the current working directory ('.').\n"
      "  If --revision (-r) is provided, filter the displayed information to\n"
      "  show only that which is associated with the revisions within the\n"
      "  specified range.  Revision numbers, dates, and the 'HEAD' keyword are\n"
@@ -1686,7 +1692,7 @@ sub_main(int argc, const char *argv[], a
   opt_state.depth = svn_depth_unknown;
   opt_state.set_depth = svn_depth_unknown;
   opt_state.accept_which = svn_cl__accept_unspecified;
-  opt_state.show_revs = svn_cl__show_revs_merged;
+  opt_state.show_revs = svn_cl__show_revs_invalid;
 
   /* No args?  Show usage. */
   if (argc <= 1)
Index: subversion/svn/mergeinfo-cmd.c
===================================================================
--- subversion/svn/mergeinfo-cmd.c	(revision 1387221)
+++ subversion/svn/mergeinfo-cmd.c	(working copy)
@@ -37,6 +37,7 @@
 #include "cl.h"
 
 #include "svn_private_config.h"
+#include "private/svn_client_private.h"
 
 
 /*** Code. ***/
@@ -55,6 +56,187 @@ print_log_rev(void *baton,
   return SVN_NO_ERROR;
 }
 
+/* Return a short representation of LOC, in the form "^/RELPATH@REV". */
+static const char *
+short_loc(svn_client__pathrev_t *loc,
+          apr_pool_t *result_pool)
+{
+  const char *relpath = svn_client__pathrev_relpath(loc, result_pool);
+
+  return apr_psprintf(result_pool, "^/%s@%ld", relpath, loc->rev);
+}
+
+/* Display an easy-to-read summary of the state of mergeing between the
+ * two branches SOURCE_PATH_OR_URL@SOURCE_REVISION and
+ * TARGET_PATH_OR_URL@TARGET_REVISION. */
+static svn_error_t *
+mergeinfo_summary(
+                  const char *source_path_or_url,
+                  const svn_opt_revision_t *source_revision,
+                  const char *target_path_or_url,
+                  const svn_opt_revision_t *target_revision,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *pool)
+{
+  svn_client__symmetric_merge_t *the_merge;
+#define ROWS 8
+#define COLS 4
+  const char *g[ROWS][COLS] = {{0}};
+  int col_width[COLS];
+  int row, col;
+
+  SVN_ERR(svn_client__find_symmetric_merge_i(
+            &the_merge,
+            source_path_or_url, source_revision,
+            target_path_or_url, target_revision,
+            ctx, pool, pool));
+
+  /*
+  SVN_ERR(svn_cmdline_printf(
+    pool, _("Source branch tip:         %s\n"),
+    short_loc(the_merge->right, pool)));
+  SVN_ERR(svn_cmdline_printf(
+    pool, _("Target branch tip:         %s\n"),
+    short_loc(the_merge->target, pool)));
+  SVN_ERR(svn_cmdline_printf(
+    pool, _("Youngest common ancestor:  %s\n"),
+    short_loc(the_merge->yca, pool)));
+  SVN_ERR(svn_cmdline_printf(
+    pool, _("Base for next merge:       %s\n"),
+    short_loc(the_merge->base, pool)));
+  SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
+  */
+
+#ifdef SVN_DEBUG
+  /* ### debug: make rev nums rather big when testing... */
+  if (the_merge->right->rev < 100)
+    {
+      the_merge->right->rev += 10000000;
+      the_merge->target->rev += 10000000;
+      the_merge->yca->rev += 10000000;
+      if (the_merge->base != the_merge->yca
+          && the_merge->base != the_merge->right
+          && the_merge->base != the_merge->target)
+      the_merge->base->rev += 10000000;
+    }
+#endif
+
+  /* Draw the YCA (that is, the branching point) */
+  g[0][0] = apr_psprintf(pool, "  %-8ld", the_merge->yca->rev);
+  g[1][0] =     "  |       ";
+  if (strcmp(the_merge->yca->url, the_merge->right->url) == 0)
+    {
+      g[2][0] = "----------";
+      g[3][0] = "   \\      ";
+      g[4][0] = "    \\     ";
+      g[5][0] = "     -----";
+    }
+  else if (strcmp(the_merge->yca->url, the_merge->target->url) == 0)
+    {
+      g[2][0] = "     -----";
+      g[3][0] = "    /     ";
+      g[4][0] = "   /      ";
+      g[5][0] = "----------";
+    }
+  else
+    {
+      g[2][0] = "     -----";
+      g[3][0] = "... /     ";
+      g[4][0] = "    \\     ";
+      g[5][0] = "     -----";
+    }
+
+  /* Ellipsis */
+    {
+      g[2][1] = "| ... |---";
+      g[3][1] = "          ";
+      g[4][1] = "          ";
+      g[5][1] = "| ... |---";
+    }
+
+  /* The previous merge */
+  if ((the_merge->base->rev > the_merge->yca->rev) && the_merge->mid)
+    {
+      g[2][2] = "---------";
+      g[3][2] = "  /      ";
+      g[4][2] = " /       ";
+      g[5][2] = "---------";
+      g[6][2] = "|        ";
+      g[7][2] = apr_psprintf(pool, "%-8ld ", the_merge->base->rev);
+    }
+  else if (the_merge->base->rev > the_merge->yca->rev)
+    {
+      g[0][2] = apr_psprintf(pool, "%-8ld ", the_merge->base->rev);
+      g[1][2] = "|        ";
+      g[2][2] = "---------";
+      g[3][2] = " \\       ";
+      g[4][2] = "  \\      ";
+      g[5][2] = "---------";
+    }
+  else
+    {
+      g[2][2] = "---------";
+      g[3][2] = "         ";
+      g[4][2] = "         ";
+      g[5][2] = "---------";
+    }
+
+  /* The tips */
+    {
+      g[0][3] = apr_psprintf(pool, "%-8ld", the_merge->right->rev);
+      g[1][3] = "|       ";
+      g[2][3] = "-       ";
+      g[3][3] = "        ";
+      g[4][3] = "        ";
+      g[5][3] = "-       ";
+      g[6][3] = "|       ";
+      g[7][3] = svn_path_is_url(target_path_or_url)
+                  ? apr_psprintf(pool, "%-8ld", the_merge->target->rev)
+                  : "WC      ";
+    }
+
+  for (col = 0; col < COLS; col++)
+    {
+      col_width[col] = 0;
+      for (row = 0; row < ROWS; row++)
+        {
+          if (g[row][col] && (strlen(g[row][col]) > col_width[col]))
+            col_width[col] = strlen(g[row][col]);
+        }
+    }
+  SVN_ERR(svn_cmdline_fputs(
+            _("    youngest          last               repos.\n"
+              "    common            full     tip of    path of\n"
+              "    ancestor          merge    branch    branch\n"
+              "\n"),
+            stdout, pool));
+  for (row = 0; row < ROWS; row++)
+    {
+      SVN_ERR(svn_cmdline_fputs("  ", stdout, pool));
+      for (col = 0; col < COLS; col++)
+        {
+          if (g[row][col])
+            {
+              SVN_ERR(svn_cmdline_fputs(g[row][col], stdout, pool));
+            }
+          else
+            {
+              /* Print <column-width> spaces */
+              SVN_ERR(svn_cmdline_printf(pool, "%*s", col_width[col], ""));
+            }
+        }
+      if (row == 2)
+        SVN_ERR(svn_cmdline_printf(pool, "  %s",
+                svn_client__pathrev_relpath(the_merge->right, pool)));
+      if (row == 5)
+        SVN_ERR(svn_cmdline_printf(pool, "  %s",
+                svn_client__pathrev_relpath(the_merge->target, pool)));
+      SVN_ERR(svn_cmdline_fputs("\n", stdout, pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__mergeinfo(apr_getopt_t *os,
@@ -140,5 +322,11 @@ svn_cl__mergeinfo(apr_getopt_t *os,
                                         TRUE, depth, NULL, ctx,
                                         pool));
     }
+  else
+    {
+      SVN_ERR(mergeinfo_summary(source, &src_peg_revision,
+                                target, &tgt_peg_revision,
+                                ctx, pool));
+    }
   return SVN_NO_ERROR;
 }
