Following on from the fix for issue #4316 "Merge errors out after resolving conflicts" r1459012, in which I made the merge APIs call the conflict resolver callback for all conflicts before returning, I mentioned that we should do the same for update and switch [1]. I'll explain a bit more.
Currently, subversion/svn/update-cmd.c:svn_cl__update() does this: * Call svn_client_update4(...) - with ctx->conflict_func2 set to svn_cl__conflict_func_postpone() which records the conflicted paths but does not resolve them. * Call svn_cl__resolve_postponed_conflicts() - which calls svn_client_resolve() - with ctx->conflict_func2 set to svn_cl__conflict_func_interactive() which does interactive or non-interactive (pre-specified) resolution. There's something wrong with this usage pattern. svn_client_update4() claims to support a conflict resolver callback, and yet 'svn' -- a really simple client application -- doesn't like the way it works, and instead uses the callback just to collect a list of paths and then runs its own conflict resolution loop instead. Why? AFAIK, the two main reasons are: - If the client is going to do interactive resolution, that could take a long time, and so the client prefers to wait until all of the repository-contacting phase of the update is complete, to avoid network timeouts. - When resolving a tree conflict, we can be sure that all the incoming changes have been received, so that if we need to look at more than one path (such as for a tree conflict involving a copy or a move) then we know that the changes have been received for any path we need to look at. Other reasons are consistency (by making update and switch work the same as merge, we can get rid of some support code in 'svn') and making this logic available to all clients (even if GUI clients, for example, may not use this). I now intend to make libsvn_client do the resolving (I mean call the resolver callback) at the end of the update, for each conflicted path. And 'switch', of course. I see this as a development of the idea that resulted in 'svn' doing the two-stage think it is presently doing. With this patch, subversion/svn/update-cmd.c:svn_cl__update() will do this: * Call svn_client_update4(...) - with ctx->conflict_func2 set to svn_cl__conflict_func_interactive() which does interactive or non-interactive (pre-specified) resolution. - which calls the callback after completing the update, before returning. This changes the notifications a bit, as mentioned in the log message (which is in the patch file). I will commit this soon if no objections. - Julian [1] At the end of the dev@ message "Re: [PATCH] Fix issue #4316 - Merge errors out after resolving conflicts" by Julian Foad on 2013-03-20, <http://svn.haxx.se/dev/archive-2013-03/0340.shtml>. -- Certified & Supported Apache Subversion Downloads: http://www.wandisco.com/subversion/download
Make 'update' and 'switch' libsvn_client APIs delay calling the conflict resolver for each conflicted path until the whole update is complete, like r1459012 did for merge. Previously, the APIs called the callback as soon as each conflict is raised, and 'svn' used a work-around. Rationale: - Avoids the possibility of a network timeout if the resolver callback takes a long time, for example when doing interactive resolution. - Means that all changes have been received. This is important when resolving a tree conflict that involves a copy or move, because the resolver (code or human) may need to look at or modify another path. - Makes all subcommands work the same way. Eliminates the code in 'svn' that implements a 'postpone' callback. - Makes this way of working available to all clients. Makes no difference to a client that does not want to use it. This changes the notifications printed by 'svn' in the case of pre-specified resolution (--accept=xxx), in the same way as described in r1459012 for 'merge'. It now prints a notification with status 'C' for each conflicted path, and then later a 'Resolved ...' line for each conflicted path. The Summary of Conflicts now reports both the number of remaining conflicts and the number of resolved conflicts. * subversion/libsvn_client/client.h subversion/libsvn_client/resolved.c (svn_client__resolve_conflicts): New function, moved and renamed from resolve_conflicts() in merge.c, with the list-of-paths parameter changed to a simple hash and the 'resolved' output made optional. * subversion/libsvn_client/merge.c (resolve_conflicts): Move to resolved.c: svn_client__resolve_conflicts(). (do_merge): Track the change of resolve_conflicts(). * subversion/libsvn_client/update.c (record_conflict): New function. (update_internal): Don't use the resolver callback in the client context, but instead use a local one that just remembers the conflicted paths. (svn_client__update_internal): Call the resolver on the conflicted paths before returning. * subversion/libsvn_client/switch.c (record_conflict, switch_internal, svn_client__switch_internal): Same as in update.c. * subversion/svn/cl.h, subversion/svn/conflict-callbacks.c (svn_cl__conflict_func_postpone, svn_cl__get_conflict_func_postpone_baton, get_postponed_conflicted_paths, svn_cl__resolve_postponed_conflicts): Delete. * subversion/svn/svn.c (sub_main): Install the proper conflict handler instead of the 'postpone' handler. * subversion/svn/merge-cmd.c (svn_cl__merge): Don't install the conflict handler here, as we've now done it in 'svn'. * subversion/svn/update-cmd.c (svn_cl__update): Remove a comment that said we were using the 'postpone' handler. Don't resolve conflicts after the operation. * subversion/svn/switch-cmd.c (svn_cl__switch): Same. * subversion/tests/cmdline/update_tests.py (update_output_with_conflicts, update_output_with_conflicts_resolved): Adjust to expect the new placement of the 'Resolved conflicts ...' line and the new form of the summary of conflicts. --This line, and those below, will be ignored-- Index: subversion/libsvn_client/client.h =================================================================== --- subversion/libsvn_client/client.h (revision 1461183) +++ subversion/libsvn_client/client.h (working copy) @@ -1113,6 +1113,17 @@ const svn_opt_revision_t * svn_cl__rev_default_to_peg(const svn_opt_revision_t *revision, const svn_opt_revision_t *peg_revision); +/* Call the conflict resolver callback in CTX for each conflict recorded + * in CONFLICTED_PATHS (const char *abspath keys; ignored values). If + * RESOLVED is not NULL, then set *RESOLVED to true if all of the + * conflicts were resolved, else to false. + */ +svn_error_t * +svn_client__resolve_conflicts(svn_boolean_t *resolved, + apr_hash_t *conflicted_paths, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool); + #ifdef __cplusplus } Index: subversion/libsvn_client/merge.c =================================================================== --- subversion/libsvn_client/merge.c (revision 1461183) +++ subversion/libsvn_client/merge.c (working copy) @@ -9567,50 +9567,6 @@ 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; - - *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_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(). @@ -9907,8 +9863,9 @@ do_merge(apr_hash_t **modified_subtrees, { svn_boolean_t resolved_all; - SVN_ERR(resolve_conflicts(&resolved_all, - &merge_cmd_baton, ctx, iterpool)); + SVN_ERR(svn_client__resolve_conflicts( + &resolved_all, merge_cmd_baton.conflicted_paths, + ctx, iterpool)); if (! resolved_all) break; Index: subversion/libsvn_client/resolved.c =================================================================== --- subversion/libsvn_client/resolved.c (revision 1461183) +++ subversion/libsvn_client/resolved.c (working copy) @@ -33,6 +33,7 @@ #include "svn_error.h" #include "svn_dirent_uri.h" #include "svn_path.h" +#include "svn_pools.h" #include "client.h" #include "private/svn_wc_private.h" @@ -41,6 +42,53 @@ /*** Code. ***/ svn_error_t * +svn_client__resolve_conflicts(svn_boolean_t *resolved, + apr_hash_t *conflicted_paths, + svn_client_ctx_t *ctx, + apr_pool_t *scratch_pool) +{ + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + apr_hash_index_t *hi; + + if (resolved) + *resolved = TRUE; + + for (hi = (conflicted_paths + ? apr_hash_first(scratch_pool, conflicted_paths) : NULL); + hi; hi = apr_hash_next(hi)) + { + const char *local_abspath = svn__apr_hash_index_key(hi); + + 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)); + + if (resolved) + { + svn_boolean_t text_c, prop_c, tree_c; + + 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; +} + +svn_error_t * svn_client_resolve(const char *path, svn_depth_t depth, svn_wc_conflict_choice_t conflict_choice, Index: subversion/libsvn_client/switch.c =================================================================== --- subversion/libsvn_client/switch.c (revision 1461183) +++ subversion/libsvn_client/switch.c (working copy) @@ -56,8 +56,34 @@ */ +/* A conflict callback that simply records the conflicted path in BATON. + + Implements svn_wc_conflict_resolver_func2_t. +*/ +static svn_error_t * +record_conflict(svn_wc_conflict_result_t **result, + const svn_wc_conflict_description2_t *description, + void *baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_hash_t *conflicted_paths = baton; + + svn_hash_sets(conflicted_paths, + apr_pstrdup(apr_hash_pool_get(conflicted_paths), + description->local_abspath), ""); + *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone, + NULL, result_pool); + return SVN_NO_ERROR; +} + +/* ... + + Add the paths of any conflict victims to CONFLICTED_PATHS. +*/ static svn_error_t * switch_internal(svn_revnum_t *result_rev, + apr_hash_t *conflicted_paths, const char *local_abspath, const char *anchor_abspath, const char *switch_url, @@ -292,7 +318,7 @@ switch_internal(svn_revnum_t *result_rev server_supports_depth, diff3_cmd, preserved_exts, svn_client__dirent_fetcher, &dfb, - ctx->conflict_func2, ctx->conflict_baton2, + record_conflict, conflicted_paths, NULL, NULL, ctx->cancel_func, ctx->cancel_baton, ctx->notify_func2, ctx->notify_baton2, @@ -397,6 +423,7 @@ svn_client__switch_internal(svn_revnum_t const char *local_abspath, *anchor_abspath; svn_boolean_t acquired_lock; svn_error_t *err, *err1, *err2; + apr_hash_t *conflicted_paths = apr_hash_make(pool); SVN_ERR_ASSERT(path); @@ -413,13 +440,21 @@ svn_client__switch_internal(svn_revnum_t acquired_lock = (err == SVN_NO_ERROR); svn_error_clear(err); - err1 = switch_internal(result_rev, local_abspath, anchor_abspath, + err1 = switch_internal(result_rev, conflicted_paths, + local_abspath, anchor_abspath, switch_url, peg_revision, revision, depth, depth_is_sticky, ignore_externals, allow_unver_obstructions, ignore_ancestry, timestamp_sleep, ctx, pool); + /* Give the conflict resolver callback the opportunity to + * resolve any conflicts that were raised. */ + if (! err1 && ctx->conflict_func2) + { + err1 = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool); + } + if (acquired_lock) err2 = svn_wc__release_write_lock(ctx->wc_ctx, anchor_abspath, pool); else Index: subversion/libsvn_client/update.c =================================================================== --- subversion/libsvn_client/update.c (revision 1461183) +++ subversion/libsvn_client/update.c (working copy) @@ -161,6 +161,27 @@ is_empty_wc(svn_boolean_t *clean_checkou return svn_io_dir_close(dir); } +/* A conflict callback that simply records the conflicted path in BATON. + + Implements svn_wc_conflict_resolver_func2_t. +*/ +static svn_error_t * +record_conflict(svn_wc_conflict_result_t **result, + const svn_wc_conflict_description2_t *description, + void *baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_hash_t *conflicted_paths = baton; + + svn_hash_sets(conflicted_paths, + apr_pstrdup(apr_hash_pool_get(conflicted_paths), + description->local_abspath), ""); + *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone, + NULL, result_pool); + return SVN_NO_ERROR; +} + /* This is a helper for svn_client__update_internal(), which see for an explanation of most of these parameters. Some stuff that's unique is as follows: @@ -172,9 +193,12 @@ is_empty_wc(svn_boolean_t *clean_checkou If NOTIFY_SUMMARY is set (and there's a notification handler in CTX), transmit the final update summary upon successful completion of the update. + + Add the paths of any conflict victims to CONFLICTED_PATHS. */ static svn_error_t * update_internal(svn_revnum_t *result_rev, + apr_hash_t *conflicted_paths, const char *local_abspath, const char *anchor_abspath, const svn_opt_revision_t *revision, @@ -408,7 +432,7 @@ update_internal(svn_revnum_t *result_rev clean_checkout, diff3_cmd, preserved_exts, svn_client__dirent_fetcher, &dfb, - ctx->conflict_func2, ctx->conflict_baton2, + record_conflict, conflicted_paths, NULL, NULL, ctx->cancel_func, ctx->cancel_baton, ctx->notify_func2, ctx->notify_baton2, @@ -505,6 +529,7 @@ svn_client__update_internal(svn_revnum_t const char *anchor_abspath, *lockroot_abspath; svn_error_t *err; svn_opt_revision_t peg_revision = *revision; + apr_hash_t *conflicted_paths = apr_hash_make(pool); SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); SVN_ERR_ASSERT(! (innerupdate && make_parents)); @@ -545,7 +570,8 @@ svn_client__update_internal(svn_revnum_t { const char *missing_parent = APR_ARRAY_IDX(missing_parents, i, const char *); - err = update_internal(result_rev, missing_parent, anchor_abspath, + err = update_internal(result_rev, conflicted_paths, + missing_parent, anchor_abspath, &peg_revision, svn_depth_empty, FALSE, ignore_externals, allow_unver_obstructions, adds_as_modification, timestamp_sleep, @@ -569,11 +595,20 @@ svn_client__update_internal(svn_revnum_t anchor_abspath = lockroot_abspath; } - err = update_internal(result_rev, local_abspath, anchor_abspath, + err = update_internal(result_rev, conflicted_paths, + local_abspath, anchor_abspath, &peg_revision, depth, depth_is_sticky, ignore_externals, allow_unver_obstructions, adds_as_modification, timestamp_sleep, TRUE, ctx, pool); + + /* Give the conflict resolver callback the opportunity to + * resolve any conflicts that were raised. */ + if (! err && ctx->conflict_func2) + { + err = svn_client__resolve_conflicts(NULL, conflicted_paths, ctx, pool); + } + cleanup: err = svn_error_compose_create( err, Index: subversion/svn/cl.h =================================================================== --- subversion/svn/cl.h (revision 1461183) +++ subversion/svn/cl.h (working copy) @@ -361,44 +361,6 @@ svn_cl__conflict_func_interactive(svn_wc apr_pool_t *result_pool, apr_pool_t *scratch_pool); -/* Create and return a baton for use with svn_cl__conflict_func_postpone() - * and svn_cl__resolve_postponed_conflicts(), allocated in RESULT_POOL. - */ -void * -svn_cl__get_conflict_func_postpone_baton(apr_pool_t *result_pool); - -/* A conflict-resolution callback which postpones all conflicts and - * remembers conflicted paths in BATON. BATON must have been obtained - * from svn_cl__get_conflict_func_postpone_baton(). - * - * Implements svn_wc_conflict_resolver_func2_t. - */ -svn_error_t * -svn_cl__conflict_func_postpone(svn_wc_conflict_result_t **result, - const svn_wc_conflict_description2_t *desc, - void *baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); - -/* Perform conflict resolution on any conflicted paths stored in the BATON - * which was obtained from svn_cl__get_conflict_func_postpone_baton(). - * - * If CONFLICTS_ALL_RESOLVED is not null, set *CONFLICTS_ALL_RESOLVED to - * true if this resolves all the conflicts on the paths that were - * recorded (or if none were recorded); or to false if some conflicts - * remain. - * - * The conflict resolution will be interactive if ACCEPT_WHICH is - * svn_cl__accept_unspecified. - */ -svn_error_t * -svn_cl__resolve_postponed_conflicts(svn_boolean_t *conflicts_all_resolved, - void *baton, - svn_cl__accept_t accept_which, - const char *editor_cmd, - svn_client_ctx_t *ctx, - apr_pool_t *scratch_pool); - /*** Command-line output functions -- printing to the user. ***/ Index: subversion/svn/conflict-callbacks.c =================================================================== --- subversion/svn/conflict-callbacks.c (revision 1461183) +++ subversion/svn/conflict-callbacks.c (working copy) @@ -1152,134 +1152,3 @@ svn_cl__conflict_func_interactive(svn_wc return SVN_NO_ERROR; } - -svn_error_t * -svn_cl__conflict_func_postpone(svn_wc_conflict_result_t **result, - const svn_wc_conflict_description2_t *desc, - void *baton, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_hash_t *conflicted_paths = baton; - - svn_hash_sets(conflicted_paths, - apr_pstrdup(apr_hash_pool_get(conflicted_paths), - desc->local_abspath), - ""); - - *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone, - NULL, result_pool); - return SVN_NO_ERROR; -} - -void * -svn_cl__get_conflict_func_postpone_baton(apr_pool_t *result_pool) -{ - return apr_hash_make(result_pool); -} - -static apr_array_header_t * -get_postponed_conflicted_paths(void *baton, apr_pool_t *result_pool) -{ - apr_hash_t *conflicted_paths = baton; - apr_array_header_t *sorted_array; - apr_array_header_t *result_array; - int i; - - sorted_array = svn_sort__hash(conflicted_paths, - svn_sort_compare_items_as_paths, - apr_hash_pool_get(conflicted_paths)); - result_array = apr_array_make(result_pool, sorted_array->nelts, - sizeof(const char *)); - for (i = 0; i < sorted_array->nelts; i++) - { - svn_sort__item_t item; - - item = APR_ARRAY_IDX(sorted_array, i, svn_sort__item_t); - APR_ARRAY_PUSH(result_array, const char *) = apr_pstrdup(result_pool, - item.key); - } - - return result_array; -} - -svn_error_t * -svn_cl__resolve_postponed_conflicts(svn_boolean_t *conflicts_all_resolved, - void *baton, - svn_cl__accept_t accept_which, - const char *editor_cmd, - svn_client_ctx_t *ctx, - apr_pool_t *scratch_pool) -{ - apr_array_header_t *targets; - int i; - apr_pool_t *iterpool; - - targets = get_postponed_conflicted_paths(baton, scratch_pool); - - if (conflicts_all_resolved != NULL) - *conflicts_all_resolved = TRUE; - - iterpool = svn_pool_create(scratch_pool); - for (i = 0; i < targets->nelts; i++) - { - const char *target = APR_ARRAY_IDX(targets, i, const char *); - svn_error_t *err = SVN_NO_ERROR; - const char *local_abspath; - svn_wc_conflict_resolver_func2_t conflict_func2; - void *conflict_baton2; - svn_cl__interactive_conflict_baton_t *b; - svn_boolean_t text_c, prop_c, tree_c; - - svn_pool_clear(iterpool); - - SVN_ERR(svn_dirent_get_absolute(&local_abspath, target, iterpool)); - - /* Store old state */ - conflict_func2 = ctx->conflict_func2; - conflict_baton2 = ctx->conflict_baton2; - - /* Set up the interactive resolver. */ - ctx->conflict_func2 = svn_cl__conflict_func_interactive; - SVN_ERR(svn_cl__get_conflict_func_interactive_baton(&b, accept_which, - ctx->config, - editor_cmd, - ctx->cancel_func, - ctx->cancel_baton, - scratch_pool)); - ctx->conflict_baton2 = b; - - err = svn_client_resolve(local_abspath, svn_depth_empty, - svn_wc_conflict_choose_unspecified, - ctx, iterpool); - - /* Restore state */ - ctx->conflict_func2 = conflict_func2; - ctx->conflict_baton2 = conflict_baton2; - - if (err) - { - if ((err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) - && (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)) - return svn_error_trace(err); - - svn_error_clear(err); - } - - /* Report if we left any of the conflicts unresolved */ - if (conflicts_all_resolved != NULL) - { - SVN_ERR(svn_wc_conflicted_p3(&text_c, &prop_c, &tree_c, - ctx->wc_ctx, local_abspath, - scratch_pool)); - if (text_c || prop_c || tree_c) - *conflicts_all_resolved = FALSE; - } - - if (b->quit) - break; - } - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} Index: subversion/svn/merge-cmd.c =================================================================== --- subversion/svn/merge-cmd.c (revision 1461183) +++ subversion/svn/merge-cmd.c (working copy) @@ -542,19 +542,6 @@ svn_cl__merge(apr_getopt_t *os, "with --reintegrate")); } - /* 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, sourcepath2, Index: subversion/svn/svn.c =================================================================== --- subversion/svn/svn.c (revision 1461183) +++ subversion/svn/svn.c (working copy) @@ -2781,14 +2781,6 @@ sub_main(int argc, const char *argv[], a ctx->auth_baton = ab; - /* Install the default conflict handler which postpones all conflicts - * and remembers the list of conflicted paths to be resolved later. - * This is overridden only within the 'resolve' subcommand. */ - ctx->conflict_func = NULL; - ctx->conflict_baton = NULL; - ctx->conflict_func2 = svn_cl__conflict_func_postpone; - ctx->conflict_baton2 = svn_cl__get_conflict_func_postpone_baton(pool); - if (opt_state.non_interactive) { if (opt_state.accept_which == svn_cl__accept_edit) @@ -2830,6 +2822,22 @@ sub_main(int argc, const char *argv[], a opt_state.accept_which = svn_cl__accept_postpone; } + /* Install the default conflict handler. */ + { + svn_cl__interactive_conflict_baton_t *b; + + ctx->conflict_func = NULL; + ctx->conflict_baton = NULL; + + ctx->conflict_func2 = svn_cl__conflict_func_interactive; + SVN_INT_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; + } + /* And now we finally run the subcommand. */ err = (*subcommand->cmd_func)(os, &command_baton, pool); if (err) Index: subversion/svn/switch-cmd.c =================================================================== --- subversion/svn/switch-cmd.c (revision 1461183) +++ subversion/svn/switch-cmd.c (working copy) @@ -157,9 +157,6 @@ svn_cl__switch(apr_getopt_t *os, ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper; ctx->notify_baton2 = &nwb; - /* Postpone conflict resolution during the switch operation. - * If any conflicts occur we'll run the conflict resolver later. */ - /* Do the 'switch' update. */ err = svn_client_switch3(NULL, target, switch_url, &peg_revision, &(opt_state->start_revision), depth, @@ -198,11 +195,5 @@ svn_cl__switch(apr_getopt_t *os, return svn_error_compose_create(externals_err, err); } - err = svn_cl__resolve_postponed_conflicts(NULL, - ctx->conflict_baton2, - opt_state->accept_which, - opt_state->editor_cmd, - ctx, scratch_pool); - return svn_error_compose_create(externals_err, err); } Index: subversion/svn/update-cmd.c =================================================================== --- subversion/svn/update-cmd.c (revision 1461183) +++ subversion/svn/update-cmd.c (working copy) @@ -163,9 +163,6 @@ svn_cl__update(apr_getopt_t *os, ctx->notify_func2 = svn_cl__check_externals_failed_notify_wrapper; ctx->notify_baton2 = &nwb; - /* Postpone conflict resolution during the update operation. - * If any conflicts occur we'll run the conflict resolver later. */ - SVN_ERR(svn_client_update4(&result_revs, targets, &(opt_state->start_revision), depth, depth_is_sticky, @@ -195,11 +192,5 @@ svn_cl__update(apr_getopt_t *os, return svn_error_compose_create(externals_err, err); } - err = svn_cl__resolve_postponed_conflicts(NULL, - ctx->conflict_baton2, - opt_state->accept_which, - opt_state->editor_cmd, - ctx, scratch_pool); - return svn_error_compose_create(externals_err, err); } Index: subversion/tests/cmdline/update_tests.py =================================================================== --- subversion/tests/cmdline/update_tests.py (revision 1461183) +++ subversion/tests/cmdline/update_tests.py (working copy) @@ -3694,7 +3694,7 @@ def update_copied_and_deleted_prop(sbox) #---------------------------------------------------------------------- -def update_output_with_conflicts(rev, target, paths=None): +def update_output_with_conflicts(rev, target, paths=None, resolved=False): """Return the expected output for an update of TARGET to revision REV, in which all of the PATHS are updated and conflicting. @@ -3707,19 +3707,19 @@ def update_output_with_conflicts(rev, ta for path in paths: lines += ['C %s\n' % path] lines += ['Updated to revision %d.\n' % rev] - lines += svntest.main.summary_of_conflicts(text_conflicts=len(paths)) + if resolved: + for path in paths: + lines += ["Resolved conflicted state of '%s'\n" % path] + lines += svntest.main.summary_of_conflicts(text_resolved=len(paths)) + else: + lines += svntest.main.summary_of_conflicts(text_conflicts=len(paths)) return lines def update_output_with_conflicts_resolved(rev, target, paths=None): """Like update_output_with_conflicts(), but where all of the conflicts are resolved within the update. """ - if paths is None: - paths = [target] - - lines = update_output_with_conflicts(rev, target, paths) - for path in paths: - lines += ["Resolved conflicted state of '%s'\n" % path] + lines = update_output_with_conflicts(rev, target, paths, resolved=True) return lines #----------------------------------------------------------------------