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