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 2018/11/02 11:42:35 UTC
svn commit: r1845577 - in /subversion/trunk/subversion:
libsvn_client/conflicts.c tests/libsvn_client/conflicts-test.c
Author: stsp
Date: Fri Nov 2 11:42:35 2018
New Revision: 1845577
URL: http://svn.apache.org/viewvc?rev=1845577&view=rev
Log:
Add resolver support for 'added file vs unversioned file' with update/switch.
Make the conflict resolver handle conflicts recorded during update and switch
operations where a newly added file was obstructed by an unversioned file.
The resolver will now offer the 'incoming_added_file_text_merge' option
in this case, allowing users to merge unversioned files with incoming
newly added files.
Because 'merge' currently skips unversioned files and does not even record
a conflict for them, this change only affects 'update' and 'switch'.
Supporting unversioned file conflicts during merges can be revisited later.
Suggested by: Ace Olszowka
* subversion/libsvn_client/conflicts.c
(resolve_merge_incoming_added_file_text_update): Handle unversioned files
in addition to versioned files.
(configure_option_incoming_added_file_text_merge): Enable this option
for the case where the local file is unversioned.
* subversion/tests/libsvn_client/conflicts-test.c
(new_file_content): Declare.
(test_update_file_add_vs_unversiond_file,
test_switch_file_add_vs_unversiond_file, test_funcs): New tests.
Modified:
subversion/trunk/subversion/libsvn_client/conflicts.c
subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c
Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1845577&r1=1845576&r2=1845577&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Fri Nov 2 11:42:35 2018
@@ -6898,8 +6898,10 @@ resolve_merge_incoming_added_file_text_u
apr_hash_t *working_props;
apr_array_header_t *propdiffs;
svn_error_t *err;
+ svn_wc_conflict_reason_t local_change;
local_abspath = svn_client_conflict_get_local_abspath(conflict);
+ local_change = svn_client_conflict_get_local_change(conflict);
/* Set up tempory storage for the working version of file. */
SVN_ERR(svn_wc__get_tmpdir(&wc_tmpdir, ctx->wc_ctx, local_abspath,
@@ -6910,20 +6912,31 @@ resolve_merge_incoming_added_file_text_u
svn_io_file_del_none,
scratch_pool, scratch_pool));
- /* Copy the detranslated working file to temporary storage. */
- SVN_ERR(svn_wc__translated_stream(&working_file_stream, ctx->wc_ctx,
- local_abspath, local_abspath,
- SVN_WC_TRANSLATE_TO_NF,
- scratch_pool, scratch_pool));
+ if (local_change == svn_wc_conflict_reason_unversioned)
+ {
+ /* Copy the unversioned file to temporary storage. */
+ SVN_ERR(svn_stream_open_readonly(&working_file_stream, local_abspath,
+ scratch_pool, scratch_pool));
+ /* Unversioned files have no properties. */
+ working_props = apr_hash_make(scratch_pool);
+ }
+ else
+ {
+ /* Copy the detranslated working file to temporary storage. */
+ SVN_ERR(svn_wc__translated_stream(&working_file_stream, ctx->wc_ctx,
+ local_abspath, local_abspath,
+ SVN_WC_TRANSLATE_TO_NF,
+ scratch_pool, scratch_pool));
+ /* Get a copy of the working file's properties. */
+ SVN_ERR(svn_wc_prop_list2(&working_props, ctx->wc_ctx, local_abspath,
+ scratch_pool, scratch_pool));
+ filter_props(working_props, scratch_pool);
+ }
+
SVN_ERR(svn_stream_copy3(working_file_stream, working_file_tmp_stream,
ctx->cancel_func, ctx->cancel_baton,
scratch_pool));
- /* Get a copy of the working file's properties. */
- SVN_ERR(svn_wc_prop_list2(&working_props, ctx->wc_ctx, local_abspath,
- scratch_pool, scratch_pool));
- filter_props(working_props, scratch_pool);
-
/* Create an empty file as fake "merge-base" for the two added files.
* The files are not ancestrally related so this is the best we can do. */
SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file_abspath, NULL,
@@ -9783,6 +9796,7 @@ configure_option_incoming_added_file_tex
incoming_new_kind == svn_node_file &&
incoming_change == svn_wc_conflict_action_add &&
(local_change == svn_wc_conflict_reason_obstructed ||
+ local_change == svn_wc_conflict_reason_unversioned ||
local_change == svn_wc_conflict_reason_added))
{
const char *description;
Modified: subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c?rev=1845577&r1=1845576&r2=1845577&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_client/conflicts-test.c Fri Nov 2 11:42:35 2018
@@ -177,6 +177,8 @@ static const char *propval_branch = "Thi
static const char *propval_different = "This is a different property value.";
/* File content. */
+static const char *new_file_content =
+ "This is a new file\n";
static const char *modified_file_content =
"This is a modified file\n";
static const char *modified_file_on_branch_content =
@@ -6189,6 +6191,179 @@ test_file_vs_dir_move_merge_assertion_fa
return SVN_NO_ERROR;
}
+static svn_error_t *
+test_update_file_add_vs_unversiond_file(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b));
+ svn_client_conflict_t *conflict;
+ svn_client_ctx_t *ctx;
+ struct status_baton sb;
+ struct svn_client_status_t *status;
+ svn_opt_revision_t opt_rev;
+ svn_stringbuf_t *buf;
+
+ SVN_ERR(svn_test__sandbox_create(b, "update_file_add_vs_unversioned_file",
+ opts, pool));
+
+ SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */
+
+ /* Add a new file. */
+ SVN_ERR(sbox_file_write(b, new_file_name, new_file_content));
+ SVN_ERR(sbox_wc_add(b, new_file_name));
+ SVN_ERR(sbox_wc_commit(b, "")); /* r2 */
+
+ SVN_ERR(sbox_wc_update(b, "", 1)); /* back to r1 */
+
+ /* Create an identical unversioned file. */
+ SVN_ERR(sbox_file_write(b, new_file_name, new_file_content));
+ SVN_ERR(sbox_wc_update(b, "", 2)); /* back to r2 */
+
+ SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
+ SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, new_file_name),
+ ctx, b->pool, b->pool));
+ SVN_TEST_ASSERT(svn_client_conflict_get_local_change(conflict) ==
+ svn_wc_conflict_reason_unversioned);
+ SVN_TEST_ASSERT(svn_client_conflict_get_incoming_change(conflict) ==
+ svn_wc_conflict_action_add);
+ {
+ svn_client_conflict_option_id_t expected_opts[] = {
+ svn_client_conflict_option_postpone,
+ svn_client_conflict_option_accept_current_wc_state,
+ svn_client_conflict_option_incoming_added_file_text_merge,
+ -1 /* end of list */
+ };
+ SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts,
+ b->pool));
+ }
+
+ SVN_ERR(svn_client_conflict_tree_resolve_by_id(
+ conflict,
+ svn_client_conflict_option_incoming_added_file_text_merge,
+ ctx, b->pool));
+
+ /* Ensure that the file has the expected status. */
+ opt_rev.kind = svn_opt_revision_working;
+ sb.result_pool = b->pool;
+ SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, new_file_name),
+ &opt_rev, svn_depth_unknown, TRUE, TRUE,
+ TRUE, TRUE, FALSE, TRUE, NULL,
+ status_func, &sb, b->pool));
+ status = sb.status;
+ SVN_TEST_ASSERT(status->kind == svn_node_file);
+ SVN_TEST_ASSERT(status->versioned);
+ SVN_TEST_ASSERT(!status->conflicted);
+ SVN_TEST_ASSERT(status->node_status == svn_wc_status_normal);
+ SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal);
+ SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none);
+ SVN_TEST_ASSERT(!status->copied);
+ SVN_TEST_ASSERT(!status->switched);
+ SVN_TEST_ASSERT(!status->file_external);
+ SVN_TEST_ASSERT(status->moved_from_abspath == NULL);
+ SVN_TEST_ASSERT(status->moved_to_abspath == NULL);
+
+ /* Ensure that the file has the expected content. */
+ SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, new_file_name),
+ b->pool));
+ SVN_TEST_STRING_ASSERT(buf->data, new_file_content);
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_switch_file_add_vs_unversiond_file(const svn_test_opts_t *opts,
+ apr_pool_t *pool)
+{
+ svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b));
+ svn_client_conflict_t *conflict;
+ svn_client_ctx_t *ctx;
+ struct status_baton sb;
+ struct svn_client_status_t *status;
+ svn_opt_revision_t opt_rev;
+ svn_stringbuf_t *buf;
+ svn_revnum_t result_rev;
+ const char *trunk_url;
+ const char *new_file_path;
+
+ SVN_ERR(svn_test__sandbox_create(b, "switch_file_add_vs_unversioned_file",
+ opts, pool));
+
+ SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */
+
+ /* Create a branch of node "A". */
+ SVN_ERR(sbox_wc_copy(b, trunk_path, branch_path));
+ SVN_ERR(sbox_wc_commit(b, "")); /* r2 */
+
+ /* Add a new file on trunk. */
+ new_file_path = svn_relpath_join(trunk_path, new_file_name, b->pool);
+ SVN_ERR(sbox_file_write(b, new_file_path, new_file_content));
+ SVN_ERR(sbox_wc_add(b, new_file_path));
+ SVN_ERR(sbox_wc_commit(b, "")); /* r3 */
+
+ SVN_ERR(sbox_wc_update(b, "", 2)); /* back to r2 */
+
+ /* Create an identical unversioned file on the branch. */
+ new_file_path = svn_relpath_join(branch_path, new_file_name, b->pool);
+ SVN_ERR(sbox_file_write(b, new_file_path, new_file_content));
+
+ /* Switch branch to trunk. */
+ trunk_url = apr_pstrcat(b->pool, b->repos_url, "/", trunk_path, SVN_VA_NULL);
+ SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
+ opt_rev.kind = svn_opt_revision_head;
+ opt_rev.value.number = SVN_INVALID_REVNUM;
+ SVN_ERR(svn_client_switch3(&result_rev, sbox_wc_path(b, branch_path),
+ trunk_url, &opt_rev, &opt_rev,
+ svn_depth_infinity,
+ TRUE, FALSE, FALSE, FALSE, ctx, b->pool));
+
+ SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, new_file_path),
+ ctx, b->pool, b->pool));
+ SVN_TEST_ASSERT(svn_client_conflict_get_local_change(conflict) ==
+ svn_wc_conflict_reason_unversioned);
+ SVN_TEST_ASSERT(svn_client_conflict_get_incoming_change(conflict) ==
+ svn_wc_conflict_action_add);
+ {
+ svn_client_conflict_option_id_t expected_opts[] = {
+ svn_client_conflict_option_postpone,
+ svn_client_conflict_option_accept_current_wc_state,
+ svn_client_conflict_option_incoming_added_file_text_merge,
+ -1 /* end of list */
+ };
+ SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts,
+ b->pool));
+ }
+
+ SVN_ERR(svn_client_conflict_tree_resolve_by_id(
+ conflict,
+ svn_client_conflict_option_incoming_added_file_text_merge,
+ ctx, b->pool));
+
+ /* Ensure that the file has the expected status. */
+ opt_rev.kind = svn_opt_revision_working;
+ sb.result_pool = b->pool;
+ SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, new_file_path),
+ &opt_rev, svn_depth_unknown, TRUE, TRUE,
+ TRUE, TRUE, FALSE, TRUE, NULL,
+ status_func, &sb, b->pool));
+ status = sb.status;
+ SVN_TEST_ASSERT(status->kind == svn_node_file);
+ SVN_TEST_ASSERT(status->versioned);
+ SVN_TEST_ASSERT(!status->conflicted);
+ SVN_TEST_ASSERT(status->node_status == svn_wc_status_normal);
+ SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal);
+ SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none);
+ SVN_TEST_ASSERT(!status->copied);
+ SVN_TEST_ASSERT(!status->switched);
+ SVN_TEST_ASSERT(!status->file_external);
+ SVN_TEST_ASSERT(status->moved_from_abspath == NULL);
+ SVN_TEST_ASSERT(status->moved_to_abspath == NULL);
+
+ /* Ensure that the file has the expected content. */
+ SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, new_file_path),
+ b->pool));
+ SVN_TEST_STRING_ASSERT(buf->data, new_file_content);
+ return SVN_NO_ERROR;
+}
+
/* ========================================================================== */
@@ -6293,6 +6468,10 @@ static struct svn_test_descriptor_t test
"local missing conflict with ambiguous dir moves"),
SVN_TEST_OPTS_PASS(test_file_vs_dir_move_merge_assertion_failure,
"file v dir move merge assertion failure"),
+ SVN_TEST_OPTS_PASS(test_update_file_add_vs_unversiond_file,
+ "file add vs unversioned file during update"),
+ SVN_TEST_OPTS_PASS(test_switch_file_add_vs_unversiond_file,
+ "file add vs unversioned file during switch"),
SVN_TEST_NULL
};