Author: rhuijben
Date: Wed Feb 18 22:15:50 2015
New Revision: 1660742
URL: http://svn.apache.org/r1660742
Log:
Fix svn_wc__db_op_make_copy_internal()'s handling of mixed revision BASE trees.
This fixes some issues around tree conflict handling, and improves
database consistency.
* build/transform_sql.py
(process_file): Allow passing columns and binding variables as argument of
IS_STRICT_DESCENDANT_OF, like the other macros.
* subversion/libsvn_wc/wc-checks.sql
(STMT_STATIC_VERIFY): Add documentation to the older statements. Extend.
* subversion/libsvn_wc/wc-queries.sql
(STMT_DELETE_WORKING_BASE_DELETE): Split into non-recursive...
(STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE): ... and recursive variants.
(STMT_INSERT_WORKING_NODE_FROM_BASE_COPY): Allow replacing nodes, and
handle moved_to when doing that.
* subversion/libsvn_wc/wc_db.c
(db_base_remove): Update caller.
(make_copy_txn): Add recursion arguments to determine when a new op-depth
is needed. Simplify code, by moving the initial shadowing to the calling
function.
(make_copy_move_moved_to): New function.
(svn_wc__db_op_make_copy_internal): Update caller. Shadow all nodes with
base-deleted before calling make_copy_txn. Move moved-to information
to this layer.
* subversion/tests/cmdline/tree_conflict_tests.py
(update_delete_mixed_rev): Remove XFail. Tweak status value.
* subversion/tests/libsvn_wc/op-depth-test.c
(make_copy_mixed): New function. Tests svn_wc__db_op_make_copy_internal.
make_copy_and_delete_mixed): New functions. Tests svn_wc__db_base_remove
and shows an existing issue with move handling on base-delete.
(test_list): Add new items.
Modified:
subversion/trunk/build/transform_sql.py
subversion/trunk/subversion/libsvn_wc/wc-checks.sql
subversion/trunk/subversion/libsvn_wc/wc-queries.sql
subversion/trunk/subversion/libsvn_wc/wc_db.c
subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py
subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
Modified: subversion/trunk/build/transform_sql.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/build/transform_sql.py?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/build/transform_sql.py (original)
+++ subversion/trunk/build/transform_sql.py Wed Feb 18 22:15:50 2015
@@ -140,7 +140,7 @@ class Processor(object):
# '/'+1 == '0'
line = re.sub(
- r'IS_STRICT_DESCENDANT_OF[(]([A-Za-z_.]+), ([?][0-9]+)[)]',
+ r'IS_STRICT_DESCENDANT_OF[(]([?]?[A-Za-z0-9_.]+),
([?]?[A-Za-z0-9_.]+)[)]',
r"(((\1) > (CASE (\2) WHEN '' THEN '' ELSE (\2) || '/' END))" +
r" AND ((\1) < CASE (\2) WHEN '' THEN X'FFFF' ELSE (\2) || '0'
END))",
line)
Modified: subversion/trunk/subversion/libsvn_wc/wc-checks.sql
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-checks.sql?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-checks.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-checks.sql Wed Feb 18 22:15:50 2015
@@ -76,6 +76,8 @@ BEGIN
END;
-- STMT_STATIC_VERIFY
+/* A parent node must exist for every normal node except the root.
+ That node must exist at a lower or equal op-depth */
SELECT local_relpath, op_depth, 'SV001: No ancestor in NODES'
FROM nodes n WHERE local_relpath != ''
AND file_external IS NULL
@@ -86,6 +88,8 @@ FROM nodes n WHERE local_relpath != ''
UNION ALL
+/* All ACTUAL nodes must have an equivalent NODE in NODES
+ or be only one level deep (delete-delete tc) */
SELECT local_relpath, -1, 'SV002: No ancestor in ACTUAL'
FROM actual_node a WHERE local_relpath != ''
AND NOT EXISTS(SELECT 1 from nodes i
@@ -96,7 +100,8 @@ FROM actual_node a WHERE local_relpath !
AND i.local_relpath=a.local_relpath)
UNION ALL
-
+/* Verify if the ACTUAL data makes sense for the related node.
+ Only conflict data is valid if there is none */
SELECT a.local_relpath, -1, 'SV003: Bad or Unneeded actual data'
FROM actual_node a
LEFT JOIN nodes n on n.wc_id = a.wc_id AND n.local_relpath = a.local_relpath
@@ -111,7 +116,8 @@ WHERE (a.properties IS NOT NULL
AND i.local_relpath=a.parent_relpath)
UNION ALL
-
+/* If a node is not present in the working copy (normal, add, copy) it doesn't
+ have revision details stored on this record */
SELECT local_relpath, op_depth, 'SV004: Unneeded node data'
FROM nodes
WHERE presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
@@ -129,7 +135,8 @@ AND (properties IS NOT NULL
OR inherited_props IS NOT NULL)
UNION ALL
-
+/* base-deleted nodes don't have a repository location. They are just
+ shadowing without a replacement */
SELECT local_relpath, op_depth, 'SV005: Unneeded base-deleted node data'
FROM nodes
WHERE presence IN (MAP_BASE_DELETED)
@@ -138,7 +145,7 @@ AND (repos_id IS NOT NULL
OR revision IS NOT NULL)
UNION ALL
-
+/* Verify if type specific data is set (or not set for wrong type) */
SELECT local_relpath, op_depth, 'SV006: Kind specific data invalid on normal'
FROM nodes
WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
@@ -157,7 +164,8 @@ AND (kind IS NULL
ELSE symlink_target IS NOT NULL END))
UNION ALL
-
+/* Local-adds are always their own operation (read: they don't have
+ op-depth descendants, nor are op-depth descendants */
SELECT local_relpath, op_depth, 'SV007: Invalid op-depth for local add'
FROM nodes
WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
@@ -165,7 +173,9 @@ WHERE presence IN (MAP_NORMAL, MAP_INCOM
AND op_depth != relpath_depth(local_relpath)
UNION ALL
-
+/* op-depth descendants are only valid if they have a direct parent
+ node at the same op-depth. Only certain types allow further
+ descendants */
SELECT local_relpath, op_depth, 'SV008: Node missing ancestor'
FROM nodes n
WHERE op_depth < relpath_depth(local_relpath)
@@ -174,11 +184,12 @@ WHERE op_depth < relpath_depth(local_rel
WHERE p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
AND p.op_depth=n.op_depth
AND (p.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
- OR (p.presence = MAP_BASE_DELETED
+ OR (p.presence IN (MAP_BASE_DELETED, MAP_NOT_PRESENT)
AND n.presence = MAP_BASE_DELETED)))
-UNION all
-
+UNION ALL
+/* Present op-depth descendants have the repository location implied by their
+ ancestor */
SELECT n.local_relpath, n.op_depth, 'SV009: Copied descendant mismatch'
FROM nodes n
JOIN nodes p
@@ -188,11 +199,65 @@ WHERE n.op_depth > 0 AND n.presence IN (
AND (n.repos_id != p.repos_id
OR n.repos_path !=
RELPATH_SKIP_JOIN(n.parent_relpath, p.repos_path, n.local_relpath)
- OR n.revision != p.revision)
-
-UNION all
+ OR n.revision != p.revision
+ OR p.kind != MAP_DIR
+ OR n.moved_here != p.moved_here)
+UNION ALL
+/* Only certain presence values are valid as op-root.
+ Note that the wc-root always has presence normal or incomplete */
SELECT n.local_relpath, n.op_depth, 'SV010: Invalid op-root presence'
FROM nodes n
WHERE n.op_depth = relpath_depth(local_relpath)
AND presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE, MAP_BASE_DELETED)
+
+UNION ALL
+/* If a node is shadowed, all its present op-depth descendants
+ must be shadowed at the same op-depth as well */
+SELECT n.local_relpath, n.op_depth, 'SV011: Incomplete shadowing'
+FROM nodes n
+JOIN nodes s ON s.wc_id=n.wc_id AND s.local_relpath=n.local_relpath
+ AND s.op_depth = relpath_depth(s.local_relpath)
+ AND s.op_depth = (SELECT MIN(op_depth) FROM nodes d
+ WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+ AND d.op_depth > n.op_depth)
+WHERE n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND EXISTS(SELECT 1
+ FROM nodes dn
+ WHERE dn.wc_id=n.wc_id AND dn.op_depth=n.op_depth
+ AND dn.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND IS_STRICT_DESCENDANT_OF(dn.local_relpath, n.local_relpath)
+ AND dn.file_external IS NULL
+ AND NOT EXISTS(SELECT 1
+ FROM nodes ds
+ WHERE ds.wc_id=n.wc_id AND ds.op_depth=s.op_depth
+ AND ds.local_relpath=dn.local_relpath))
+
+UNION ALL
+/* A base-delete is only valid if it directly deletes a present node */
+SELECT s.local_relpath, s.op_depth, 'SV012: Invalid base-delete'
+FROM nodes s
+LEFT JOIN nodes n ON n.wc_id=s.wc_id AND n.local_relpath=s.local_relpath
+ AND n.op_depth = (SELECT MAX(op_depth) FROM nodes d
+ WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+ AND d.op_depth < s.op_depth)
+WHERE s.presence = MAP_BASE_DELETED
+ AND n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
+
+UNION ALL
+
+SELECT d.local_relpath, d.op_depth, 'SV013: Moved here without origin'
+FROM nodes d
+WHERE d.op_depth = relpath_depth(d.local_relpath)
+ AND d.moved_here = 1
+ AND NOT EXISTS(SELECT 1 FROM nodes s
+ WHERE s.wc_id = d.wc_id AND s.moved_to = d.local_relpath)
+
+UNION ALL
+
+SELECT s.local_relpath, s.op_depth, 'SV014: Moved to without target'
+FROM nodes s
+WHERE s.moved_to IS NOT NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes d
+ WHERE d.wc_id = s.wc_id AND d.local_relpath = s.moved_to
+ AND d.moved_here =1 AND d.repos_path IS NOT NULL)
\ No newline at end of file
Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Wed Feb 18 22:15:50
2015
@@ -233,6 +233,16 @@ WHERE wc_id = ?1 AND IS_STRICT_DESCENDAN
-- STMT_DELETE_WORKING_BASE_DELETE
DELETE FROM nodes
+WHERE wc_id = ?1 AND local_relpath = ?2
+ AND presence = MAP_BASE_DELETED
+ AND op_depth > ?3
+ AND op_depth = (SELECT MIN(op_depth) FROM nodes n
+ WHERE n.wc_id = ?1
+ AND n.local_relpath = nodes.local_relpath
+ AND op_depth > ?3)
+
+-- STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE
+DELETE FROM nodes
WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
AND presence = MAP_BASE_DELETED
AND op_depth > ?3
@@ -1023,15 +1033,17 @@ WHERE wc_id = ?1
ORDER BY local_relpath
-- STMT_INSERT_WORKING_NODE_FROM_BASE_COPY
-INSERT INTO nodes (
+INSERT OR REPLACE INTO nodes (
wc_id, local_relpath, op_depth, parent_relpath, repos_id, repos_path,
revision, presence, depth, kind, changed_revision, changed_date,
changed_author, checksum, properties, translated_size, last_mod_time,
- symlink_target )
+ symlink_target, moved_to )
SELECT wc_id, local_relpath, ?3 /*op_depth*/, parent_relpath, repos_id,
repos_path, revision, presence, depth, kind, changed_revision,
changed_date, changed_author, checksum, properties, translated_size,
- last_mod_time, symlink_target
+ last_mod_time, symlink_target,
+ (SELECT moved_to FROM nodes
+ WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3) moved_to
FROM nodes
WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = 0
Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Wed Feb 18 22:15:50 2015
@@ -2410,8 +2410,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
}
if (keep_working)
{
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_WORKING_BASE_DELETE));
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, wcroot->sdb,
+ STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
SVN_ERR(svn_sqlite__step_done(stmt));
}
@@ -15010,95 +15011,163 @@ svn_wc__db_temp_op_start_directory_updat
static svn_error_t *
make_copy_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
- int op_depth,
+ apr_int64_t last_repos_id,
+ const char *last_repos_relpath,
+ svn_revnum_t last_revision,
+ int last_op_depth,
+ svn_boolean_t shadowed,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- svn_boolean_t add_working_base_deleted = FALSE;
- svn_boolean_t remove_working = FALSE;
- const apr_array_header_t *children;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- int i;
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_LOWEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ svn_boolean_t have_row = FALSE;
+ svn_revnum_t revision;
+ apr_int64_t repos_id;
+ const char *repos_relpath;
+ svn_node_kind_t kind;
+ int op_depth = relpath_depth(local_relpath);
- if (have_row)
+ if (last_op_depth != op_depth)
{
- svn_wc__db_status_t working_status;
- int working_op_depth;
-
- working_status = svn_sqlite__column_token(stmt, 1, presence_map);
- working_op_depth = svn_sqlite__column_int(stmt, 0);
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_DEPTH_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ op_depth));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
+ if (have_row)
+ shadowed = TRUE;
+ }
- SVN_ERR_ASSERT(working_status == svn_wc__db_status_normal
- || working_status == svn_wc__db_status_base_deleted
- || working_status == svn_wc__db_status_not_present
- || working_status == svn_wc__db_status_incomplete);
-
- /* Only change nodes in the layers where we are creating the copy.
- Deletes in higher layers will just apply to the copy */
- if (working_op_depth <= op_depth)
- {
- add_working_base_deleted = TRUE;
+ SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &kind, &revision,
+ &repos_relpath, &repos_id, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ wcroot, local_relpath,
+ scratch_pool, scratch_pool));
- if (working_status == svn_wc__db_status_base_deleted)
- remove_working = TRUE;
- }
+ if (last_repos_relpath
+ && repos_id == last_repos_id
+ && revision == last_revision)
+ {
+ const char *name = svn_relpath_skip_ancestor(last_repos_relpath,
+ repos_relpath);
+
+ if (strcmp(name, svn_relpath_basename(local_relpath, NULL)) == 0)
+ op_depth = last_op_depth;
}
- else
- SVN_ERR(svn_sqlite__reset(stmt));
- if (remove_working)
+ /* Insert a not-present node to mark that we don't know what exists
+ here */
+ if (last_op_depth > 0 && last_op_depth != op_depth)
{
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_LOWEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step_done(stmt));
+ insert_working_baton_t iwb;
+
+ blank_iwb(&iwb);
+ iwb.presence = svn_wc__db_status_not_present;
+ iwb.op_depth = last_op_depth;
+
+ iwb.original_repos_id = repos_id;
+ iwb.original_repos_relpath = repos_relpath;
+ iwb.original_revnum = revision;
+ iwb.kind = kind;
+
+ SVN_ERR(insert_working_node(&iwb, wcroot, local_relpath, scratch_pool));
}
- if (add_working_base_deleted)
+ /* Can we add a new copy node at the wanted op-depth? */
+ if (!have_row || op_depth == last_op_depth)
{
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_INSERT_DELETE_FROM_BASE));
+ int i;
+
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, wcroot->sdb,
+ STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
+
+ if (shadowed)
+ SVN_ERR(db_extend_parent_delete(wcroot, local_relpath, kind,
+ op_depth, scratch_pool));
+
+ if (kind == svn_node_dir)
+ {
+ const apr_array_header_t *children;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ SVN_ERR(gather_repo_children(&children, wcroot, local_relpath,
+ 0, scratch_pool, iterpool));
+
+ for (i = 0; i < children->nelts; i++)
+ {
+ const char *name = APR_ARRAY_IDX(children, i, const char *);
+ const char *copy_relpath;
+
+ svn_pool_clear(iterpool);
+
+ copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
+
+ SVN_ERR(make_copy_txn(wcroot, copy_relpath,
+ repos_id, repos_relpath, revision,
+ op_depth, shadowed, scratch_pool));
+ }
+ svn_pool_destroy(iterpool);
+ }
}
else
{
+ /* Auch... we can't make a copy of whatever comes deeper, as this
+ op-depth is already filled by something else. Let's hope
+ the user doesn't mind.
+
+ Luckily we know that the moves are already moved to the shadowing
+ layer, so we can just remove dangling base-deletes if there are
+ any.
+ */
+ /* BASE_DELETED may be at op_depth, so let's use last_op_depth! */
+
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-
STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
+ STMT_DELETE_WORKING_BASE_DELETE));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
- op_depth));
+ last_op_depth));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ last_op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
}
- /* Get the BASE children, as WORKING children don't need modifications */
- SVN_ERR(gather_repo_children(&children, wcroot, local_relpath,
- 0, scratch_pool, iterpool));
-
- for (i = 0; i < children->nelts; i++)
- {
- const char *name = APR_ARRAY_IDX(children, i, const char *);
- const char *copy_relpath;
-
- svn_pool_clear(iterpool);
+ return SVN_NO_ERROR;
+}
- copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
+/* Helper for svn_wc__db_op_make_copy_internal */
+static svn_error_t *
+make_copy_move_moved_to(svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int cur_op_depth,
+ int new_op_depth,
+ const char *moved_to,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
- SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, iterpool));
- }
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_UPDATE_MOVED_TO_RELPATH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+ local_relpath, cur_op_depth));
+ SVN_ERR(svn_sqlite__step_done(stmt));
- svn_pool_destroy(iterpool);
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_UPDATE_MOVED_TO_RELPATH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id,
+ local_relpath, new_op_depth, moved_to));
+ SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
}
+
svn_error_t *
svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
@@ -15140,12 +15209,56 @@ svn_wc__db_op_make_copy_internal(svn_wc_
}
else
{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ svn_error_t *err = NULL;
+ int affected_rows;
+
+ op_depth = relpath_depth(local_relpath);
/* We don't allow copies to contain server-excluded nodes;
the update editor is going to have to bail out. */
- SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath,
scratch_pool));
+ SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, iterpool));
+
+ /* Insert a shadowing layer */
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, wcroot->sdb,
+ STMT_INSERT_DELETE_FROM_NODE_RECURSIVE));
+
+ /* As we are keeping whatever is below, move the*/
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "isdd",
+ wcroot->wc_id, local_relpath,
+ 0, op_depth));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+ SVN_ERR_ASSERT(affected_rows > 0);
+
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, wcroot->sdb,
+ STMT_SELECT_MOVED_DESCENDANTS_SRC));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd",
+ wcroot->wc_id, local_relpath,
+ op_depth));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ while (have_row && !err)
+ {
+ err = make_copy_move_moved_to(
+ wcroot,
+ svn_sqlite__column_text(stmt, 1, iterpool),
+ svn_sqlite__column_int(stmt, 0),
+ op_depth,
+ svn_sqlite__column_text(stmt, 4, iterpool),
+ iterpool);
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+
+ SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+
SVN_ERR(make_copy_txn(wcroot, local_relpath,
- relpath_depth(local_relpath), scratch_pool));
+ INVALID_REPOS_ID, NULL, SVN_INVALID_REVNUM,
+ relpath_depth(local_relpath), FALSE,
scratch_pool));
}
if (conflicts)
Modified: subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py Wed Feb 18
22:15:50 2015
@@ -1449,7 +1449,6 @@ def update_dir_with_not_present(sbox):
run_and_verify_svn(None, [],
'ci', '-m', '', wc_dir)
-@XFail()
def update_delete_mixed_rev(sbox):
"update that deletes mixed-rev"
@@ -1484,6 +1483,10 @@ def update_delete_mixed_rev(sbox):
status='A ', copied='+', treeconflict='C', wc_rev='-')
expected_status.tweak('A/B/F', 'A/B/E', 'A/B/E/beta', 'A/B/lambda',
copied='+', wc_rev='-')
+
+ # The entries world doesn't see a changed revision as another add
+ # while the WC-NG world does...
+ expected_status.tweak('A/B/E', status='A ', entry_status=' ')
run_and_verify_update(wc_dir,
expected_output, expected_disk, expected_status,
None, None, None, None, None, 1,
Modified: subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Wed Feb 18
22:15:50 2015
@@ -10993,6 +10993,334 @@ move_deep_bump(const svn_test_opts_t *op
return SVN_NO_ERROR;
}
+
+static svn_error_t *
+make_copy_mixed(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+ svn_test__sandbox_t b;
+
+ SVN_ERR(svn_test__sandbox_create(&b, "make_copy_mixed", opts, pool));
+
+ SVN_ERR(sbox_wc_mkdir(&b, "A"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/K"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/O"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/R"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/R/S"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T"));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_update(&b, "", 1));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r2", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r3", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r4", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r5", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+
+ SVN_ERR(sbox_wc_update(&b, "", 5));
+ SVN_ERR(sbox_wc_update(&b, "A", 4));
+ SVN_ERR(sbox_wc_update(&b, "A/B", 3));
+ SVN_ERR(sbox_wc_update(&b, "A/B/C", 2));
+ SVN_ERR(sbox_wc_update(&b, "A/B/K", 1));
+ SVN_ERR(sbox_wc_update(&b, "A/N/O", 3));
+
+ SVN_ERR(sbox_wc_delete(&b, "A/B/C/F"));
+ SVN_ERR(sbox_wc_delete(&b, "A/B/G/J"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+
+ SVN_ERR(sbox_wc_update(&b, "A/N/P", 1));
+ SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1));
+ SVN_ERR(sbox_wc_delete(&b, "A/N/P"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+ SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q"));
+ SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H"));
+
+ /* And something that can't be represented */
+ SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1));
+ SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E"));
+
+ {
+ nodes_row_t nodes[] = {
+ {0, "", "normal", 5, "", NOT_MOVED, "k"},
+ {0, "A", "normal", 4, "A"},
+ {0, "A/B", "normal", 3, "A/B"},
+ {0, "A/B/C", "normal", 2, "A/B/C"},
+ {0, "A/B/C/D", "normal", 2, "A/B/C/D"},
+ {0, "A/B/C/E", "normal", 1, "A/B/C/E"},
+ {0, "A/B/C/F", "normal", 2, "A/B/C/F"},
+ {0, "A/B/G", "normal", 3, "A/B/G"},
+ {0, "A/B/G/H", "normal", 3, "A/B/G/H"},
+ {0, "A/B/G/I", "normal", 3, "A/B/G/I"},
+ {0, "A/B/G/J", "normal", 3, "A/B/G/J"},
+ {0, "A/B/K", "normal", 1, "A/B/K"},
+ {0, "A/B/K/L", "normal", 1, "A/B/K/L"},
+ {0, "A/B/K/M", "normal", 1, "A/B/K/M"},
+ {0, "A/N", "normal", 4, "A/N"},
+ {0, "A/N/O", "normal", 3, "A/N/O"},
+ {0, "A/N/P", "normal", 1, "A/N/P"},
+ {0, "A/N/Q", "normal", 1, "A/N/Q"},
+ {0, "A/R", "normal", 4, "A/R"},
+ {0, "A/R/S", "normal", 4, "A/R/S"},
+ {0, "A/R/S/T", "normal", 4, "A/R/S/T"},
+ {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE},
+ {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE},
+ {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE},
+ {3, "A/N/P", "normal", NO_COPY_FROM},
+ {3, "A/N/Q", "base-deleted", NO_COPY_FROM, "Q"},
+ {4, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"},
+ {4, "A/B/C/F", "base-deleted", NO_COPY_FROM},
+ {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"},
+ {4, "A/B/G/J", "normal", NO_COPY_FROM},
+
+ {0}
+ };
+
+ SVN_ERR(check_db_rows(&b, "", nodes));
+ }
+
+ SVN_ERR(svn_wc__db_op_make_copy(b.wc_ctx->db, sbox_wc_path(&b, "A"),
+ NULL, NULL, pool));
+
+ {
+ nodes_row_t nodes[] = {
+ {0, "", "normal", 5, "", NOT_MOVED, "k"},
+ {0, "A", "normal", 4, "A"},
+ {0, "A/B", "normal", 3, "A/B"},
+ {0, "A/B/C", "normal", 2, "A/B/C"},
+ {0, "A/B/C/D", "normal", 2, "A/B/C/D"},
+ {0, "A/B/C/E", "normal", 1, "A/B/C/E"},
+ {0, "A/B/C/F", "normal", 2, "A/B/C/F"},
+ {0, "A/B/G", "normal", 3, "A/B/G"},
+ {0, "A/B/G/H", "normal", 3, "A/B/G/H"},
+ {0, "A/B/G/I", "normal", 3, "A/B/G/I"},
+ {0, "A/B/G/J", "normal", 3, "A/B/G/J"},
+ {0, "A/B/K", "normal", 1, "A/B/K"},
+ {0, "A/B/K/L", "normal", 1, "A/B/K/L"},
+ {0, "A/B/K/M", "normal", 1, "A/B/K/M"},
+ {0, "A/N", "normal", 4, "A/N"},
+ {0, "A/N/O", "normal", 3, "A/N/O"},
+ {0, "A/N/P", "normal", 1, "A/N/P"},
+ {0, "A/N/Q", "normal", 1, "A/N/Q"},
+ {0, "A/R", "normal", 4, "A/R"},
+ {0, "A/R/S", "normal", 4, "A/R/S"},
+ {0, "A/R/S/T", "normal", 4, "A/R/S/T"},
+ {1, "A", "normal", 4, "A"},
+ {1, "A/B", "not-present", 3, "A/B"},
+ {1, "A/B/C", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/C/D", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"},
+ {1, "A/B/C/F", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/G", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"},
+ {1, "A/B/G/I", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/G/J", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/K", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/K/L", "base-deleted", NO_COPY_FROM},
+ {1, "A/B/K/M", "base-deleted", NO_COPY_FROM},
+ {1, "A/N", "normal", 4, "A/N"},
+ {1, "A/N/O", "not-present", 3, "A/N/O"},
+ {1, "A/N/P", "not-present", 1, "A/N/P"},
+ {1, "A/N/Q", "not-present", 1, "A/N/Q", FALSE, "Q"},
+ {1, "A/R", "normal", 4, "A/R"},
+ {1, "A/R/S", "normal", 4, "A/R/S"},
+ {1, "A/R/S/T", "normal", 4, "A/R/S/T"},
+ {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE},
+ {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE},
+ {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE},
+ {2, "A/B", "normal", 3, "A/B"},
+ {2, "A/B/C", "not-present", 2, "A/B/C"},
+ {2, "A/B/G", "normal", 3, "A/B/G"},
+ {2, "A/B/G/H", "normal", 3, "A/B/G/H"},
+ {2, "A/B/G/I", "normal", 3, "A/B/G/I"},
+ {2, "A/B/G/J", "normal", 3, "A/B/G/J"},
+ {2, "A/B/K", "not-present", 1, "A/B/K"},
+ {3, "A/B/C", "normal", 2, "A/B/C"},
+ {3, "A/B/C/D", "normal", 2, "A/B/C/D"},
+ {3, "A/B/C/E", "not-present", 1, "A/B/C/E"},
+ {3, "A/B/C/F", "normal", 2, "A/B/C/F"},
+ {3, "A/B/K", "normal", 1, "A/B/K"},
+ {3, "A/B/K/L", "normal", 1, "A/B/K/L"},
+ {3, "A/B/K/M", "normal", 1, "A/B/K/M"},
+ {3, "A/N/O", "normal", 3, "A/N/O"},
+ {3, "A/N/P", "normal", NO_COPY_FROM},
+ {4, "A/B/C/F", "base-deleted", NO_COPY_FROM},
+ {4, "A/B/G/H", "base-deleted", NO_COPY_FROM},
+ {4, "A/B/G/J", "normal", NO_COPY_FROM},
+
+ {0}
+ };
+
+ SVN_ERR(check_db_rows(&b, "", nodes));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+make_copy_and_delete_mixed(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+ svn_test__sandbox_t b;
+
+ SVN_ERR(svn_test__sandbox_create(&b, "make_copy_and_del_mixed", opts, pool));
+
+ SVN_ERR(sbox_wc_mkdir(&b, "A"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/K"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/O"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/R"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/R/S"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T"));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_update(&b, "", 1));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r2", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r3", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r4", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+ SVN_ERR(sbox_wc_propset(&b, "k", "r5", ""));
+ SVN_ERR(sbox_wc_commit(&b, ""));
+
+ SVN_ERR(sbox_wc_update(&b, "", 5));
+ SVN_ERR(sbox_wc_update(&b, "A", 4));
+ SVN_ERR(sbox_wc_update(&b, "A/B", 3));
+ SVN_ERR(sbox_wc_update(&b, "A/B/C", 2));
+ SVN_ERR(sbox_wc_update(&b, "A/B/K", 1));
+ SVN_ERR(sbox_wc_update(&b, "A/N/O", 3));
+
+ SVN_ERR(sbox_wc_delete(&b, "A/B/C/F"));
+ SVN_ERR(sbox_wc_delete(&b, "A/B/G/J"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+
+ SVN_ERR(sbox_wc_update(&b, "A/N/P", 1));
+ SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1));
+ SVN_ERR(sbox_wc_delete(&b, "A/N/P"));
+ SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+ SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q"));
+ SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H"));
+
+ /* And something that can't be represented */
+ SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1));
+ SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E"));
+
+ {
+ nodes_row_t nodes[] = {
+ {0, "", "normal", 5, "", NOT_MOVED, "k"},
+ {0, "A", "normal", 4, "A"},
+ {0, "A/B", "normal", 3, "A/B"},
+ {0, "A/B/C", "normal", 2, "A/B/C"},
+ {0, "A/B/C/D", "normal", 2, "A/B/C/D"},
+ {0, "A/B/C/E", "normal", 1, "A/B/C/E"},
+ {0, "A/B/C/F", "normal", 2, "A/B/C/F"},
+ {0, "A/B/G", "normal", 3, "A/B/G"},
+ {0, "A/B/G/H", "normal", 3, "A/B/G/H"},
+ {0, "A/B/G/I", "normal", 3, "A/B/G/I"},
+ {0, "A/B/G/J", "normal", 3, "A/B/G/J"},
+ {0, "A/B/K", "normal", 1, "A/B/K"},
+ {0, "A/B/K/L", "normal", 1, "A/B/K/L"},
+ {0, "A/B/K/M", "normal", 1, "A/B/K/M"},
+ {0, "A/N", "normal", 4, "A/N"},
+ {0, "A/N/O", "normal", 3, "A/N/O"},
+ {0, "A/N/P", "normal", 1, "A/N/P"},
+ {0, "A/N/Q", "normal", 1, "A/N/Q"},
+ {0, "A/R", "normal", 4, "A/R"},
+ {0, "A/R/S", "normal", 4, "A/R/S"},
+ {0, "A/R/S/T", "normal", 4, "A/R/S/T"},
+ {1, "E", "normal", 1, "A/B/C/E", MOVED_HERE},
+ {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE},
+ {1, "Q", "normal", 1, "A/N/Q", MOVED_HERE},
+ {3, "A/N/P", "normal", NO_COPY_FROM},
+ {3, "A/N/Q", "base-deleted", NO_COPY_FROM, "Q"},
+ {4, "A/B/C/E", "base-deleted", NO_COPY_FROM, "E"},
+ {4, "A/B/C/F", "base-deleted", NO_COPY_FROM},
+ {4, "A/B/G/H", "base-deleted", NO_COPY_FROM, "H"},
+ {4, "A/B/G/J", "normal", NO_COPY_FROM},
+
+ {0}
+ };
+
+ SVN_ERR(check_db_rows(&b, "", nodes));
+ }
+
+ SVN_ERR(svn_wc__db_base_remove(b.wc_ctx->db, sbox_wc_path(&b, "A"),
+ TRUE, FALSE, FALSE, 99,
+ NULL, NULL, pool));
+
+ {
+ nodes_row_t nodes[] = {
+ {0, "", "normal", 5, "", NOT_MOVED, "k"},
+ {0, "A", "not-present", 99, "A"},
+ {1, "A", "normal", 4, "A"},
+ {1, "A/B", "not-present", 3, "A/B"},
+ {1, "A/N", "normal", 4, "A/N"},
+ {1, "A/N/O", "not-present", 3, "A/N/O"},
+ {1, "A/N/P", "not-present", 1, "A/N/P"},
+ {1, "A/N/Q", "not-present", 1, "A/N/Q", FALSE},
+ {1, "A/R", "normal", 4, "A/R"},
+ {1, "A/R/S", "normal", 4, "A/R/S"},
+ {1, "A/R/S/T", "normal", 4, "A/R/S/T"},
+ {1, "E", "normal", 1, "A/B/C/E"},
+ {1, "H", "normal", 3, "A/B/G/H", MOVED_HERE},
+ {1, "Q", "normal", 1, "A/N/Q"},
+ {2, "A/B", "normal", 3, "A/B"},
+ {2, "A/B/C", "not-present", 2, "A/B/C"},
+ {2, "A/B/G", "normal", 3, "A/B/G"},
+ {2, "A/B/G/H", "normal", 3, "A/B/G/H"},
+ {2, "A/B/G/I", "normal", 3, "A/B/G/I"},
+ {2, "A/B/G/J", "normal", 3, "A/B/G/J"},
+ {3, "A/B/C", "normal", 2, "A/B/C"},
+ {3, "A/B/C/D", "normal", 2, "A/B/C/D"},
+ {3, "A/B/C/E", "not-present", 1, "A/B/C/E"},
+ {3, "A/B/C/F", "normal", 2, "A/B/C/F"},
+ {2, "A/B/K", "not-present", 1, "A/B/K"},
+ {3, "A/B/K", "normal", 1, "A/B/K"},
+ {3, "A/B/K/L", "normal", 1, "A/B/K/L"},
+ {3, "A/B/K/M", "normal", 1, "A/B/K/M"},
+ {3, "A/N/O", "normal", 3, "A/N/O"},
+ {3, "A/N/P", "normal", NO_COPY_FROM},
+ {4, "A/B/C/F", "base-deleted", NO_COPY_FROM},
+ {4, "A/B/G/H", "base-deleted", NO_COPY_FROM},
+ {4, "A/B/G/J", "normal", NO_COPY_FROM},
+
+ {0}
+ };
+
+ /* This currently fails because Q and E are still marked as moved,
+ while there is nothing to be moved. */
+ SVN_ERR(check_db_rows(&b, "", nodes));
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* ---------------------------------------------------------------------- */
/* The list of test functions */
@@ -11202,6 +11530,10 @@ static struct svn_test_descriptor_t test
"move edit obstruction"),
SVN_TEST_OPTS_PASS(move_deep_bump,
"move deep bump"),
+ SVN_TEST_OPTS_PASS(make_copy_mixed,
+ "make a copy of a mixed revision tree"),
+ SVN_TEST_OPTS_XFAIL(make_copy_and_delete_mixed,
+ "make a copy of a mixed revision tree and del"),
SVN_TEST_NULL
};