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


Reply via email to