The attached patch fixes issue #4316 'Merge errors out after resolving 
conflicts'.

I have a particular question about the notifications printed after applying 
this patch -- see the end of this mail.

The patch makes the libsvn_client merge function call the resolver for all 
conflicts raised while merging one revision range, and then continue with the 
merge of the next revision range if all the conflicts were resolved.

In a previous attempt I started to make 'svn' repeat the merge after resolving 
any conflicts, if the merge had bailed out early because of conflicts.  Brane 
suggested that made for a poor merge API if the caller has to be prepared to 
figure out how much of the merging was done and how much more needs to be done 
and to call the merge again itself.  Better for the merge API to do everything 
itself.

Of course the caller still has the possibility of *not* resolving conflicts, 
and in that case the merge is still going to bail out.  But at least we have a 
good solution for the case where the user *does* resolve all the conflicts.


NOTIFICATIONS CHANGED

As I mentioned in my "Conflict resolver callback design" email, doing this does 
mean that the notification receiver will get a 'C' (conflict) notification for 
every conflict even if that conflict is going to be resolved to a 
pre-determined choice.  In terms of the 'svn' client and the 'svn merge' 
command, this means that 'svn merge --accept=[mine-full, etc.]' will, if we 
don't take further action, print something like in this example:

[[[
--- Merging r3 through r4 into 'merge_tests-135/A2/mu':
 C   merge_tests-135/A2/mu
--- Recording mergeinfo for merge of r3 through r4 into 'merge_tests-135/A2/mu':
 G   merge_tests-135/A2/mu
Resolved conflicted state of 'merge_tests-135/A2/mu'
--- Merging r6 through r8 into 'merge_tests-135/A2/mu':
 U   merge_tests-135/A2/mu
--- Merging r10 through r11 into 'merge_tests-135/A2/mu':
 U   merge_tests-135/A2/mu
--- Recording mergeinfo for merge of r5 through r11 into 
'merge_tests-135/A2/mu':
 G   merge_tests-135/A2/mu
Summary of conflicts:
  Property conflicts: 1
]]]

I think if this was changed to print a slightly different summary, something 
like...

[[[
Summary of conflicts:
  Property conflicts: 0 (and 1 already resolved)
]]]

... then it would be fine.  I don't see that the interleaved 'Resolved ...' 
line is a problem.

Do others agree?

If so, I'll make it so.  I would make the logic something like, for each kind 
of conflicts: if (number-remaining > 0 || number-already-resolved > 0) { print 
'Property conflics: <number-remaining>'; if (already-resolved > 0) print ' (and 
<number-already-resolved> already resolved)'; }.

I notice that if 'svn update' or 'switch' is invoked with 
'--accept=[mine-conflict, etc.]' then currently it produces first the 
general update notifications including any 'C' status for conflicts, 
then a 'Summary of conflicts', and after that it proceeds to resolve the 
conflicts and prints 'Resolved ...' for each one.  I think (again as mentioned 
in that other email) it might make sense to move the calling of the resolver 
into the libsvn_client functions.

Thoughts?  Any review of the patch is welcome too.

- Julian



--
Certified & Supported Apache Subversion Downloads: 
http://www.wandisco.com/subversion/download
Fix issue #4316 "Merge errors out after resolving conflicts".  In the
libsvn_client merge functions, if conflicts are raised while merging one of
the revision ranges, then call the conflict resolution callback for all of
those conflicts, and then continue with the rest of the merge if all of
those conflicts were resolved.

Previously the merge functions called the conflict resolution callback
only for text and property conflicts, not for tree conflicts.  It called the
resolver before recording and reporting a (text or prop) conflict, and
avoided recording and reporting the conflict if the resolver resolved it.
Now it always records and reports all conflicts as they occur, and
afterwards calls the resolver which may resolve them.

### merge_tests.py 90 and 103 need to have their output expectations tweaked.

### merge_tests.py 135 has a failure where a revision range differs by one
### revision with a dir merge compared with a single-file merge; not sure why.

* subversion/libsvn_client/merge.c
  (merge_file_changed,
   merge_dir_changed,
   merge_dir_added): If there is a conflict, don't call the resolver, just
    record the conflict.
  (single_range_conflict_report_t,
   single_range_conflict_report_create): New conflict reporting structure,
    containing also the remaining range to be merged.
  (conflict_report_t,
   conflict_report_create,
   conflict_report_dup,
   make_merge_conflict_error): Tweak: store a merge_source_t instead of just
    a revision range.
  (subrange_source): Add an assertion.
  (do_file_merge,
   do_mergeinfo_unaware_dir_merge,
   do_mergeinfo_aware_dir_merge,
   do_directory_merge): Use the new kind of conflict report structure.
  (resolve_conflicts): New function.
  (do_merge): After merging a revision range, do conflict resolution and
    continue with the rest of the merge until it is all done.

* subversion/tests/cmdline/merge_tests.py
  (expected_merge_output2): Tweak.
  (expected_out_and_err): Tweak.
  (conflict_aborted_mergeinfo_described_partial_merge): Update the
    expectations.

* subversion/svn/merge-cmd.c
  (svn_cl__merge): Always install the requested conflict resolver before
    doing the merge, and never run svn_cl__resolve_postponed_conflicts()
    after the merge.
--This line, and those below, will be ignored--

Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1457120)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -2002,9 +2002,14 @@ merge_file_changed(const char *relpath,
                                   left, right,
                                   left_props, prop_changes,
                                   merge_b->dry_run,
-                                  ctx->conflict_func2, ctx->conflict_baton2,
+                                  NULL, NULL,
                                   ctx->cancel_func, ctx->cancel_baton,
                                   scratch_pool));
+      if (property_state == svn_wc_notify_state_conflicted)
+        {
+          alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
+                               merge_b->pool);
+        }
     }
 
   /* Easy out: We are only applying mergeinfo differences. */
@@ -2040,7 +2045,7 @@ merge_file_changed(const char *relpath,
                             merge_b->dry_run, merge_b->diff3_cmd,
                             merge_b->merge_options,
                             left_props, prop_changes,
-                            ctx->conflict_func2, ctx->conflict_baton2,
+                            NULL, NULL,
                             ctx->cancel_func,
                             ctx->cancel_baton,
                             scratch_pool));
@@ -2842,7 +2847,7 @@ merge_dir_changed(const char *relpath,
                                   left, right,
                                   left_props, props,
                                   merge_b->dry_run,
-                                  ctx->conflict_func2, ctx->conflict_baton2,
+                                  NULL, NULL,
                                   ctx->cancel_func, ctx->cancel_baton,
                                   scratch_pool));
 
@@ -2994,11 +2999,15 @@ merge_dir_added(const char *relpath,
                                   svn_prop_hash_to_array(new_props,
                                                          scratch_pool),
                                   merge_b->dry_run,
-                                  merge_b->ctx->conflict_func2,
-                                  merge_b->ctx->conflict_baton2,
+                                  NULL, NULL,
                                   merge_b->ctx->cancel_func,
                                   merge_b->ctx->cancel_baton,
                                   scratch_pool));
+      if (prop_state == svn_wc_notify_state_conflicted)
+        {
+          alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
+                               merge_b->pool);
+        }
     }
 
   return SVN_NO_ERROR;
@@ -5319,6 +5328,38 @@ record_skips_in_mergeinfo(const char *me
 }
 
 /* Data for reporting when a merge aborted because of raising conflicts.
+ */
+typedef struct single_range_conflict_report_t
+{
+  /* What sub-range of the requested source raised conflicts?
+   * The 'inheritable' flag is ignored. */
+  merge_source_t *conflicted_range;
+  /* What sub-range of the requested source remains to be merged?
+   * NULL if no more.  The 'inheritable' flag is ignored. */
+  merge_source_t *remaining_source;
+
+} single_range_conflict_report_t;
+
+/* Create a single_range_conflict_report_t, containing deep copies of
+ * CONFLICTED_RANGE and REMAINING_SOURCE, allocated in RESULT_POOL. */
+static single_range_conflict_report_t *
+single_range_conflict_report_create(const merge_source_t *conflicted_range,
+                                    const merge_source_t *remaining_source,
+                                    apr_pool_t *result_pool)
+{
+  single_range_conflict_report_t *report
+    = apr_palloc(result_pool, sizeof(*report));
+
+  assert(conflicted_range != NULL);
+
+  report->conflicted_range = merge_source_dup(conflicted_range, result_pool);
+  report->remaining_source
+    = remaining_source ? merge_source_dup(remaining_source, result_pool)
+                       : NULL;
+  return report;
+}
+
+/* Data for reporting when a merge aborted because of raising conflicts.
  *
  * ### TODO: More info, including the ranges (or other parameters) the user
  *     needs to complete the merge.
@@ -5327,7 +5368,8 @@ typedef struct conflict_report_t
 {
   const char *target_abspath;
   /* The revision range during which conflicts were raised */
-  svn_merge_range_t *r;
+  const merge_source_t *conflicted_range;
+  /* Was the conflicted range the last range in the whole requested merge? */
   svn_boolean_t was_last_range;
 } conflict_report_t;
 
@@ -5335,14 +5377,14 @@ typedef struct conflict_report_t
  * allocated in RESULT_POOL. */
 static conflict_report_t *
 conflict_report_create(const char *target_abspath,
-                       const svn_merge_range_t *conflicted_range,
+                       const merge_source_t *conflicted_range,
                        svn_boolean_t was_last_range,
                        apr_pool_t *result_pool)
 {
   conflict_report_t *report = apr_palloc(result_pool, sizeof(*report));
 
   report->target_abspath = apr_pstrdup(result_pool, target_abspath);
-  report->r = svn_merge_range_dup(conflicted_range, result_pool);
+  report->conflicted_range = merge_source_dup(conflicted_range, result_pool);
   report->was_last_range = was_last_range;
   return report;
 }
@@ -5355,7 +5397,8 @@ conflict_report_dup(const conflict_repor
   conflict_report_t *new = apr_pmemdup(result_pool, report, sizeof(*new));
 
   new->target_abspath = apr_pstrdup(result_pool, report->target_abspath);
-  new->r = svn_merge_range_dup(report->r, result_pool);
+  new->conflicted_range = merge_source_dup(report->conflicted_range,
+                                           result_pool);
   return new;
 }
 
@@ -5368,13 +5411,17 @@ make_merge_conflict_error(conflict_repor
   assert(!report || svn_dirent_is_absolute(report->target_abspath));
 
   if (report && ! report->was_last_range)
-    return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL,
+    {
+      svn_error_t *err = svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL,
        _("One or more conflicts were produced while merging r%ld:%ld into\n"
          "'%s' --\n"
          "resolve all conflicts and rerun the merge to apply the remaining\n"
          "unmerged revisions"),
-       report->r->start, report->r->end,
+       report->conflicted_range->loc1->rev, report->conflicted_range->loc2->rev,
        svn_dirent_local_style(report->target_abspath, scratch_pool));
+      assert(report->conflicted_range->loc1->rev != report->conflicted_range->loc2->rev); /* ### is a valid case in a 2-URL merge */
+      return err;
+    }
   return SVN_NO_ERROR;
 }
 
@@ -7237,6 +7284,7 @@ subrange_source(const merge_source_t *so
 
   /* For this function we require that the input source is 'ancestral'. */
   SVN_ERR_ASSERT_NO_RETURN(source->ancestral);
+  SVN_ERR_ASSERT_NO_RETURN(start_rev != end_rev);
 
   loc1.rev = start_rev;
   loc2.rev = end_rev;
@@ -7277,7 +7325,7 @@ subrange_source(const merge_source_t *so
 */
 static svn_error_t *
 do_file_merge(svn_mergeinfo_catalog_t result_catalog,
-              svn_merge_range_t **conflicted_range,
+              single_range_conflict_report_t **conflict_report,
               const merge_source_t *source,
               const char *target_abspath,
               const svn_diff_tree_processor_t *processor,
@@ -7301,7 +7349,7 @@ do_file_merge(svn_mergeinfo_catalog_t re
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
 
-  *conflicted_range = NULL;
+  *conflict_report = NULL;
 
   /* Note that this is a single-file merge. */
   range.start = source->loc1->rev;
@@ -7545,7 +7593,16 @@ do_file_merge(svn_mergeinfo_catalog_t re
 
           if (is_path_conflicted_by_merge(merge_b))
             {
-              *conflicted_range = svn_merge_range_dup(r, result_pool);
+              merge_source_t *remaining_range = NULL;
+
+              if (real_source->loc2->rev != source->loc2->rev)
+                remaining_range = subrange_source(source,
+                                                  real_source->loc2->rev,
+                                                  source->loc2->rev,
+                                                  scratch_pool);
+              *conflict_report = single_range_conflict_report_create(
+                                   real_source, remaining_range, result_pool);
+
               /* Only record partial mergeinfo if only a partial merge was
                  performed before a conflict was encountered. */
               range.end = r->end;
@@ -7802,14 +7859,14 @@ subtree_touched_by_merge(const char *loc
    SOURCE, DEPTH, NOTIFY_B, and MERGE_B
    are all cascaded from do_directory_merge's arguments of the same names.
 
-   CONFLICTED_RANGE is as documented for do_directory_merge().
+   CONFLICT_REPORT is as documented for do_directory_merge().
 
    NOTE: This is a very thin wrapper around drive_merge_report_editor() and
    exists only to populate CHILDREN_WITH_MERGEINFO with the single element
    expected during mergeinfo unaware merges.
 */
 static svn_error_t *
-do_mergeinfo_unaware_dir_merge(svn_merge_range_t **conflicted_range,
+do_mergeinfo_unaware_dir_merge(single_range_conflict_report_t **conflict_report,
                                const merge_source_t *source,
                                const char *target_dir_wcpath,
                                apr_array_header_t *children_with_mergeinfo,
@@ -7825,7 +7882,7 @@ do_mergeinfo_unaware_dir_merge(svn_merge
   svn_client__merge_path_t *item
     = svn_client__merge_path_create(target_dir_wcpath, scratch_pool);
 
-  *conflicted_range = NULL;
+  *conflict_report = NULL;
   item->remaining_ranges = svn_rangelist__initialize(source->loc1->rev,
                                                      source->loc2->rev,
                                                      TRUE, scratch_pool);
@@ -7837,11 +7894,8 @@ do_mergeinfo_unaware_dir_merge(svn_merge
                                     merge_b, scratch_pool));
   if (is_path_conflicted_by_merge(merge_b))
     {
-      svn_merge_range_t *r = apr_palloc(result_pool, sizeof(*r));
-      r->start = source->loc1->rev;
-      r->end = source->loc2->rev;
-      r->inheritable = TRUE;
-      *conflicted_range = r;
+      *conflict_report = single_range_conflict_report_create(
+                           source, NULL, result_pool);
     }
   return SVN_NO_ERROR;
 }
@@ -9088,7 +9142,7 @@ remove_noop_subtree_ranges(const merge_s
 
    Handle DEPTH as documented for svn_client_merge5().
 
-   CONFLICTED_RANGE is as documented for do_directory_merge().
+   CONFLICT_REPORT is as documented for do_directory_merge().
 
    Perform any temporary allocations in SCRATCH_POOL.
 
@@ -9099,7 +9153,7 @@ remove_noop_subtree_ranges(const merge_s
 */
 static svn_error_t *
 do_mergeinfo_aware_dir_merge(svn_mergeinfo_catalog_t result_catalog,
-                             svn_merge_range_t **conflicted_range,
+                             single_range_conflict_report_t **conflict_report,
                              const merge_source_t *source,
                              const char *target_abspath,
                              apr_array_header_t *children_with_mergeinfo,
@@ -9131,7 +9185,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
        same repository as the target -- merge tracking might be
        happenin'! ***/
 
-  *conflicted_range = NULL;
+  *conflict_report = NULL;
 
   /* Point our RA_SESSION to the URL of our youngest merge source side. */
   ra_session = is_rollback ? merge_b->ra_session1 : merge_b->ra_session2;
@@ -9320,11 +9374,17 @@ do_mergeinfo_aware_dir_merge(svn_mergein
                  we have merged. */
               if (is_path_conflicted_by_merge(merge_b))
                 {
-                  svn_merge_range_t *r = apr_palloc(result_pool, sizeof(*r));
-                  r->start = start_rev;
-                  r->end = end_rev;
-                  r->inheritable = TRUE;
-                  *conflicted_range = r;
+                  merge_source_t *remaining_range = NULL;
+
+                  if (real_source->loc2->rev != source->loc2->rev)
+                    remaining_range = subrange_source(source,
+                                                      real_source->loc2->rev,
+                                                      source->loc2->rev,
+                                                      scratch_pool);
+                  *conflict_report = single_range_conflict_report_create(
+                                       real_source, remaining_range,
+                                       result_pool);
+
                   range.end = end_rev;
                   break;
                 }
@@ -9412,7 +9472,7 @@ do_mergeinfo_aware_dir_merge(svn_mergein
  */
 static svn_error_t *
 do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
-                   svn_merge_range_t **conflicted_range,
+                   single_range_conflict_report_t **conflict_report,
                    const merge_source_t *source,
                    const char *target_abspath,
                    const svn_diff_tree_processor_t *processor,
@@ -9435,14 +9495,14 @@ do_directory_merge(svn_mergeinfo_catalog
   /* If we are not honoring mergeinfo we can skip right to the
      business of merging changes! */
   if (HONOR_MERGEINFO(merge_b))
-    SVN_ERR(do_mergeinfo_aware_dir_merge(result_catalog, conflicted_range,
+    SVN_ERR(do_mergeinfo_aware_dir_merge(result_catalog, conflict_report,
                                          source, target_abspath,
                                          children_with_mergeinfo,
                                          processor, depth,
                                          squelch_mergeinfo_notifications,
                                          merge_b, result_pool, scratch_pool));
   else
-    SVN_ERR(do_mergeinfo_unaware_dir_merge(conflicted_range,
+    SVN_ERR(do_mergeinfo_unaware_dir_merge(conflict_report,
                                            source, target_abspath,
                                            children_with_mergeinfo,
                                            processor, depth,
@@ -9487,6 +9547,52 @@ ensure_ra_session_url(svn_ra_session_t *
   return SVN_NO_ERROR;
 }
 
+/* Call the conflict resolver callback in CTX for each conflict recorded
+ * in MERGE_B.  Set *RESOLVED to true if all of the conflicts were
+ * resolved, else to false, */
+static svn_error_t *
+resolve_conflicts(svn_boolean_t *resolved,
+                  merge_cmd_baton_t *merge_b,
+                  svn_client_ctx_t *ctx,
+                  apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  apr_hash_index_t *hi;
+
+  SVN_DBG(("resolving any conflicts: %lx", (long)merge_b->conflicted_paths));
+  *resolved = TRUE;
+  for (hi = (merge_b->conflicted_paths
+             ? apr_hash_first(scratch_pool, merge_b->conflicted_paths) : NULL);
+       hi; hi = apr_hash_next(hi))
+    {
+      const char *local_abspath = svn__apr_hash_index_key(hi);
+      svn_boolean_t text_c, prop_c, tree_c;
+
+      SVN_DBG(("resolving conflicts on path '%s'", local_abspath));
+      svn_pool_clear(iterpool);
+      SVN_ERR(svn_wc__resolve_conflicts(ctx->wc_ctx, local_abspath,
+                                        svn_depth_empty,
+                                        TRUE /* resolve_text */,
+                                        "" /* resolve_prop (ALL props) */,
+                                        TRUE /* resolve_tree */,
+                                        svn_wc_conflict_choose_unspecified,
+                                        ctx->conflict_func2,
+                                        ctx->conflict_baton2,
+                                        ctx->cancel_func, ctx->cancel_baton,
+                                        ctx->notify_func2, ctx->notify_baton2,
+                                        iterpool));
+
+      SVN_ERR(svn_wc_conflicted_p3(&text_c, &prop_c, &tree_c,
+                                   ctx->wc_ctx, local_abspath,
+                                   iterpool));
+      if (text_c || prop_c || tree_c)
+        *resolved = FALSE;
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Drive a merge of MERGE_SOURCES into working copy node TARGET
    and possibly record mergeinfo describing the merge -- see
    RECORD_MERGEINFO().
@@ -9708,7 +9814,7 @@ do_merge(apr_hash_t **modified_subtrees,
       svn_node_kind_t src1_kind;
       merge_source_t *source =
         APR_ARRAY_IDX(merge_sources, i, merge_source_t *);
-      svn_merge_range_t *conflicted_range;
+      single_range_conflict_report_t *conflicted_range_report;
 
       svn_pool_clear(iterpool);
 
@@ -9750,24 +9856,53 @@ do_merge(apr_hash_t **modified_subtrees,
       SVN_ERR(svn_ra_check_path(ra_session1, "", source->loc1->rev,
                                 &src1_kind, iterpool));
 
-      /* Call our merge helpers based on SRC1's kind. */
-      if (src1_kind != svn_node_dir)
-        {
-          SVN_ERR(do_file_merge(result_catalog, &conflicted_range,
-                                source, target->abspath,
-                                processor,
-                                sources_related,
-                                squelch_mergeinfo_notifications,
-                                &merge_cmd_baton, iterpool, iterpool));
-        }
-      else /* Directory */
-        {
-          SVN_ERR(do_directory_merge(result_catalog, &conflicted_range,
-                                     source, target->abspath,
-                                     processor,
-                                     depth, squelch_mergeinfo_notifications,
-                                     &merge_cmd_baton, iterpool, iterpool));
+      /* Run the merge; if there are conflicts, allow the callback to
+       * resolve them, and if it resolves all of them, then run the
+       * merge again with the remaining revision range, until it is all
+       * done. */
+      do
+        {
+          /* Merge as far as possible without resolving any conflicts */
+          if (src1_kind != svn_node_dir)
+            {
+              SVN_ERR(do_file_merge(result_catalog, &conflicted_range_report,
+                                    source, target->abspath,
+                                    processor,
+                                    sources_related,
+                                    squelch_mergeinfo_notifications,
+                                    &merge_cmd_baton, iterpool, iterpool));
+            }
+          else /* Directory */
+            {
+              SVN_ERR(do_directory_merge(result_catalog, &conflicted_range_report,
+                                         source, target->abspath,
+                                         processor,
+                                         depth, squelch_mergeinfo_notifications,
+                                         &merge_cmd_baton, iterpool, iterpool));
+            }
+
+          /* Give the conflict resolver callback the opportunity to
+           * resolve any conflicts that were raised.  If it resolves all
+           * of them, go around again to merge the next sub-range (if any). */
+          if (conflicted_range_report && ctx->conflict_func2 && ! dry_run)
+            {
+              svn_boolean_t resolved_all;
+
+              SVN_ERR(resolve_conflicts(&resolved_all,
+                                        &merge_cmd_baton, ctx, iterpool));
+              if (! resolved_all)
+                break;
+
+              merge_cmd_baton.conflicted_paths = NULL;
+              /* Caution: this source is in iterpool */
+              source = conflicted_range_report->remaining_source;
+              conflicted_range_report = NULL;
+            }
+          else
+            break;
         }
+      while (source);
+
       /* The final mergeinfo on TARGET_WCPATH may itself elide. */
       if (! dry_run)
         SVN_ERR(svn_client__elide_mergeinfo(target->abspath, NULL,
@@ -9777,12 +9912,12 @@ do_merge(apr_hash_t **modified_subtrees,
        * range of a multi-pass merge, we raise an error that aborts
        * the merge. The user will be asked to resolve conflicts
        * before merging subsequent revision ranges. */
-      if (conflicted_range)
+      if (conflicted_range_report)
         {
           *conflict_report = conflict_report_create(
-                               target->abspath, conflicted_range,
+                               target->abspath, conflicted_range_report->conflicted_range,
                                (i == merge_sources->nelts - 1
-                                && conflicted_range->end == source->loc2->rev),
+                                && ! conflicted_range_report->remaining_source),
                                result_pool);
           break;
         }
Index: subversion/svn/merge-cmd.c
===================================================================
--- subversion/svn/merge-cmd.c	(revision 1457120)
+++ subversion/svn/merge-cmd.c	(working copy)
@@ -542,29 +542,18 @@ svn_cl__merge(apr_getopt_t *os,
                                   "with --reintegrate"));
     }
 
-  /* Decide how to handle conflicts.  If the user wants interactive
-   * conflict resolution, postpone conflict resolution during the merge
-   * and if any conflicts occur we'll run the conflict resolver later.
-   * Otherwise install the appropriate resolver now. */
-  if (opt_state->accept_which == svn_cl__accept_unspecified
-      || opt_state->accept_which == svn_cl__accept_postpone
-      || opt_state->accept_which == svn_cl__accept_edit
-      || opt_state->accept_which == svn_cl__accept_launch)
-    {
-      /* 'svn.c' has already installed the 'postpone' handler for us. */
-    }
-  else
-    {
-      svn_cl__interactive_conflict_baton_t *b;
-
-      ctx->conflict_func2 = svn_cl__conflict_func_interactive;
-      SVN_ERR(svn_cl__get_conflict_func_interactive_baton(
-                &b,
-                opt_state->accept_which,
-                ctx->config, opt_state->editor_cmd,
-                ctx->cancel_func, ctx->cancel_baton, pool));
-      ctx->conflict_baton2 = b;
-    }
+  /* Install the conflict resolver. */
+  {
+    svn_cl__interactive_conflict_baton_t *b;
+
+    ctx->conflict_func2 = svn_cl__conflict_func_interactive;
+    SVN_ERR(svn_cl__get_conflict_func_interactive_baton(
+              &b,
+              opt_state->accept_which,
+              ctx->config, opt_state->editor_cmd,
+              ctx->cancel_func, ctx->cancel_baton, pool));
+    ctx->conflict_baton2 = b;
+  }
 
   merge_err = run_merge(two_sources_specified,
                         sourcepath1, peg_revision1,
@@ -580,22 +569,12 @@ svn_cl__merge(apr_getopt_t *os,
                _("Merge tracking not possible, use --ignore-ancestry or\n"
                  "fix invalid mergeinfo in target with 'svn propset'"));
     }
-  if (! merge_err || merge_err->apr_err == SVN_ERR_WC_FOUND_CONFLICT)
+
+  if (!opt_state->quiet)
     {
-      svn_error_t *err = SVN_NO_ERROR;
+      svn_error_t *err = svn_cl__notifier_print_conflict_stats(
+                           ctx->notify_baton2, pool);
 
-      if (! opt_state->quiet)
-        err = svn_cl__notifier_print_conflict_stats(ctx->notify_baton2,
-                                                        pool);
-
-      /* Resolve any postponed conflicts.  (Only if we've been using the
-       * default 'postpone' resolver which remembers what was postponed.) */
-      if (!err && ctx->conflict_func2 == svn_cl__conflict_func_postpone)
-        err = svn_cl__resolve_postponed_conflicts(NULL,
-                                                  ctx->conflict_baton2,
-                                                  opt_state->accept_which,
-                                                  opt_state->editor_cmd,
-                                                  ctx, pool);
       merge_err = svn_error_compose_create(merge_err, err);
     }
 
Index: subversion/tests/cmdline/merge_tests.py
===================================================================
--- subversion/tests/cmdline/merge_tests.py	(revision 1457120)
+++ subversion/tests/cmdline/merge_tests.py	(working copy)
@@ -18327,7 +18327,7 @@ def expected_merge_output2(tgt_ospath,
   # Summary of conflicts
   lines += svntest.main.summary_of_conflicts(prop_conflicts=prop_conflicts)
 
-  return RegexListOutput(lines)
+  return RegexListOutput(lines, match_all=False)
 
 def expected_out_and_err(tgt_ospath,
                            recorded_ranges,
@@ -18343,6 +18343,7 @@ def expected_out_and_err(tgt_ospath,
   """
   expected_out = expected_merge_output2(tgt_ospath, recorded_ranges,
                                         merged_ranges, prop_conflicts)
+  expect_error = False;
   if expect_error:
     expected_err = RegexListOutput([
                      '^svn: E155015: .* conflicts were produced .* into$',
@@ -18453,10 +18454,10 @@ def conflict_aborted_mergeinfo_described
     if conflict_rev:
       edit_file_or_dir(tgt_path, conflict_rev, 'Conflict')
 
-    src_url = '^/' + src_path
+    src_url = '^/' + src_path + '@11'
     svntest.actions.run_and_verify_svn(
                       None, expected_out, expected_err,
-                      'merge', src_url, tgt_ospath, '--accept', 'postpone',
+                      'merge', src_url, tgt_ospath, '--accept', 'working',
                       *rev_args)
 
     if expected_mi is not None:
@@ -18492,26 +18493,26 @@ def conflict_aborted_mergeinfo_described
     # but mergeinfo for the whole range was recorded, preventing subsequent
     # repeat merges from applying the rest of the source changes.
     expect = expected_out_and_err(tgt_ospath,
-                                  '3-4', ['3-4'],
+                                  '3-4,5-11', ['3-4', '6-8,10-11'],
                                   prop_conflicts=1)
-    try_merge(target, 4, [], expect, '3-5,9')
+    try_merge(target, 4, [], expect, '3-11')
 
     # Try a multiple-range merge that raises a conflict in the
     # first sub-range in the first specified range;
     expect = expected_out_and_err(tgt_ospath,
-                                  '4', ['4'],
+                                  '4,5-6,8-10', ['4', '6', '8,10'],
                                   prop_conflicts=1)
-    try_merge(target, 4, ['-c4-6,8-10'], expect, '4-5,9')
+    try_merge(target, 4, ['-c4-6,8-10'], expect, '4-6,8-10')
     # last sub-range in the first specified range;
     expect = expected_out_and_err(tgt_ospath,
-                                  '4-6', ['4,6'],
+                                  '4-6,8-10', ['4,6', '8,10'],
                                   prop_conflicts=1)
-    try_merge(target, 6, ['-c4-6,8-10'], expect, '4-6,9')
+    try_merge(target, 6, ['-c4-6,8-10'], expect, '4-6,8-10')
     # first sub-range in the last specified range;
     expect = expected_out_and_err(tgt_ospath,
-                                  '4-6,8', ['4,6', '8'],
+                                  '4-6,8,9-10', ['4,6', '8', '10'],
                                   prop_conflicts=1)
-    try_merge(target, 8, ['-c4-6,8-10'], expect, '4-6,8-9')
+    try_merge(target, 8, ['-c4-6,8-10'], expect, '4-6,8-10')
     # last sub-range in the last specified range.
     # (Expect no error, because 'svn merge' does not throw an error if
     # there is no more merging to do when a conflict occurs.)
@@ -18524,15 +18525,15 @@ def conflict_aborted_mergeinfo_described
     expect = expected_out_and_err(tgt_ospath,
                                   '8', ['8'],
                                   prop_conflicts=1)
-    try_merge(target, 8,  ['-c8-10,4-6'], expect, '5,8-9')
+    try_merge(target, 8,  ['-c8-10,4-6'], expect, '4-6,8-10')
     expect = expected_out_and_err(tgt_ospath,
                                   '8-10', ['8,10'],
                                   prop_conflicts=1)
-    try_merge(target, 10, ['-c8-10,4-6'], expect, '5,8-10')
+    try_merge(target, 10, ['-c8-10,4-6'], expect, '4-6,8-10')
     expect = expected_out_and_err(tgt_ospath,
                                   '8-10,4', ['8,10', '4'],
                                   prop_conflicts=1)
-    try_merge(target, 4,  ['-c8-10,4-6'], expect, '4-5,8-10')
+    try_merge(target, 4,  ['-c8-10,4-6'], expect, '4-6,8-10')
     expect = expected_out_and_err(tgt_ospath,
                                   '8-10,4-6', ['8,10', '4,6'],
                                   prop_conflicts=1, expect_error=False)
@@ -18552,17 +18553,17 @@ def conflict_aborted_mergeinfo_described
                                   expect_error=False)
     try_merge(target, None, ['-r6:3', '-r10:7'], expect, '7')
     expect = expected_out_and_err(tgt_ospath,
-                                  '-6', ['-6'],
+                                  '-6,5-4,10-8', ['-6', '-4', '-10,-8'],
                                   prop_conflicts=1)
-    try_merge(target, 6,  ['-r6:3', '-r10:7'], expect, '4,7-8,10')
+    try_merge(target, 6,  ['-r6:3', '-r10:7'], expect, '7')
     expect = expected_out_and_err(tgt_ospath,
-                                  '6-4', ['-6,-4'],
+                                  '6-4,10-8', ['-6,-4', '-10,-8'],
                                   prop_conflicts=1)
-    try_merge(target, 4,  ['-r6:3', '-r10:7'], expect, '7-8,10')
+    try_merge(target, 4,  ['-r6:3', '-r10:7'], expect, '7')
     expect = expected_out_and_err(tgt_ospath,
-                                  '6-4,-10', ['-6,-4', '-10'],
+                                  '6-4,-10,9-8', ['-6,-4', '-10', '-8'],
                                   prop_conflicts=1)
-    try_merge(target, 10, ['-r6:3', '-r10:7'], expect, '7-8')
+    try_merge(target, 10, ['-r6:3', '-r10:7'], expect, '7')
     expect = expected_out_and_err(tgt_ospath,
                                   '6-4,10-8', ['-6,-4', '-10,-8'],
                                   prop_conflicts=1, expect_error=False)

Reply via email to