Author: rhuijben
Date: Tue Feb 24 16:44:59 2015
New Revision: 1662016
URL: http://svn.apache.org/r1662016
Log:
Create '1.9.x-update-delete' branch based of the '1.9.x-commit-fixes' branch.
This backports the fixes of the 'make copy' operation, that creates a copy
of a working copy in its own place, to allow clearing the BASE layer
on an incoming delete or replace during update.
Before this patch-set, the copy didn't accurately describe mixed revision
copies and could leave half moves.
* subversion/libsvn_wc/wc-queries.sql (r1660742)
(STMT_DELETE_WORKING_BASE_DELETE): Make non-recursive.
(STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE): New query.
(STMT_INSERT_WORKING_NODE_FROM_BASE_COPY): Allow replacing
an existing node, but keep its moved_to.
* subversion/libsvn_wc/wc_db.c (r1661718, r1660742,...)
(db_base_remove): Improve shadowing detection. Always apply
moves, even when the caller doesn't want to introduce
a new conflict. Break moves that can't be represented.
Remove duplicated query.
(db_move_moved_to): New function. Moving moved-to from
one relpath-opdepth pair to another one.
(db_move_moved_to_down_recursive): New function, moving all
moved to information to another op-depth.
(make_copy_txn): Extend function to properly introduce
not-present nodes, and to keep move information valid.
(svn_wc__db_op_make_copy_internal): Add argument.
Update caller. Provide base-deleted layer before copying
to allow storing move information on it.
(svn_wc__db_op_make_copy): Update caller.
* subversion/libsvn_wc/wc_db_private.h (r1661591)
(svn_wc__db_op_make_copy_internal): Add argument.
* subversion/libsvn_wc/wc_db_update_move.c (r1661591)
(tc_editor_delete): Update caller.
* subversion/tests/cmdline/tree_conflict_tests.py (r1660742)
(update_delete_mixed_rev): Remove XFail. Tweak node status.
* subversion/tests/libsvn_wc/op-depth-test.c (r1660742)
(make_copy_mixed,
make_copy_and_delete_mixed): New functions.
(test_funcs): Add new functions.
Added:
subversion/branches/1.9.x-update-delete/ (props changed)
- copied from r1662010, subversion/branches/1.9.x-commit-fixes/
Modified:
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc-queries.sql
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db.c
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_private.h
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_update_move.c
subversion/branches/1.9.x-update-delete/subversion/tests/cmdline/tree_conflict_tests.py
subversion/branches/1.9.x-update-delete/subversion/tests/libsvn_wc/op-depth-test.c
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
--- bugtraq:logregex (added)
+++ bugtraq:logregex Tue Feb 24 16:44:59 2015
@@ -0,0 +1,2 @@
+[Ii]ssues?:?(\s*(,|and)?\s*#\d+)+
+(\d+)
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
bugtraq:url = http://subversion.tigris.org/issues/show_bug.cgi?id=%BUGID%
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
--- svn:auto-props (added)
+++ svn:auto-props Tue Feb 24 16:44:59 2015
@@ -0,0 +1,13 @@
+*.c = svn:eol-style=native
+*.cpp = svn:eol-style=native
+*.h = svn:eol-style=native
+*.hpp = svn:eol-style=native
+*.java = svn:eol-style=native
+*.py = svn:eol-style=native
+*.pl = svn:eol-style=native
+*.rb = svn:eol-style=native
+*.sql = svn:eol-style=native
+*.txt = svn:eol-style=native
+README = svn:eol-style=native
+BRANCH-README = svn:eol-style=native
+STATUS = svn:eol-style=native
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Feb 24 16:44:59 2015
@@ -0,0 +1,57 @@
+ChangeLog*
+Makefile
+config.cache
+config.log
+config.nice
+config.status
+configure
+libtool
+.gdb_history
+.swig_checked
+*.orig
+*.rej
+TAGS
+tags
+neon
+build-outputs.mk
+autogen-standalone.mk
+autom4te.cache
+gen-make.opts
+tests.log*
+fails.log*
+db4-win32
+db
+*.o
+*~
+.*~
+apr
+apr-util
+apr-iconv
+Release
+Debug
+ipch
+subversion_msvc.dsw
+subversion_msvc.ncb
+subversion_msvc.opt
+subversion_msvc.plg
+subversion_vcnet.sln
+subversion_vcnet.ncb
+subversion_vcnet.suo
+subversion_vcnet.v11.suo
+subversion_vcnet.sdf
+subversion_vcnet.opensdf
+mkmf.log
+.project
+.classpath
+.cdtproject
+.settings
+.cproject
+zlib
+sqlite-amalgamation
+serf
+gmock-fused
+.git
+.gitignore
+compile_commands.json
+.kdev4
+*.kdev4
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
--- svn:mergeinfo (added)
+++ svn:mergeinfo Tue Feb 24 16:44:59 2015
@@ -0,0 +1,92 @@
+/subversion/branches/1.5.x-r30215:870312
+/subversion/branches/1.7.x-fs-verify:1146708,1161180
+/subversion/branches/10Gb:1388102,1388163-1388190,1388195,1388202,1388205,1388211,1388276,1388362,1388375,1388394,1388636,1388639-1388640,1388643-1388644,1388654,1388720,1388789,1388795,1388801,1388805,1388807,1388810,1388816,1389044,1389276,1389289,1389662,1389867,1390017,1390209,1390216,1390407,1390409,1390414,1390419,1390955
+/subversion/branches/atomic-revprop:965046-1000689
+/subversion/branches/authzperf:1615360
+/subversion/branches/auto-props-sdc:1384106-1401643
+/subversion/branches/bdb-reverse-deltas:872050-872529
+/subversion/branches/cache-server:1458643-1476567
+/subversion/branches/diff-callbacks3:870059-870761
+/subversion/branches/diff-optimizations:1031270-1037352
+/subversion/branches/diff-optimizations-bytes:1037353-1067789
+/subversion/branches/dont-save-plaintext-passwords-by-default:870728-871118
+/subversion/branches/double-delete:870511-872970
+/subversion/branches/dump-load-cross-check:1654853-1657295
+/subversion/branches/ev2-export:1325914,1332738,1413107
+/subversion/branches/explore-wc:875486,875493,875497,875507,875511,875514,875559,875580-875581,875584,875587,875611,875627,875647,875667-875668,875711-875712,875733-875734,875736,875744-875748,875751,875758,875782,875795-875796,875830,875836,875838,875842,875852,875855,875864,875870,875873,875880,875885-875888,875890,875897-875898,875905,875907-875909,875935,875943-875944,875946,875979,875982-875983,875985-875986,875990,875997
+/subversion/branches/file-externals:871779-873302
+/subversion/branches/fs-rep-sharing:869036-873803
+/subversion/branches/fsfs-format7:1426304,1430673,1433848,1438408,1438982,1441129,1442051,1442068,1442504,1442910,1443171,1443803,1444690,1444693,1444695,1445040,1445080,1446103,1451129,1453590,1454307,1460579,1461851,1461865,1462837,1462904,1463120,1467362,1467382,1469487,1471208,1477166,1478055,1481447,1489817,1489949,1490673-1490674,1491784,1493042,1498029,1498103,1498155,1500054,1507729-1507731,1507735-1507736
+/subversion/branches/fsfs-improvements:1499981-1547039
+/subversion/branches/fsfs-lock-many:1571740-1577217
+/subversion/branches/fsfs-pack:873717-874575
+/subversion/branches/fsx:1507845-1509914
+/subversion/branches/fsx-id:1645603-1649011
+/subversion/branches/gnome-keyring:870558-871410
+/subversion/branches/gpg-agent-password-store:1005036-1150766
+/subversion/branches/gtest_addition:1452117-1502138
+/subversion/branches/http-protocol-v2:874395-876041
+/subversion/branches/in-memory-cache:869829-871452
+/subversion/branches/in-repo-authz:1414342-1424779
+/subversion/branches/inheritable-props:1297080-1395089
+/subversion/branches/integrate-cache-item-serialization:1068724-1068739
+/subversion/branches/integrate-cache-membuffer:998649-998852
+/subversion/branches/integrate-compression-level:1068651-1072287
+/subversion/branches/integrate-io-improvements:1068684-1072297
+/subversion/branches/integrate-is-cachable:1072568-1074082
+/subversion/branches/integrate-partial-getter:1072558-1076552
+/subversion/branches/integrate-readline-speedup:1072553-1072555
+/subversion/branches/integrate-stream-api-extensions:1068695-1072516
+/subversion/branches/integrate-string-improvements:1068251-1190617
+/subversion/branches/integrate-txdelta-caching:1072541-1078213
+/subversion/branches/issue-2779-dev:965496-984198
+/subversion/branches/issue-2843-dev:871432-874179
+/subversion/branches/issue-3000:871713,871716-871719,871721-871726,871728,871734
+/subversion/branches/issue-3067-deleted-subtrees:873375-874084
+/subversion/branches/issue-3148-dev:875193-875204
+/subversion/branches/issue-3220-dev:872210-872226
+/subversion/branches/issue-3242-dev:879653-896436
+/subversion/branches/issue-3334-dirs:875156-875867
+/subversion/branches/issue-3975:1152931-1160746
+/subversion/branches/issue-4116-dev:1424719-1425040
+/subversion/branches/issue-4194-dev:1410507-1414880
+/subversion/branches/javahl-ra:991978-1494640
+/subversion/branches/kwallet:870785-871314
+/subversion/branches/log-addressing:1509279-1546844
+/subversion/branches/log-g-performance:870941-871032
+/subversion/branches/merge-skips-obstructions:874525-874615
+/subversion/branches/move-tracking-2:1607334
+/subversion/branches/multi-layer-moves:1239019-1300930
+/subversion/branches/nfc-nfd-aware-client:870276,870376
+/subversion/branches/node_pool:1304828-1305388
+/subversion/branches/performance:979193,980118,981087,981090,981189,981194,981287,981684,981827,982043,982355,983398,983406,983430,983474,983488,983490,983760,983764,983766,983770,984927,984973,984984,985014,985037,985046,985472,985477,985482,985487-985488,985493,985497,985500,985514,985601,985603,985606,985669,985673,985695,985697,986453,986465,986485,986491-986492,986517,986521,986605,986608,986817,986832,987865,987868-987869,987872,987886-987888,987893,988319,988898,990330,990533,990535-990537,990541,990568,990572,990574-990575,990600,990759,992899,992904,992911,993127,993141,994956,995478,995507,995603,998012,998858,999098,1001413,1001417,1004291,1022668,1022670,1022676,1022715,1022719,1025660,1025672,1027193,1027203,1027206,1027214,1027227,1028077,1028092,1028094,1028104,1028107,1028111,1028354,1029038,1029042-1029043,1029054-1029055,1029062-1029063,1029078,1029080,1029090,1029092-1029093,1029111,1029151,1029158,1029229-1029230,1029232,1029335-1029336,1029339-1029340,1029342,10
29344,1030763,1030827,1031203,1031235,1032285,1032333,1033040,1033057,1033294,1035869,1035882,1039511,1043705,1053735,1056015,1066452,1067683,1067697-1078365
+/subversion/branches/pin-externals:1643757-1659392
+/subversion/branches/py-tests-as-modules:956579-1033052
+/subversion/branches/ra_serf-digest-authn:875693-876404
+/subversion/branches/reintegrate-improvements:873853-874164
+/subversion/branches/remote-only-status:1581845-1586090
+/subversion/branches/revprop-cache:1298521-1326293
+/subversion/branches/revprop-caching-ng:1620597,1620599
+/subversion/branches/revprop-packing:1143907,1143971,1143997,1144017,1144499,1144568,1146145
+/subversion/branches/subtree-mergeinfo:876734-878766
+/subversion/branches/svn-auth-x509:1603509-1655900
+/subversion/branches/svn-info-detail:1660035-1660413
+/subversion/branches/svn-mergeinfo-enhancements:870119-870195,870197-870288
+/subversion/branches/svn-patch-improvements:918519-934609
+/subversion/branches/svn_mutex:1141683-1182099
+/subversion/branches/svnpatch-diff:865738-876477
+/subversion/branches/svnraisetc:874709-875149
+/subversion/branches/svnserve-logging:869828-870893
+/subversion/branches/tc-issue-3334:874697-874773
+/subversion/branches/tc-merge-notify:874017-874062
+/subversion/branches/tc-resolve:874191-874239
+/subversion/branches/tc_url_rev:874351-874483
+/subversion/branches/tree-conflicts:868291-873154
+/subversion/branches/tree-conflicts-notify:873926-874008
+/subversion/branches/tristate-chunked-request:1502394-1502681
+/subversion/branches/tweak-build-take-two:1424288-1425049,1425051-1425613
+/subversion/branches/uris-as-urls:1060426-1064427
+/subversion/branches/verify-at-commit:1462039-1462408
+/subversion/branches/verify-keep-going:1439280-1546110
+/subversion/branches/wc-collate-path:1402685-1480384
+/subversion/trunk:1660587,1660610,1660633,1660641,1660659,1660671,1660687,1660742,1660758,1660781,1660874,1660928,1660955,1660961,1661335,1661363,1661504,1661671,1661718,1661730,1661755,1661890
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
tsvn:logwidthmarker = 78
Propchange: subversion/branches/1.9.x-update-delete/
------------------------------------------------------------------------------
webviewer:revision = http://svn.apache.org/r%REVISION%
Modified:
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc-queries.sql
URL:
http://svn.apache.org/viewvc/subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc-queries.sql?rev=1662016&r1=1662010&r2=1662016&view=diff
==============================================================================
--- subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc-queries.sql
(original)
+++ subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc-queries.sql
Tue Feb 24 16:44:59 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
@@ -1012,15 +1022,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/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db.c?rev=1662016&r1=1662010&r2=1662016&view=diff
==============================================================================
--- subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db.c
(original)
+++ subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db.c Tue
Feb 24 16:44:59 2015
@@ -2230,6 +2230,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
const char *repos_relpath;
svn_node_kind_t kind;
svn_boolean_t keep_working;
+ int op_depth;
+ svn_node_kind_t wrk_kind;
+ svn_boolean_t no_delete_wc = FALSE;
SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, NULL,
&repos_relpath, &repos_id,
@@ -2248,28 +2251,55 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
SVN_ERR(svn_sqlite__step_done(lock_stmt));
}
- if (status == svn_wc__db_status_normal
- && keep_as_working)
+ /* Check if there is already a working node */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_NODE_INFO));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (!have_row)
+ return svn_error_trace(svn_sqlite__reset(stmt)); /* No BASE */
+
+ op_depth = svn_sqlite__column_int(stmt, 0);
+ wrk_kind = svn_sqlite__column_token(stmt, 4, kind_map);
+
+ if (op_depth > 0
+ && op_depth == relpath_depth(local_relpath))
{
- SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath,
- NULL, NULL,
- scratch_pool));
- keep_working = TRUE;
+ svn_wc__db_status_t presence;
+ presence = svn_sqlite__column_token(stmt, 3, presence_map);
+
+ if (presence == svn_wc__db_status_base_deleted)
+ {
+ keep_working = FALSE;
+ no_delete_wc = TRUE;
+ }
+ else
+ {
+ keep_working = TRUE;
+ }
}
else
+ keep_working = FALSE;
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ if (keep_as_working && op_depth == 0)
{
- /* Check if there is already a working node */
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&keep_working, stmt));
- SVN_ERR(svn_sqlite__reset(stmt));
+ if (status == svn_wc__db_status_normal
+ || status == svn_wc__db_status_incomplete)
+ {
+ SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath, TRUE,
+ NULL, NULL,
+ scratch_pool));
+ }
+ keep_working = TRUE;
}
/* Step 1: Create workqueue operations to remove files and dirs in the
local-wc */
if (!keep_working
&& queue_deletes
+ && !no_delete_wc
&& (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_incomplete))
{
@@ -2278,11 +2308,11 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
scratch_pool);
- if (kind == svn_node_dir)
+ if (wrk_kind == svn_node_dir)
{
apr_pool_t *iterpool;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_BASE_PRESENT));
+ STMT_SELECT_WORKING_PRESENT));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
iterpool = svn_pool_create(scratch_pool);
@@ -2361,27 +2391,12 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
ACTUAL_NODE records */
/* Step 3: Delete WORKING nodes */
- if (conflict)
+ if (!keep_working)
{
apr_pool_t *iterpool;
- /*
- * When deleting a conflicted node, moves of any moved-outside children
- * of the node must be broken. Else, the destination will still be marked
- * moved-here after the move source disappears from the working copy.
- *
- * ### FIXME: It would be nicer to have the conflict resolver
- * break the move instead. It might also be a good idea to
- * flag a tree conflict on each moved-away child. But doing so
- * might introduce actual-only nodes without direct parents,
- * and we're not yet sure if other existing code is prepared
- * to handle such nodes. To be revisited post-1.8.
- *
- * ### In case of a conflict we are most likely creating WORKING nodes
- * describing a copy of what was in BASE. The move information
- * should be updated to describe a move from the WORKING layer.
- * When stored that way the resolver of the tree conflict still has
- * the knowledge of what was moved.
+ /* When deleting everything in working we should break moves from
+ here and to here.
*/
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_MOVED_OUTSIDE));
@@ -2405,10 +2420,52 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
svn_pool_destroy(iterpool);
SVN_ERR(svn_sqlite__reset(stmt));
}
- if (keep_working)
+ else
{
+ /* We are keeping things that are in WORKING, but we should still
+ break moves of things in BASE. (Mixed revisions make it
+ impossible to guarantee that we can keep everything moved) */
+
+ apr_pool_t *iterpool;
+
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_WORKING_BASE_DELETE));
+ STMT_SELECT_MOVED_DESCENDANTS_SRC));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+ local_relpath, 0));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ iterpool = svn_pool_create(scratch_pool);
+ while (have_row)
+ {
+ int delete_op_depth = svn_sqlite__column_int(stmt, 0);
+ const char *src_relpath;
+ const char *dst_relpath;
+ svn_error_t *err;
+
+ svn_pool_clear(iterpool);
+
+ src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+ dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
+
+ err = svn_wc__db_op_break_move_internal(wcroot, src_relpath,
+ delete_op_depth,
+ dst_relpath,
+ NULL,
+ iterpool);
+
+ if (err)
+ return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+ svn_pool_destroy(iterpool);
+ SVN_ERR(svn_sqlite__reset(stmt));
+ }
+
+ if (keep_working)
+ {
+ 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));
}
@@ -2434,15 +2491,6 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, scratch_pool));
- /* Step 6: Delete actual node if we don't keep working */
- if (! keep_working)
- {
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_DELETE_ACTUAL_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step_done(stmt));
- }
-
if (SVN_IS_VALID_REVNUM(not_present_revision))
{
struct insert_base_baton_t ibb;
@@ -15042,6 +15090,87 @@ svn_wc__db_temp_op_start_directory_updat
return SVN_NO_ERROR;
}
+/* Helper for svn_wc__db_op_make_copy_internal */
+static svn_error_t *
+db_move_moved_to(svn_wc__db_wcroot_t *wcroot,
+ const char *src1_relpath,
+ int src1_op_depth,
+ const char *src2_relpath,
+ int src2_op_depth,
+ const char *dst_relpath,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ int affected_rows;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_UPDATE_MOVED_TO_RELPATH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+ src1_relpath, src1_op_depth));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ if (affected_rows == 1)
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_UPDATE_MOVED_TO_RELPATH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id,
+ src2_relpath, src2_op_depth,
+ dst_relpath));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+ }
+ if (affected_rows != 1)
+ return svn_error_create(SVN_ERR_WC_PATH_NOT_FOUND, NULL, NULL);
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+db_move_moved_to_down_recursive(svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int new_shadow_layer,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ 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,
+ new_shadow_layer));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ while (have_row)
+ {
+ int del_op_depth;
+ const char *src_relpath;
+ const char *dst_relpath;
+ svn_error_t *err;
+
+ svn_pool_clear(iterpool);
+
+ del_op_depth = svn_sqlite__column_int(stmt, 0);
+ src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+ dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
+
+ err = svn_error_trace(
+ db_move_moved_to(
+ wcroot,
+ src_relpath, del_op_depth,
+ src_relpath, new_shadow_layer,
+ dst_relpath, iterpool));
+
+ if (err)
+ return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
+
/* The body of svn_wc__db_temp_op_make_copy(). This is
used by the update editor when deleting a base node tree would be a
@@ -15079,98 +15208,148 @@ 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,
+ int root_shadow_depth,
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);
+ 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));
- /* 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;
+ 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 (working_status == svn_wc__db_status_base_deleted)
- remove_working = TRUE;
- }
+ 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)
+ /* 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_DELETE_LOWEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step_done(stmt));
- }
+ int i;
- if (add_working_base_deleted)
- {
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_INSERT_DELETE_FROM_BASE));
+ 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, root_shadow_depth,
+ 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(db_move_moved_to_down_recursive(wcroot, local_relpath,
+ root_shadow_depth,
+ scratch_pool));
+
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));
+ /* Insert a not-present node to mark that we don't know what exists here.
- for (i = 0; i < children->nelts; i++)
+ We do this last (after recursing), to allow the move fix-up code to
+ see the original moves. */
+ if (last_op_depth > 0 && last_op_depth != op_depth)
{
- const char *name = APR_ARRAY_IDX(children, i, const char *);
- const char *copy_relpath;
+ insert_working_baton_t iwb;
- svn_pool_clear(iterpool);
+ blank_iwb(&iwb);
+ iwb.presence = svn_wc__db_status_not_present;
+ iwb.op_depth = last_op_depth;
- copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
+ iwb.original_repos_id = repos_id;
+ iwb.original_repos_relpath = repos_relpath;
+ iwb.original_revnum = revision;
+ iwb.kind = kind;
- SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, iterpool));
+ SVN_ERR(insert_working_node(&iwb, wcroot, local_relpath, scratch_pool));
}
- svn_pool_destroy(iterpool);
-
return SVN_NO_ERROR;
}
+
svn_error_t *
svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_boolean_t move_move_info,
const svn_skel_t *conflicts,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
@@ -15209,12 +15388,36 @@ svn_wc__db_op_make_copy_internal(svn_wc_
}
else
{
+ 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,
+ scratch_pool));
+
+ /* 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);
+
+ if (!move_move_info)
+ SVN_ERR(db_move_moved_to_down_recursive(wcroot, local_relpath,
+ op_depth, scratch_pool));
+
SVN_ERR(make_copy_txn(wcroot, local_relpath,
- relpath_depth(local_relpath), scratch_pool));
+ INVALID_REPOS_ID, NULL, SVN_INVALID_REVNUM,
+ op_depth, FALSE, op_depth,
+ scratch_pool));
}
if (conflicts)
@@ -15244,7 +15447,8 @@ svn_wc__db_op_make_copy(svn_wc__db_t *db
VERIFY_USABLE_WCROOT(wcroot);
SVN_WC__DB_WITH_TXN(
- svn_wc__db_op_make_copy_internal(wcroot, local_relpath, conflicts,
work_items,
+ svn_wc__db_op_make_copy_internal(wcroot, local_relpath, FALSE,
+ conflicts, work_items,
scratch_pool),
wcroot);
Modified:
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_private.h
URL:
http://svn.apache.org/viewvc/subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_private.h?rev=1662016&r1=1662010&r2=1662016&view=diff
==============================================================================
---
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_private.h
(original)
+++
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_private.h
Tue Feb 24 16:44:59 2015
@@ -400,6 +400,7 @@ svn_wc__db_op_copy_layer_internal(svn_wc
svn_error_t *
svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_boolean_t move_move_info,
const svn_skel_t *conflicts,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool);
Modified:
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_update_move.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_update_move.c?rev=1662016&r1=1662010&r2=1662016&view=diff
==============================================================================
---
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_update_move.c
(original)
+++
subversion/branches/1.9.x-update-delete/subversion/libsvn_wc/wc_db_update_move.c
Tue Feb 24 16:44:59 2015
@@ -1242,7 +1242,7 @@ tc_editor_delete(node_move_baton_t *nmb,
* it is not the/an op-root. (or we can't make us a copy)
*/
- SVN_ERR(svn_wc__db_op_make_copy_internal(b->wcroot, relpath,
+ SVN_ERR(svn_wc__db_op_make_copy_internal(b->wcroot, relpath, FALSE,
NULL, NULL, scratch_pool));
reason = svn_wc_conflict_reason_edited;
Modified:
subversion/branches/1.9.x-update-delete/subversion/tests/cmdline/tree_conflict_tests.py
URL:
http://svn.apache.org/viewvc/subversion/branches/1.9.x-update-delete/subversion/tests/cmdline/tree_conflict_tests.py?rev=1662016&r1=1662010&r2=1662016&view=diff
==============================================================================
---
subversion/branches/1.9.x-update-delete/subversion/tests/cmdline/tree_conflict_tests.py
(original)
+++
subversion/branches/1.9.x-update-delete/subversion/tests/cmdline/tree_conflict_tests.py
Tue Feb 24 16:44:59 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/branches/1.9.x-update-delete/subversion/tests/libsvn_wc/op-depth-test.c
URL:
http://svn.apache.org/viewvc/subversion/branches/1.9.x-update-delete/subversion/tests/libsvn_wc/op-depth-test.c?rev=1662016&r1=1662010&r2=1662016&view=diff
==============================================================================
---
subversion/branches/1.9.x-update-delete/subversion/tests/libsvn_wc/op-depth-test.c
(original)
+++
subversion/branches/1.9.x-update-delete/subversion/tests/libsvn_wc/op-depth-test.c
Tue Feb 24 16:44:59 2015
@@ -11128,6 +11128,338 @@ 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));
+ }
+
+ SVN_ERR(verify_db(&b));
+
+ 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, "H"},
+ {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));
+ }
+
+ SVN_ERR(verify_db(&b));
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
test_global_commit(const svn_test_opts_t *opts, apr_pool_t *pool)
{
@@ -11469,6 +11801,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_PASS(make_copy_and_delete_mixed,
+ "make a copy of a mixed revision tree and del"),
SVN_TEST_OPTS_PASS(test_global_commit,
"test global commit"),
SVN_TEST_NULL