You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2016/06/10 15:04:06 UTC
svn commit: r1747727 - in /subversion/trunk/subversion:
include/private/svn_wc_private.h include/svn_client.h
libsvn_client/conflicts.c libsvn_wc/conflicts.c libsvn_wc/wc-queries.sql
libsvn_wc/wc_db.c libsvn_wc/wc_db.h svn/conflict-callbacks.c
Author: stsp
Date: Fri Jun 10 15:04:06 2016
New Revision: 1747727
URL: http://svn.apache.org/viewvc?rev=1747727&view=rev
Log:
Add a conflict resolver option which follows an incoming file move.
This new option works for update, switch, and merge operations.
There is no unit test for this option yet.
I have not tested reverse-updates or reverse-merges yet.
We need many many additional tests anyway.
* subversion/include/private/svn_wc_private.h
(svn_wc__guess_incoming_move_target_node): Declare.
* subversion/include/svn_client.h
(svn_client_conflict_option_incoming_move_file_text_merge): New option ID.
* subversion/libsvn_client/conflicts.c
(conflict_tree_incoming_delete_details): Add 'moved_to_abspath'.
(resolve_merge_incoming_added_file_text_merge): Fix typo in comment.
(resolve_incoming_move_file_text_merge): New resolver function.
(configure_option_incoming_move_file_merge): New option config function.
(svn_client_conflict_tree_get_resolution_options): Configure new option.
* subversion/libsvn_wc/conflicts.c
(svn_wc__guess_incoming_move_target_node): Implement. This function
attempts to map a deleted tree conflict victim to a working copy node
which corresponds to the incoming move target.
* subversion/libsvn_wc/wc-queries.sql
(STMT_FIND_REPOS_PATH_IN_WC): New query. Returns all local relpaths at
the 'working' layer (i.e. from nodes_current) which map to a particular
repository path at a particular revision.
* subversion/libsvn_wc/wc_db.c
(svn_wc__find_repos_node_in_wc): New. Runs the above query.
* subversion/libsvn_wc/wc_db.h
(svn_wc__find_repos_node_in_wc): Declare.
* subversion/svn/conflict-callbacks.c
(builtin_resolver_options): Wire up the new option in the conflict menu.
Modified:
subversion/trunk/subversion/include/private/svn_wc_private.h
subversion/trunk/subversion/include/svn_client.h
subversion/trunk/subversion/libsvn_client/conflicts.c
subversion/trunk/subversion/libsvn_wc/conflicts.c
subversion/trunk/subversion/libsvn_wc/wc-queries.sql
subversion/trunk/subversion/libsvn_wc/wc_db.c
subversion/trunk/subversion/libsvn_wc/wc_db.h
subversion/trunk/subversion/svn/conflict-callbacks.c
Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Fri Jun 10 15:04:06 2016
@@ -1890,6 +1890,30 @@ svn_wc__conflict_tree_update_moved_away_
void *notify_baton,
apr_pool_t *scratch_pool);
+/* Find a node in the working copy which corresponds to the new location
+ * MOVED_TO_REPOS_RELPATH@REV of the tree conflict victim at VICTIM_ABSPATH.
+ * If no such node can be found, set *MOVED_TO_ABSPATH to NULL.
+ *
+ * The node should be useful for conflict resolution, e.g. it should be
+ * possible to merge changes into this node to resolve an incoming-move
+ * tree conflict. But the exact criteria for selecting the node are left
+ * to the implementation of this function.
+ * Note that this function may not necessarily return a node which was
+ * actually moved. The only hard guarantee is that the node corresponds to
+ * the repository node MOVED_TO_REPOS_RELPATH@REV specified by the caller.
+ * In many cases, this will be a moved node if the caller's parameters are
+ * correct. But users should be able to override the selection made by
+ * this function.
+ */
+svn_error_t *
+svn_wc__guess_incoming_move_target_node(const char **moved_to_abspath,
+ svn_wc_context_t *wc_ctx,
+ const char *victim_abspath,
+ const char *moved_to_repos_relpath,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
/**
* Move @a src_abspath to @a dst_abspath, by scheduling @a dst_abspath
* for addition to the repository, remembering the history. Mark @a src_abspath
Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Fri Jun 10 15:04:06 2016
@@ -4423,6 +4423,9 @@ typedef enum svn_client_conflict_option_
svn_client_conflict_option_incoming_delete_ignore,
svn_client_conflict_option_incoming_delete_accept,
+ /* Options for incoming move vs local edit */
+ svn_client_conflict_option_incoming_move_file_text_merge,
+
} svn_client_conflict_option_id_t;
/**
Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Fri Jun 10 15:04:06 2016
@@ -1773,6 +1773,10 @@ struct conflict_tree_incoming_delete_det
* or in ADDED_REV (in which case moves should be interpreted in reverse).
* Follow MOVE->NEXT for subsequent moves in later revisions. */
struct repos_move_info *move;
+
+ /* The path were we believe the moved-here node corresponding to the
+ * deleted node exists in the working copy. */
+ const char *moved_to_abspath;
};
static const char *
@@ -4541,7 +4545,7 @@ resolve_merge_incoming_added_file_text_m
local_abspath = svn_client_conflict_get_local_abspath(conflict);
- /* Set up tempory storage for the repository version of file. */
+ /* Set up temporary storage for the repository version of file. */
SVN_ERR(svn_wc__get_tmpdir(&wc_tmpdir, ctx->wc_ctx, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_io_open_unique_file3(&incoming_new_file,
@@ -5579,6 +5583,174 @@ unlock_wc:
return SVN_NO_ERROR;
}
+/* Implements conflict_option_resolve_func_t. */
+static svn_error_t *
+resolve_incoming_move_file_text_merge(svn_client_conflict_option_t *option,
+ svn_client_conflict_t *conflict,
+ apr_pool_t *scratch_pool)
+{
+ svn_client_conflict_option_id_t option_id;
+ const char *local_abspath;
+ const char *lock_abspath;
+ svn_client_ctx_t *ctx = conflict->ctx;
+ svn_error_t *err;
+ const char *repos_root_url;
+ const char *repos_uuid;
+ const char *incoming_old_repos_relpath;
+ svn_revnum_t incoming_old_pegrev;
+ const char *incoming_new_repos_relpath;
+ svn_revnum_t incoming_new_pegrev;
+ const char *wc_tmpdir;
+ apr_file_t *ancestor_file;
+ const char *ancestor_abspath;
+ svn_stream_t *ancestor_stream;
+ apr_hash_t *victim_props;
+ apr_hash_t *move_target_props;
+ const char *ancestor_url;
+ const char *corrected_url;
+ svn_ra_session_t *ra_session;
+ svn_wc_merge_outcome_t merge_content_outcome;
+ svn_wc_notify_state_t merge_props_outcome;
+ apr_array_header_t *propdiffs;
+ struct conflict_tree_incoming_delete_details *details;
+
+ details = conflict->tree_conflict_incoming_details;
+ if (details == NULL)
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("Conflict resolution option '%d' requires "
+ "details for tree conflict at '%s' to be "
+ "fetched from the repository."),
+ option->id,
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ option_id = svn_client_conflict_option_get_id(option);
+ local_abspath = svn_client_conflict_get_local_abspath(conflict);
+ SVN_ERR(svn_client_conflict_get_repos_info(&repos_root_url, &repos_uuid,
+ conflict, scratch_pool,
+ scratch_pool));
+ SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(
+ &incoming_old_repos_relpath, &incoming_old_pegrev,
+ NULL, conflict, scratch_pool,
+ scratch_pool));
+ SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(
+ &incoming_new_repos_relpath, &incoming_new_pegrev,
+ NULL, conflict, scratch_pool,
+ scratch_pool));
+
+ /* Set up temporary storage for the common ancestor version of the file. */
+ SVN_ERR(svn_wc__get_tmpdir(&wc_tmpdir, ctx->wc_ctx, local_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_io_open_unique_file3(&ancestor_file,
+ &ancestor_abspath, wc_tmpdir,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ ancestor_stream = svn_stream_from_aprfile2(ancestor_file, TRUE, scratch_pool);
+
+ /* Fetch the ancestor file's content. */
+ ancestor_url = svn_path_url_add_component2(repos_root_url,
+ incoming_old_repos_relpath,
+ scratch_pool);
+ SVN_ERR(svn_client__open_ra_session_internal(&ra_session, &corrected_url,
+ ancestor_url, NULL, NULL,
+ FALSE, FALSE, conflict->ctx,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_ra_get_file(ra_session, "", incoming_old_pegrev,
+ ancestor_stream, NULL, /* fetched_rev */
+ NULL /* we don't need these props */, scratch_pool));
+
+ /* Flush ancestor file to disk. */
+ SVN_ERR(svn_stream_close(ancestor_stream));
+ SVN_ERR(svn_io_file_flush(ancestor_file, scratch_pool));
+
+ /* ### The following WC modifications should be atomic. */
+ SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, ctx->wc_ctx,
+ local_abspath,
+ scratch_pool, scratch_pool));
+
+ err = verify_local_state_for_incoming_delete(conflict, option, scratch_pool);
+ if (err)
+ goto unlock_wc;
+
+ /* Get a copy of the conflict victim's properties. */
+ err = svn_wc_prop_list2(&victim_props, ctx->wc_ctx, local_abspath,
+ scratch_pool, scratch_pool);
+ if (err)
+ goto unlock_wc;
+
+ /* Get a copy of the move target's properties. */
+ err = svn_wc_prop_list2(&move_target_props, ctx->wc_ctx,
+ details->moved_to_abspath,
+ scratch_pool, scratch_pool);
+ if (err)
+ goto unlock_wc;
+
+ /* Create a property diff for the files. */
+ err = svn_prop_diffs(&propdiffs, victim_props, move_target_props,
+ scratch_pool);
+ if (err)
+ goto unlock_wc;
+
+ /* Perform the file merge. */
+ err = svn_wc_merge5(&merge_content_outcome, &merge_props_outcome,
+ ctx->wc_ctx, ancestor_abspath,
+ local_abspath, details->moved_to_abspath,
+ NULL, NULL, NULL, /* labels */
+ NULL, NULL, /* conflict versions */
+ FALSE, /* dry run */
+ NULL, NULL, /* diff3_cmd, merge_options */
+ NULL, propdiffs,
+ NULL, NULL, /* conflict func/baton */
+ ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool);
+ svn_io_sleep_for_timestamps(details->moved_to_abspath, scratch_pool);
+ if (err)
+ goto unlock_wc;
+
+ if (ctx->notify_func2)
+ {
+ svn_wc_notify_t *notify;
+
+ /* Tell the world about the file merge that just happened. */
+ notify = svn_wc_create_notify(details->moved_to_abspath,
+ svn_wc_notify_update_update,
+ scratch_pool);
+ if (merge_content_outcome == svn_wc_merge_conflict)
+ notify->content_state = svn_wc_notify_state_conflicted;
+ else
+ notify->content_state = svn_wc_notify_state_merged;
+ notify->prop_state = merge_props_outcome;
+ notify->kind = svn_node_file;
+ ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
+ }
+
+ /* The merge is done. Local edits are now at the moved-to location.
+ * Delete the tree conflict victim (clears the tree conflict marker). */
+ err = svn_wc_delete4(ctx->wc_ctx, local_abspath, FALSE, FALSE,
+ ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2,
+ scratch_pool);
+
+ if (ctx->notify_func2)
+ {
+ svn_wc_notify_t *notify;
+
+ notify = svn_wc_create_notify(local_abspath, svn_wc_notify_resolved_tree,
+ scratch_pool);
+ ctx->notify_func2(ctx->notify_baton2, notify, scratch_pool);
+ }
+
+ conflict->resolution_tree = option_id;
+
+unlock_wc:
+ err = svn_error_compose_create(err, svn_wc__release_write_lock(ctx->wc_ctx,
+ lock_abspath,
+ scratch_pool));
+ SVN_ERR(err);
+
+ return SVN_NO_ERROR;
+}
+
/* Resolver options for a text conflict */
static const svn_client_conflict_option_t text_conflict_options[] =
{
@@ -6404,6 +6576,92 @@ configure_option_incoming_delete_accept(
return SVN_NO_ERROR;
}
+/* Configure 'incoming move file merge' resolution option for
+ * a tree conflict. */
+static svn_error_t *
+configure_option_incoming_move_file_merge(svn_client_conflict_t *conflict,
+ apr_array_header_t *options,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t victim_node_kind;
+ svn_wc_conflict_action_t incoming_change;
+ svn_wc_conflict_reason_t local_change;
+ const char *incoming_old_repos_relpath;
+ svn_revnum_t incoming_old_pegrev;
+ svn_node_kind_t incoming_old_kind;
+ const char *incoming_new_repos_relpath;
+ svn_revnum_t incoming_new_pegrev;
+ svn_node_kind_t incoming_new_kind;
+ struct conflict_tree_incoming_delete_details *details;
+
+ details = conflict->tree_conflict_incoming_details;
+ if (details == NULL || details->move == NULL)
+ return SVN_NO_ERROR;
+
+ incoming_change = svn_client_conflict_get_incoming_change(conflict);
+ local_change = svn_client_conflict_get_local_change(conflict);
+ victim_node_kind = svn_client_conflict_tree_get_victim_node_kind(conflict);
+ SVN_ERR(svn_client_conflict_get_incoming_old_repos_location(
+ &incoming_old_repos_relpath, &incoming_old_pegrev,
+ &incoming_old_kind, conflict, scratch_pool,
+ scratch_pool));
+ SVN_ERR(svn_client_conflict_get_incoming_new_repos_location(
+ &incoming_new_repos_relpath, &incoming_new_pegrev,
+ &incoming_new_kind, conflict, scratch_pool,
+ scratch_pool));
+
+ if (victim_node_kind == svn_node_file &&
+ incoming_old_kind == svn_node_file &&
+ incoming_new_kind == svn_node_none &&
+ incoming_change == svn_wc_conflict_action_delete)
+ {
+ svn_client_conflict_option_t *option;
+ const char *wcroot_abspath;
+ const char *local_abspath;
+ struct repos_move_info *move;
+ const char *moved_to_abspath;
+
+ option = apr_pcalloc(options->pool, sizeof(*option));
+ option->id = svn_client_conflict_option_incoming_move_file_text_merge;
+ SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, conflict->ctx->wc_ctx,
+ conflict->local_abspath, scratch_pool,
+ scratch_pool));
+ local_abspath = svn_client_conflict_get_local_abspath(conflict);
+
+ /* Find the last move in the move chain. This should correspond to
+ * the node's location in incoming_new_pegrev. */
+ /* ### What about reverse-merges and reverse-updates? */
+ move = details->move;
+ while (move->next)
+ move = move->next;
+
+ SVN_ERR(svn_wc__guess_incoming_move_target_node(
+ &moved_to_abspath, conflict->ctx->wc_ctx, local_abspath,
+ move->moved_to_repos_relpath, incoming_new_pegrev,
+ scratch_pool, scratch_pool));
+ if (moved_to_abspath == NULL)
+ return SVN_NO_ERROR;
+
+ details->moved_to_abspath = apr_pstrdup(conflict->pool,
+ moved_to_abspath);
+ option->description =
+ apr_psprintf(
+ options->pool,
+ _("follow move-away of '%s' and merge with '%s'"),
+ svn_dirent_local_style(svn_dirent_skip_ancestor(wcroot_abspath,
+ local_abspath),
+ scratch_pool),
+ svn_dirent_local_style(svn_dirent_skip_ancestor(wcroot_abspath,
+ moved_to_abspath),
+ scratch_pool));
+ option->conflict = conflict;
+ option->do_resolve_func = resolve_incoming_move_file_text_merge;
+ APR_ARRAY_PUSH(options, const svn_client_conflict_option_t *) = option;
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_client_conflict_tree_get_resolution_options(apr_array_header_t **options,
svn_client_conflict_t *conflict,
@@ -6451,6 +6709,8 @@ svn_client_conflict_tree_get_resolution_
scratch_pool));
SVN_ERR(configure_option_incoming_delete_accept(conflict, *options,
scratch_pool));
+ SVN_ERR(configure_option_incoming_move_file_merge(conflict, *options,
+ scratch_pool));
return SVN_NO_ERROR;
}
Modified: subversion/trunk/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/conflicts.c?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_wc/conflicts.c Fri Jun 10 15:04:06 2016
@@ -3684,3 +3684,74 @@ svn_wc__conflict_tree_update_moved_away_
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_wc__guess_incoming_move_target_node(const char **moved_to_abspath,
+ svn_wc_context_t *wc_ctx,
+ const char *victim_abspath,
+ const char *moved_to_repos_relpath,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *candidates;
+ apr_pool_t *iterpool;
+ int i;
+
+ *moved_to_abspath = NULL;
+ SVN_ERR(svn_wc__find_repos_node_in_wc(&candidates, wc_ctx->db, victim_abspath,
+ moved_to_repos_relpath, rev,
+ scratch_pool, scratch_pool));
+
+ /* Find a "useful move target" node in our set of candidates.
+ * Since there is no way to be certain, filter out nodes which seem
+ * unlikely candidates, and return the first node which is "good enough".
+ * Nodes which are tree conflict victims don't count, and nodes which
+ * cannot be modified (e.g. replaced or deleted nodes) don't count.
+ * Ignore switched nodes as well, since that is an unlikely case during
+ * update/swtich/merge conflict resolution. And externals shouldn't even
+ * be on our candidate list in the first place. */
+ iterpool = svn_pool_create(scratch_pool);
+ for (i = 0; i < candidates->nelts; i++)
+ {
+ const char *local_abspath;
+ svn_boolean_t tree_conflicted;
+ svn_wc__db_status_t status;
+ svn_boolean_t is_wcroot;
+ svn_boolean_t is_switched;
+
+ svn_pool_clear(iterpool);
+
+ local_abspath = APR_ARRAY_IDX(candidates, i, const char *);
+
+ SVN_ERR(svn_wc__internal_conflicted_p(NULL, NULL, &tree_conflicted,
+ wc_ctx->db, local_abspath,
+ iterpool));
+ if (tree_conflicted)
+ continue;
+
+ SVN_ERR(svn_wc__db_read_info(&status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ wc_ctx->db, local_abspath, iterpool,
+ iterpool));
+ if (status != svn_wc__db_status_normal &&
+ status != svn_wc__db_status_added)
+ continue;
+
+ SVN_ERR(svn_wc__db_is_switched(&is_wcroot, &is_switched, NULL,
+ wc_ctx->db, local_abspath, iterpool));
+ if (is_wcroot || is_switched)
+ continue;
+
+ /* This might be a move target. Fingers crossed ;-) */
+ *moved_to_abspath = apr_pstrdup(result_pool, local_abspath);
+ break;
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Fri Jun 10 15:04:06 2016
@@ -1291,6 +1291,10 @@ PRAGMA locking_mode = exclusive;
exclusive-locking is mostly used on remote file systems. */
PRAGMA journal_mode = DELETE
+-- STMT_FIND_REPOS_PATH_IN_WC
+SELECT local_relpath FROM nodes_current
+ WHERE wc_id = ?1 AND repos_path = ?2 AND revision = ?3
+
/* ------------------------------------------------------------------------- */
/* these are used in entries.c */
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Fri Jun 10 15:04:06 2016
@@ -16577,3 +16577,48 @@ svn_wc__db_process_commit_queue(svn_wc__
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const char *repos_relpath,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *wri_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &wri_relpath, db,
+ wri_abspath, scratch_pool,
+ scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_FIND_REPOS_PATH_IN_WC));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isr", wcroot->wc_id, repos_relpath, rev));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ *local_abspath_list = apr_array_make(result_pool, have_row ? 1 : 0,
+ sizeof(const char*));
+ while (have_row)
+ {
+ const char *local_relpath;
+ const char *local_abspath;
+
+ local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+ local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
+ result_pool);
+ APR_ARRAY_PUSH(*local_abspath_list, const char *) = local_abspath;
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+
+ return svn_error_trace(svn_sqlite__reset(stmt));
+}
+
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.h?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.h Fri Jun 10 15:04:06 2016
@@ -3459,6 +3459,24 @@ svn_wc__required_lock_for_resolve(const
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+
+/* Return an array of const char * elements, which represent local absolute
+ * paths for nodes, within the working copy indicated by WRI_ABSPATH, which
+ * correspond to REPOS_RELPATH@REV.
+ * If no such nodes exist, return an empty array.
+ *
+ * Note that this function returns each and every such node that is known
+ * in the WC, including, for example, nodes that were children of a directory
+ * which has been replaced.
+ */
+svn_error_t *
+svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ const char *repos_relpath,
+ svn_revnum_t rev,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
/* @} */
typedef svn_error_t * (*svn_wc__db_verify_cb_t)(void *baton,
Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1747727&r1=1747726&r2=1747727&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Fri Jun 10 15:04:06 2016
@@ -445,6 +445,10 @@ static const resolver_option_t builtin_r
{ "a", N_("accept incoming deletion"), NULL,
svn_client_conflict_option_incoming_delete_accept },
+ /* Options for incoming move vs local edit. */
+ { "m", N_("follow incoming move and merge"), NULL,
+ svn_client_conflict_option_incoming_move_file_text_merge },
+
{ NULL }
};