Issue #2153 is a simple bug:
   If you have a mixed-rev working copy, in which .svn/entries has an
   entry E marked as 'deleted', but E's parent is still at a revision
   from before E's deletion, then if you do 'svn cp my_wc new_url',
   the new_url will still contain E.  This is because the deleted
   entry is never even seen by harvest_committables(), and therefore
   no editor->delete() command is ever given to remove it from the
   txn.
I thought it would have a simple fix, too, but my simple fix is
causing other regression tests to fail.  I need to continue with an
issues sweep right now, so I'm posting my patch here in case anyone's
able to spot the problem quickly.
[[[
Fix issue #2153: wc-to-url copies would wrongly include deleted items.
Thanks to Ben Collins-Sussman for various helpful hints.
    ##############################################################
    ###                                                        ###
    ###  Not ready for commit yet.  The new regression test    ###
    ###  passes, but these changes cause at least basic_tests  ###
    ###  25 and commit_tests 12 to fail.                       ###
    ###                                                        ###
    ##############################################################
* subversion/libsvn_client/commit_util.c
  (harvest_committables): If in copy_mode, request deleted entries
     too, and set the SVN_CLIENT_COMMIT_ITEM_DELETE flag on them.
* subversion/tests/clients/cmdline/copy_tests.py
  (mixed_wc_to_url): New test.
  (test_list): Run it.
]]]
Index: subversion/libsvn_client/commit_util.c
===================================================================
--- subversion/libsvn_client/commit_util.c	(revision 12355)
+++ subversion/libsvn_client/commit_util.c	(working copy)
@@ -162,8 +162,9 @@
    will not recurse into subdirectories of PATH when PATH is itself a
    directory.
 
-   If in COPY_MODE, the entry is treated as if it is destined to be
-   added with history as URL.
+   If in COPY_MODE, treat the entry as if it is destined to be added
+   with history as URL, and add 'deleted' entries to COMMITTABLES as
+   items to delete in the copy destination.
 
    If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to see 
    if the user has cancelled the operation.  */
@@ -249,7 +250,7 @@
          recurse anyway, so... ) */
       svn_error_t *err;
       const svn_wc_entry_t *e = NULL;
-      err = svn_wc_entries_read (&entries, adm_access, FALSE, pool);
+      err = svn_wc_entries_read (&entries, adm_access, copy_mode, pool);
 
       /* If we failed to get an entries hash for the directory, no
          sweat.  Cleanup and move along.  */
@@ -296,11 +297,20 @@
   if ((entry->url) && (! copy_mode))
     url = entry->url;
 
-  /* Check for the deletion case.  Deletes can occur only when we are
-     not in "adds-only mode".  They can be either explicit
-     (schedule == delete) or implicit (schedule == replace ::= delete+add).  */
+  /* Check for the deletion case.  Deletes occur only when not in
+     "adds-only mode".  We use the SVN_CLIENT_COMMIT_ITEM_DELETE flag
+     to represent two slightly different conditions:
+
+     - The entry is marked as 'deleted'.  When copying a mixed-rev wc,
+       we still need to send a delete for that entry, otherwise the
+       object will wrongly exist in the repository copy.
+
+     - The entry is scheduled for deletion or replacement, which case
+       we need to send a delete either way.
+  */
   if ((! adds_only)
-      && ((entry->schedule == svn_wc_schedule_delete)
+      && (entry->deleted
+          || (entry->schedule == svn_wc_schedule_delete)
           || (entry->schedule == svn_wc_schedule_replace)))
     {
       state_flags |= SVN_CLIENT_COMMIT_ITEM_DELETE;
@@ -327,6 +337,7 @@
 
   /* Check for the copied-subtree addition case.  */
   if ((entry->copied || copy_mode) 
+      && (! entry->deleted)
       && (entry->schedule == svn_wc_schedule_normal))
     {
       svn_revnum_t p_rev = entry->revision - 1; /* arbitrary non-equal value */
Index: subversion/tests/clients/cmdline/copy_tests.py
===================================================================
--- subversion/tests/clients/cmdline/copy_tests.py	(revision 12355)
+++ subversion/tests/clients/cmdline/copy_tests.py	(working copy)
@@ -1475,6 +1475,65 @@
                                          None, None, None, None, None,
                                          wc_dir)
 
+
+#----------------------------------------------------------------------
+
+def mixed_wc_to_url(sbox):
+  "copy a complex mixed-rev wc"
+
+  # For issue 2153.
+  #
+  # Copy a mixed-revision wc (that also has some uncommitted local
+  # mods, and an entry marked as 'deleted') to a URL.  Make sure the
+  # copy gets the uncommitted mods, and does not contain the deleted
+  # file.
+
+  sbox.build()
+
+  wc_dir = sbox.wc_dir
+  url = svntest.main.current_repo_url
+  G_url = svntest.main.current_repo_url + '/A/D/G'
+  Z_url = svntest.main.current_repo_url + '/A/D/Z'
+  G_path = os.path.join(wc_dir, 'A', 'D', 'G')
+  pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
+  rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
+
+  # Remove A/D/G/pi, then commit that removal.
+  svntest.actions.run_and_verify_svn(None, None, [], 'rm', pi_path)
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'ci', '-m', "Delete pi.", wc_dir)
+
+  # Make a modification to A/D/G/rho, then commit that modification.
+  svntest.main.file_append(rho_path, "\nFirst modification to rho.\n")
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'ci', '-m', "Modify rho.", wc_dir)
+
+  # Make another modification to A/D/G/rho, but don't commit it.
+  svntest.main.file_append(rho_path, "Second modification to rho.\n")
+
+  # Now copy local A/D/G to create new directory A/D/Z the repository.
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'cp', '-m', "Make a copy.",
+                                     G_path, Z_url)
+
+  # Check out A/D/Z.  If it has pi, that's a bug; or if its rho does
+  # not have the second local mod, that's also a bug.
+  svntest.main.safe_rmtree(wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'co', Z_url, wc_dir)
+  
+  if os.path.exists(os.path.join(wc_dir, 'pi')):
+    raise svntest.Failure
+
+  fp = open(os.path.join(wc_dir, 'rho'), 'r')
+  found_it = 0
+  for line in fp.readlines():
+    if re.match("^Second modification to rho.", line):
+      found_it = 1
+  if not found_it:
+    raise svntest.Failure
+
+
 ########################################################################
 # Run the tests
 
@@ -1505,6 +1564,7 @@
               repos_to_wc_1634,
               double_uri_escaping_1814,
               wc_to_wc_copy_deleted,
+              mixed_wc_to_url,
              ]
 
 if __name__ == '__main__':
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Dec 17 22:54:10 2004