You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/11/04 21:48:30 UTC

svn commit: r1031230 [17/21] - in /subversion/branches/py-tests-as-modules: ./ build/ build/ac-macros/ build/win32/ contrib/client-side/ notes/ notes/http-and-webdav/ notes/wc-ng/ subversion/bindings/ctypes-python/csvn/ subversion/bindings/javahl/nativ...

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/copy_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/copy_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/copy_tests.py Thu Nov  4 20:48:21 2010
@@ -3799,106 +3799,6 @@ def allow_unversioned_parent_for_copy_sr
                                      wc2_dir,
                                      copy_to_path)
 
-
-#----------------------------------------------------------------------
-# Issue #2986
-def replaced_local_source_for_incoming_copy(sbox):
-  "update receives copy, but local source is replaced"
-  sbox.build()
-  wc_dir = sbox.wc_dir
-  other_wc_dir = wc_dir + '-other'
-
-  # These paths are for regular content testing.
-  tau_path = os.path.join(wc_dir, 'A', 'D', 'G', 'tau')
-  rho_url = sbox.repo_url + '/A/D/G/rho'
-  pi_url = sbox.repo_url + '/A/D/G/pi'
-  other_G_path = os.path.join(other_wc_dir, 'A', 'D', 'G')
-  other_rho_path = os.path.join(other_G_path, 'rho')
-
-  # These paths are for properties testing.
-  H_path = os.path.join(wc_dir, 'A', 'D', 'H')
-  chi_path = os.path.join(H_path, 'chi')
-  psi_path = os.path.join(H_path, 'psi')
-  omega_path = os.path.join(H_path, 'omega')
-  psi_url = sbox.repo_url + '/A/D/H/psi'
-  chi_url = sbox.repo_url + '/A/D/H/chi'
-  other_H_path = os.path.join(other_wc_dir, 'A', 'D', 'H')
-  other_psi_path = os.path.join(other_H_path, 'psi')
-  other_omega_path = os.path.join(other_H_path, 'omega')
-
-  # Prepare for properties testing.  If the regular content bug
-  # reappears, we still want to be able to test for the property bug
-  # independently.  That means making two files have the same content,
-  # to avoid encountering the checksum error that might reappear in a
-  # regression.  So here we do that, as well as set the marker
-  # property that we'll check for later.  The reason to set the marker
-  # property in this commit, rather than later, is so that we pass the
-  # conditional in update_editor.c:locate_copyfrom() that compares the
-  # revisions.
-  svntest.main.file_write(chi_path, "Same contents for two files.\n")
-  svntest.main.file_write(psi_path, "Same contents for two files.\n")
-  svntest.actions.run_and_verify_svn(None, None, [], 'propset',
-                                     'chi-prop', 'chi-val', chi_path)
-  svntest.actions.run_and_verify_svn(None, None, [], 'ci',
-                                     '-m', 'identicalize contents', wc_dir);
-  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
-  # Make the duplicate working copy.
-  svntest.main.safe_rmtree(other_wc_dir)
-  shutil.copytree(wc_dir, other_wc_dir)
-
-  try:
-    ## Test properties. ##
-
-    # Commit a replacement from the first working copy.
-    svntest.actions.run_and_verify_svn(None, None, [], 'rm',
-                                       omega_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'cp',
-                                       psi_url, omega_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'ci',
-                                       '-m', 'a propset and a copy', wc_dir);
-
-    # Now schedule a replacement in the second working copy, then update
-    # to receive the replacement from the first working copy, with the
-    # source being the now-scheduled-replace file.
-    svntest.actions.run_and_verify_svn(None, None, [], 'rm',
-                                       other_psi_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'cp',
-                                       chi_url, other_psi_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'up',
-                                       other_wc_dir)
-    exit_code, output, errput = svntest.main.run_svn(None, 'proplist',
-                                                     '-v', other_omega_path)
-    if len(errput):
-      raise svntest.Failure("unexpected error output: %s" % errput)
-    if len(output):
-      raise svntest.Failure("unexpected properties found on '%s': %s"
-                            % (other_omega_path, output))
-
-    ## Test regular content. ##
-
-    # Commit a replacement from the first working copy.
-    svntest.actions.run_and_verify_svn(None, None, [], 'rm',
-                                       tau_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'cp',
-                                       rho_url, tau_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'ci',
-                                       '-m', 'copy rho to tau', wc_dir);
-
-    # Now schedule a replacement in the second working copy, then update
-    # to receive the replacement from the first working copy, with the
-    # source being the now-scheduled-replace file.
-    svntest.actions.run_and_verify_svn(None, None, [], 'rm',
-                                       other_rho_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'cp',
-                                       pi_url, other_rho_path);
-    svntest.actions.run_and_verify_svn(None, None, [], 'up',
-                                       other_wc_dir)
-
-  finally:
-    svntest.main.safe_rmtree(other_wc_dir)
-
-
 def unneeded_parents(sbox):
   "svn cp --parents FILE_URL DIR_URL"
 
@@ -4771,68 +4671,169 @@ def move_added_nodes(sbox):
   expected_status.add({'X/Z' : Item(status='A ', wc_rev='0')})
   svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
 
-def locate_wrong_origin(sbox):
-  "update editor locates invalid file source"
+def copy_over_deleted_dir(sbox):
+  "copy a directory over a deleted directory"
+  sbox.build(read_only = True)
+
+  main.run_svn(None, 'rm', os.path.join(sbox.wc_dir, 'A/B'))
+  main.run_svn(None, 'cp', os.path.join(sbox.wc_dir, 'A/D'),
+               os.path.join(sbox.wc_dir, 'A/B'))
 
+def mixed_rev_copy_del(sbox):
+  """copy mixed-rev and delete children"""
+  
   sbox.build()
+  wc_dir = sbox.wc_dir
 
-  iota = os.path.join(sbox.wc_dir, 'iota')
-  gamma = os.path.join(sbox.wc_dir, 'A/D/gamma')
+  # Delete and commit A/B/E/alpha
+  svntest.main.run_svn(None, 'rm', sbox.ospath('A/B/E/alpha'))
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/B/E/alpha', status='D ')
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E/alpha': Item(verb='Deleting'),
+    })
+  expected_status.remove('A/B/E/alpha')
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status,
+                                        None,
+                                        wc_dir)
 
-  D1 = os.path.join(sbox.wc_dir, 'D1')
-  D2 = os.path.join(sbox.wc_dir, 'D2')
+  # Update to r2, then update A/B/E/alpha and A/B/E/beta to r1
+  svntest.main.run_svn(None, 'up', wc_dir)
+  expected_status.tweak(wc_rev=2)
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+  svntest.main.run_svn(None, 'up', '-r1',
+                       sbox.ospath('A/B/E/alpha'),
+                       sbox.ospath('A/B/E/beta'))
+  expected_status.add({
+    'A/B/E/alpha' : Item(status='  ', wc_rev=1),
+    })
+  expected_status.tweak('A/B/E/beta', wc_rev=1)
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-  main.run_svn(None, 'mkdir', D1, D2)
-  main.run_svn(None, 'cp', iota, os.path.join(D1, 'iota'))
-  main.run_svn(None, 'cp', gamma, os.path.join(D2, 'iota'))
+  # Copy A/B/E to A/B/E_copy
+  svntest.actions.run_and_verify_svn(None, None, [], 'cp',
+                                     sbox.ospath('A/B/E'),
+                                     sbox.ospath('A/B/E_copy'))
+  expected_status.add({
+    'A/B/E_copy'       : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E_copy/alpha' : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E_copy/beta'  : Item(status='  ', copied='+', wc_rev='-'),
+    })
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-  main.run_svn(None, 'ci', sbox.wc_dir, '-m', 'Add 2*iotas in r2')
-  main.run_svn(None, 'rm', D1)
+  # Delete A/B/E_copy/alpha and A/B/E_copy/beta
+  svntest.main.run_svn(None, 'rm',
+                       sbox.ospath('A/B/E_copy/alpha'),
+                       sbox.ospath('A/B/E_copy/beta'))
+  expected_status.tweak('A/B/E_copy/alpha', 'A/B/E_copy/beta', status='D ')
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  # This test currently fails above, as both alpha and beta disappear
+  # from status, what should happen is unclear.  In 1.6 both names
+  # remained in status 'D'.
+
+  # The commit doesn't work either, it should not delete alpha but
+  # must delete beta.  In 1.6 both alpha and beta were deleted and the
+  # commit failed.  It's not clear how the client can determine that
+  # alpha and beta should be treated differently.
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E_copy'      : Item(verb='Adding'),
+    'A/B/E_copy/beta' : Item(verb='Deleting'),
+    })
+  expected_status.tweak('A/B/E_copy', wc_rev=3, copied=None)
+  expected_status.remove('A/B/E_copy/alpha', 'A/B/E_copy/beta')
+  svntest.actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status,
+                                        None,
+                                        wc_dir)
+def copy_delete_undo(sbox, use_revert):
+  "copy, delete child, undo"
 
-  main.run_svn(None, 'ci', sbox.wc_dir, '-m', 'Why?')
+  sbox.build()
+  wc_dir = sbox.wc_dir
 
-  main.run_svn(None, 'cp', D2, D1)
-  main.run_svn(None, 'ci', sbox.wc_dir, '-m', 'Replace one iota')
+  # Copy directory with children
+  svntest.main.run_svn(wc_dir, 'copy',
+                       sbox.ospath('A/B/E'), sbox.ospath('A/B/E-copied'))
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({
+    'A/B/E-copied'       : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E-copied/alpha' : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E-copied/beta'  : Item(status='  ', copied='+', wc_rev='-'),
+    })
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-  # <= 1.6 needs a new checkout here to reproduce, but not since r961831.
-  # so we just perform an update
-  main.run_svn(None, 'up', sbox.wc_dir)
+  # Delete a child
+  svntest.main.run_svn(wc_dir, 'rm', sbox.ospath('A/B/E-copied/alpha'))
+  expected_status.tweak('A/B/E-copied/alpha', status='D ', copied=None,
+                        wc_rev='?', entry_rev='1')
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-  main.run_svn(None, 'cp', sbox.repo_url + '/D1/iota@2',
-               sbox.repo_url + '/iobeta', '-m', 'Copy iota')
+  # Undo the whole copy
+  if (use_revert):
+    svntest.main.run_svn(wc_dir, 'revert', '--recursive',
+                         sbox.ospath('A/B/E-copied'))
+    svntest.main.safe_rmtree(os.path.join(wc_dir, 'A/B/E-copied'))
+  else:
+    svntest.main.run_svn(wc_dir, 'rm', '--force', sbox.ospath('A/B/E-copied'))
+  expected_status.remove('A/B/E-copied',
+                         'A/B/E-copied/alpha',
+                         'A/B/E-copied/beta')
 
+  # Undo via revert FAILs here because a wq item remains
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 4)
+  # Copy a directory without children.
+  svntest.main.run_svn(wc_dir, 'copy',
+                       sbox.ospath('A/B/F'), sbox.ospath('A/B/E-copied'))
   expected_status.add({
-    'D1'                : Item(status='  ', wc_rev='4'),
-    'D1/iota'           : Item(status='  ', wc_rev='4'),
-    'D2'                : Item(status='  ', wc_rev='4'),
-    'D2/iota'           : Item(status='  ', wc_rev='4'),
-  })
-  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+    'A/B/E-copied'       : Item(status='A ', copied='+', wc_rev='-'),
+    })
 
-  # The next update receives an add_file('/D1/iota', 2), which it then tries
-  # to locate in the local working copy. It finds a '/D1/iota' in the expected
-  # place, with a last-changed revision of 2 and a local revision of HEAD-1
-  #
-  # locate_copyfrom identifies this file as correct because 
-  #     * last-mod <= 2 and
-  #     * 2 <= REV
-  #
-  # Luckily close_file() receives an expected_checksum which makes us fail, or
-  # we would have a completely broken working copy
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
-  # So this gives a Checksum mismatch error.
-  main.run_svn(None, 'up', sbox.wc_dir)
+def copy_delete_delete(sbox):
+  "copy, delete child, delete copy"
+  copy_delete_undo(sbox, False)
+
+def copy_delete_revert(sbox):
+  "copy, delete child, revert copy"
+  copy_delete_undo(sbox, True)
 
-# This test currently fails, but should work ok once we move to single DB
-def copy_over_deleted_dir(sbox):
-  "copy a directory over a deleted directory"
-  sbox.build(read_only = True)
+def delete_replace_delete(sbox):
+  "delete, replace, delete"
 
-  main.run_svn(None, 'rm', os.path.join(sbox.wc_dir, 'A/B'))
-  main.run_svn(None, 'cp', os.path.join(sbox.wc_dir, 'A/D'),
-               os.path.join(sbox.wc_dir, 'A/B'))
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Delete directory with children
+  svntest.main.run_svn(wc_dir, 'rm', sbox.ospath('A/B/E'))
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ')
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  # Replace with directory with different children
+  svntest.main.run_svn(wc_dir, 'copy',
+                       sbox.ospath('A/D/G'), sbox.ospath('A/B/E'))
+  expected_status.tweak('A/B/E', status='R ', copied='+', wc_rev='-')
+  expected_status.add({
+    'A/B/E/pi' : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E/rho' : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E/tau' : Item(status='  ', copied='+', wc_rev='-'),
+    })
+  # A/B/E/alpha and A/B/E/beta show up as deleted, is that right?
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  # Delete replacement
+  svntest.main.run_svn(wc_dir, 'rm', '--force', sbox.ospath('A/B/E'))
+  expected_status.tweak('A/B/E', status='D ', copied=None, wc_rev='1')
+  expected_status.remove('A/B/E/pi', 'A/B/E/rho', 'A/B/E/tau')
+  # Currently fails because pi, rho, tau get left behind
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 
 ########################################################################
@@ -4910,7 +4911,6 @@ test_list = [ None,
               copy_make_parents_repo_repo,
               URI_encoded_repos_to_wc,
               allow_unversioned_parent_for_copy_src,
-              replaced_local_source_for_incoming_copy,
               unneeded_parents,
               double_parents_with_url,
               copy_into_absent_dir,
@@ -4929,10 +4929,11 @@ test_list = [ None,
               changed_data_should_match_checkout,
               XFail(changed_dir_data_should_match_checkout),
               move_added_nodes,
-              # Serf needs a different testcase for this issue
-              XFail(Skip(locate_wrong_origin,
-                         svntest.main.is_ra_type_dav_serf)),
               copy_over_deleted_dir,
+              XFail(mixed_rev_copy_del),
+              copy_delete_delete,
+              XFail(copy_delete_revert),
+              delete_replace_delete,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/diff_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/diff_tests.py Thu Nov  4 20:48:21 2010
@@ -2409,8 +2409,12 @@ def diff_repos_wc_add_with_props(sbox):
   diff_X_bar_base_r3 = make_diff_header("X/bar", "revision 0",
                                                  "revision 3") + diff_X_bar
 
-  expected_output_r1_base = diff_X_r1_base + diff_X_bar_r1_base + diff_foo_r1_base
-  expected_output_base_r3 = diff_foo_base_r3 + diff_X_bar_base_r3 + diff_X_base_r3
+  expected_output_r1_base = svntest.verify.UnorderedOutput(diff_X_r1_base +
+                                                           diff_X_bar_r1_base +
+                                                           diff_foo_r1_base)
+  expected_output_base_r3 = svntest.verify.UnorderedOutput(diff_foo_base_r3 +
+                                                           diff_X_bar_base_r3 +
+                                                           diff_X_base_r3)
 
   os.chdir(sbox.wc_dir)
 

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/export_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/export_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/export_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/export_tests.py Thu Nov  4 20:48:21 2010
@@ -621,6 +621,36 @@ def export_externals_with_native_eol(sbo
                                         expected_disk,
                                         '--native-eol', 'CR')
 
+def export_to_current_dir(sbox):
+  "export to current dir"
+  # Issue 3727: Forced export in current dir creates unexpected subdir.
+  sbox.build(create_wc = False, read_only = True)
+
+  svntest.main.safe_rmtree(sbox.wc_dir)
+  os.mkdir(sbox.wc_dir)
+
+  orig_dir = os.getcwd()
+  os.chdir(sbox.wc_dir)
+
+  export_url = sbox.repo_url + '/A/B/E'
+  export_target = '.'
+  expected_output = svntest.wc.State('', {
+    '.'         : Item(status='A '),
+    'alpha'     : Item(status='A '),
+    'beta'      : Item(status='A '),
+    })
+  expected_disk = svntest.wc.State('', {
+    'alpha'     : Item("This is the file 'alpha'.\n"),
+    'beta'      : Item("This is the file 'beta'.\n"),
+    })
+  svntest.actions.run_and_verify_export(export_url,
+                                        export_target,
+                                        expected_output,
+                                        expected_disk,
+                                        '--force')
+
+  os.chdir(orig_dir)
+
 ########################################################################
 # Run the tests
 
@@ -650,6 +680,7 @@ test_list = [ None,
               export_with_url_unsafe_characters,
               XFail(export_working_copy_with_depths),
               export_externals_with_native_eol,
+              export_to_current_dir,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn--help_stdout Thu Nov  4 20:48:21 2010
@@ -36,6 +36,7 @@ Available subcommands:
    propget (pget, pg)
    proplist (plist, pl)
    propset (pset, ps)
+   relocate
    resolve
    resolved
    revert

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout Thu Nov  4 20:48:21 2010
@@ -50,19 +50,16 @@ Valid options:
                              history
   -c [--change] ARG        : the change made in revision ARG
   --targets ARG            : pass contents of file ARG as additional args
-  --stop-on-copy           : do not cross copies while traversing history
-                             [alias: --soc]
+  --stop-on-copy [--soc]   : do not cross copies while traversing history
   --incremental            : give output suitable for concatenation
   --xml                    : output in XML
   -l [--limit] ARG         : maximum number of log entries
   --with-all-revprops      : retrieve all revision properties
   --with-no-revprops       : retrieve no revision properties
   --with-revprop ARG       : retrieve revision property ARG
-  --show-diff              : produce diff output
-                             [alias: --diff]
+  --diff                   : produce diff output
   --diff-cmd ARG           : use ARG as diff command
-  --internal-diff          : override diff-cmd specified in config file
-                             [alias: --idiff]
+  --internal-diff [--idiff] : override diff-cmd specified in config file
   -x [--extensions] ARG    : Default: '-u'. When Subversion is invoking an
                              external diff program, ARG is simply passed along
                              to the program. But when Subversion is using its
@@ -83,21 +80,19 @@ Valid options:
 Global options:
   --username ARG           : specify a username ARG
   --password ARG           : specify a password ARG
-  --no-auth-cache          : do not cache authentication tokens
-                             [alias: --nac]
+  --no-auth-cache [--nac]  : do not cache authentication tokens
   --non-interactive        : do no interactive prompting
   --trust-server-cert      : accept unknown SSL server certificates without
                              prompting (but only with '--non-interactive')
-  --config-dir ARG         : read user configuration files from directory ARG
-                             [alias: --cd]
+  --config-dir [--cd] ARG  : read user configuration files from directory ARG
   --config-option ARG      : set user configuration option in the format:
                                  FILE:SECTION:OPTION=[VALUE]
                              For example:
                                  servers:global:http-library=serf
 
-switch (sw): Update the working copy to a different URL.
+switch (sw): Update the working copy to a different URL within the same repository.
 usage: 1. switch URL[@PEGREV] [PATH]
-       2. switch --relocate FROM TO [PATH...]
+       2. switch --relocate FROM-PREFIX TO-PREFIX [PATH...]
 
   1. Update the working copy to mirror a new URL within the repository.
      This behavior is similar to 'svn update', and is the way to
@@ -119,22 +114,15 @@ usage: 1. switch URL[@PEGREV] [PATH]
      Use the --set-depth option to set a new working copy depth on the
      targets of this operation.
 
-  2. Rewrite working copy URL metadata to reflect a syntactic change only.
-     This is used when repository's root URL changes (such as a scheme
-     or hostname change) but your working copy still reflects the same
-     directory within the same repository.
-
-     FROM is the root URL which will be relocated from.
-     You can use 'svn info' to determine the root URL of the current
-     working copy directory (look for 'URL:' in its output).
-
-     TO is the root URL which will be relocated to.
+  2. The '--relocate' option is deprecated. This syntax is equivalent to
+     'svn relocate FROM-PREFIX TO-PREFIX [PATH]'.
 
   See also 'svn help update' for a list of possible characters
   reporting the action taken.
 
   Examples:
     svn switch ^/branches/1.x-release
+    svn switch --relocate http:// svn://
     svn switch --relocate http://www.example.com/repo/project \
                           svn://svn.example.com/repo/project
 
@@ -149,31 +137,27 @@ Valid options:
                                 'PREV'       revision just before COMMITTED
   -N [--non-recursive]     : obsolete; try --depth=files or --depth=immediates
   --depth ARG              : limit operation by depth ARG ('empty', 'files',
-                            'immediates', or 'infinity')
-  --set-depth ARG          : set new working copy depth to ARG ('exclude',
-                            'empty', 'files', 'immediates', or 'infinity')
-                            [alias: --sd]
+                             'immediates', or 'infinity')
+  --set-depth [--sd] ARG   : set new working copy depth to ARG ('exclude',
+                             'empty', 'files', 'immediates', or 'infinity')
   -q [--quiet]             : print nothing, or only summary information
   --diff3-cmd ARG          : use ARG as merge command
   --relocate               : relocate via URL-rewriting
-  --ignore-externals       : ignore externals definitions
-                             [alias: --ie]
+  --ignore-externals [--ie] : ignore externals definitions
   --force                  : force operation to run
   --accept ARG             : specify automatic conflict resolution action
-                            ('postpone', 'base', 'mine-conflict',
+                             ('postpone', 'base', 'mine-conflict',
                              'theirs-conflict', 'mine-full', 'theirs-full',
                              'edit', 'launch')
 
 Global options:
   --username ARG           : specify a username ARG
   --password ARG           : specify a password ARG
-  --no-auth-cache          : do not cache authentication tokens
-                             [alias: --nac]
+  --no-auth-cache [--nac]  : do not cache authentication tokens
   --non-interactive        : do no interactive prompting
   --trust-server-cert      : accept unknown SSL server certificates without
                              prompting (but only with '--non-interactive')
-  --config-dir ARG         : read user configuration files from directory ARG
-                             [alias: --cd]
+  --config-dir [--cd] ARG  : read user configuration files from directory ARG
   --config-option ARG      : set user configuration option in the format:
                                  FILE:SECTION:OPTION=[VALUE]
                              For example:

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/getopt_tests_data/svn_help_stdout Thu Nov  4 20:48:21 2010
@@ -36,6 +36,7 @@ Available subcommands:
    propget (pget, pg)
    proplist (plist, pl)
    propset (pset, ps)
+   relocate
    resolve
    resolved
    revert

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/info_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/info_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/info_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/info_tests.py Thu Nov  4 20:48:21 2010
@@ -285,6 +285,39 @@ def info_on_mkdir(sbox):
                        ('depth',    {}, 'infinity'),
                        ('schedule', {}, 'add')])
 
+def info_wcroot_abspaths(sbox):
+  """wc root paths in 'svn info' output"""
+
+  def check_wcroot_paths(lines, wcroot_abspath):
+    "check that paths found on input lines beginning 'Path: ' are as expected"
+    path = None
+    target = None
+    for line in lines:
+      if line.startswith('Path: '):
+        target = line[6:].rstrip()
+      if line.startswith('Working Copy Root Path: '):
+        path = line[24:].rstrip()
+      if target is not None and path is not None:
+        break
+
+    if target is None:
+      target = "(UNKNOWN)"
+      
+    if path is None:
+      print "No WC root path for '%s'" % (target)
+      raise svntest.Failure
+    
+    if path != wcroot_abspath:
+      print("For target '%s'..." % (target))
+      print("   Reported WC root path: %s" % (path))
+      print("   Expected WC root path: %s" % (wcroot_abspath))
+      raise svntest.Failure
+
+  sbox.build(read_only=True)
+  exit_code, output, errput = svntest.main.run_svn(None, 'info', '-R', sbox.wc_dir)
+  check_wcroot_paths(output, os.path.abspath(sbox.wc_dir))
+
+
 ########################################################################
 # Run the tests
 
@@ -293,6 +326,7 @@ test_list = [ None,
               info_with_tree_conflicts,
               info_on_added_file,
               info_on_mkdir,
+              info_wcroot_abspaths,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/input_validation_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/input_validation_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/input_validation_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/input_validation_tests.py Thu Nov  4 20:48:21 2010
@@ -166,6 +166,47 @@ def invalid_merge_args(sbox):
   run_and_verify_svn_in_wc(sbox, "svn: Path '.*' does not exist",
                            'merge', '-c42', '^/mu', 'nonexistent')
 
+def invalid_wcpath_upgrade(sbox):
+  "non-working copy paths for 'upgrade'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'upgrade',
+                             target, target)
+
+def invalid_resolve_targets(sbox):
+  "non-working copy paths for 'resolve'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'resolve',
+                             '--accept', 'base', target)
+
+def invalid_resolved_targets(sbox):
+  "non-working copy paths for 'resolved'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'resolved',
+                             target)
+
+def invalid_revert_targets(sbox):
+  "non-working copy paths for 'revert'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'revert',
+                             target)
+
+def invalid_lock_targets(sbox):
+  "wc paths and repo URL target mixture for 'lock'"
+  sbox.build(read_only=True)
+  for (target1, target2) in [("iota", "^/"), ("file://", "iota")]:
+    run_and_verify_svn_in_wc(sbox, "svn: Cannot mix repository and working "
+                             "copy targets", 'lock', target1, target2)
+
+def invalid_status_targets(sbox):
+  "non-working copy paths for 'status'"
+  sbox.build(read_only=True)
+  for target in _invalid_wc_path_targets:
+    run_and_verify_svn_in_wc(sbox, "svn:.*is not a local path", 'status',
+                             target)
 
 ########################################################################
 # Run the tests
@@ -184,6 +225,12 @@ test_list = [ None,
               invalid_import_args,
               invalid_log_targets,
               invalid_merge_args,
+              invalid_wcpath_upgrade,
+              invalid_resolve_targets,
+              invalid_resolved_targets,
+              invalid_revert_targets,
+              invalid_lock_targets,
+              invalid_status_targets,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/lock_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/lock_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/lock_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/lock_tests.py Thu Nov  4 20:48:21 2010
@@ -37,6 +37,24 @@ XFail = svntest.testcase.XFail
 Item = svntest.wc.StateItem
 
 ######################################################################
+# Helpers
+
+def check_writability(path, writable):
+  bits = stat.S_IWGRP | stat.S_IWOTH | stat.S_IWRITE
+  mode = os.stat(path)[0]
+  if bool(mode & bits) != writable:
+    raise svntest.Failure("path '%s' is unexpectedly %s (mode %o)"
+                          % (path, ["writable", "read-only"][writable], mode))
+
+def is_writable(path):
+  "Raise if PATH is not writable."
+  check_writability(path, True)
+
+def is_readonly(path):
+  "Raise if PATH is not readonly."
+  check_writability(path, False)
+
+######################################################################
 # Tests
 
 #----------------------------------------------------------------------
@@ -1573,6 +1591,48 @@ def replace_and_propset_locked_path(sbox
                                      'commit', '-m', '', G_path)
 
 
+#----------------------------------------------------------------------
+def cp_isnt_ro(sbox):
+  "uncommitted svn:needs-lock add/cp not read-only"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  mu_URL = sbox.repo_url + '/A/mu'
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  mu2_path = os.path.join(wc_dir, 'A', 'mu2')
+  mu3_path = os.path.join(wc_dir, 'A', 'mu3')
+  kappa_path = os.path.join(wc_dir, 'kappa')
+  open(kappa_path, 'w').write("This is the file 'kappa'.\n")
+
+  ## added file
+  sbox.simple_add(kappa_path)
+  svntest.actions.set_prop('svn:needs-lock', 'yes', kappa_path)
+  is_writable(kappa_path)
+  sbox.simple_commit(kappa_path)
+  is_readonly(kappa_path)
+
+  ## versioned file
+  svntest.actions.set_prop('svn:needs-lock', 'yes', mu_path)
+  is_writable(mu_path)
+  sbox.simple_commit(mu_path)
+  is_readonly(mu_path)
+
+  # At this point, mu has 'svn:needs-lock' set
+
+  ## wc->wc copied file
+  svntest.main.run_svn(None, 'copy', mu_path, mu2_path)
+  is_writable(mu2_path)
+  sbox.simple_commit(mu2_path)
+  is_readonly(mu2_path)
+
+  ## URL->wc copied file
+  svntest.main.run_svn(None, 'copy', mu_URL, mu3_path)
+  is_writable(mu3_path)
+  sbox.simple_commit(mu3_path)
+  is_readonly(mu3_path)
+
+
 ########################################################################
 # Run the tests
 
@@ -1619,6 +1679,7 @@ test_list = [ None,
               verify_path_escaping,
               XFail(replace_and_propset_locked_path,
                     svntest.main.is_ra_type_dav),
+              cp_isnt_ro,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/log_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/log_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/log_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/log_tests.py Thu Nov  4 20:48:21 2010
@@ -298,7 +298,8 @@ def merge_history_repos(sbox):
   # Mergeinfo changes on /trunk:
   #    Merged /branches/a:r7
   os.chdir('trunk')
-  svntest.main.run_svn(None, 'merge', '--record-only', '-r6:7',
+  svntest.main.run_svn(None, 'merge', '--allow-mixed-revisions',
+                       '--record-only', '-r6:7',
                        os.path.join('..', branch_a))
   svntest.main.run_svn(None, 'ci', '-m',
                        "Block r7 from merging to trunk.",
@@ -392,7 +393,8 @@ def merge_history_repos(sbox):
   #    Merged /trunk:r2
   #    Merged /branches/c:r3-16
   os.chdir('trunk')
-  svntest.main.run_svn(None, 'merge', os.path.join('..', branch_c) + '@HEAD')
+  svntest.main.run_svn(None, 'merge', '--allow-mixed-revisions',
+                       os.path.join('..', branch_c) + '@HEAD')
   svntest.main.file_write(os.path.join('A', 'mu'),
                           "This is the file 'mu'.\n" +
                           "Don't forget to look at 'upsilon', as well.\n" +
@@ -1297,7 +1299,7 @@ def log_changes_range(sbox):
 
   exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
                                                               'log', '-c',
-                                                              '2:5', repo_url)
+                                                              '2-5', repo_url)
 
   log_chain = parse_log_output(output)
   check_log_chain(log_chain, [2, 3, 4, 5])
@@ -1316,6 +1318,19 @@ def log_changes_list(sbox):
   log_chain = parse_log_output(output)
   check_log_chain(log_chain, [2, 5, 7])
 
+def log_changes_complex(sbox):
+  "test log -c on complex set of ranges"
+
+  guarantee_repos_and_wc(sbox)
+  repo_url = sbox.repo_url
+
+  exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
+                                                              'log', '-c',
+                                                              '2,5-3,-8,6-7', repo_url)
+
+  log_chain = parse_log_output(output)
+  check_log_chain(log_chain, [2, 5, 4, 3, 8, 6, 7])
+
 #----------------------------------------------------------------------
 def only_one_wc_path(sbox):
   "svn log of two wc paths is disallowed"
@@ -1760,8 +1775,9 @@ test_list = [ None,
               SkipUnless(merge_sensitive_log_added_path,
                          server_has_mergeinfo),
               log_single_change,
-              XFail(log_changes_range),
+              log_changes_range,
               log_changes_list,
+              log_changes_complex,
               only_one_wc_path,
               retrieve_revprops,
               log_xml_with_bad_data,

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_reintegrate_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_reintegrate_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_reintegrate_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_reintegrate_tests.py Thu Nov  4 20:48:21 2010
@@ -669,7 +669,7 @@ def reintegrate_fail_on_modified_wc(sbox
   svntest.actions.run_and_verify_merge(
     A_path, None, None, sbox.repo_url + '/A_COPY', None, None, None, None,
     None, None, None,
-    ".*Cannot reintegrate into a working copy that has local modifications.*",
+    ".*Cannot merge into a working copy that has local modifications.*",
     None, None, None, None, True, False, '--reintegrate', A_path)
 
 #----------------------------------------------------------------------
@@ -692,7 +692,7 @@ def reintegrate_fail_on_mixed_rev_wc(sbo
   svntest.actions.run_and_verify_merge(
     A_path, None, None, sbox.repo_url + '/A_COPY', None, None, None, None,
     None, None, None,
-    ".*Cannot reintegrate into mixed-revision working copy.*",
+    ".*Cannot merge into mixed-revision working copy.*",
     None, None, None, None, True, False, '--reintegrate', A_path)
 
 #----------------------------------------------------------------------
@@ -737,7 +737,7 @@ def reintegrate_fail_on_switched_wc(sbox
   svntest.actions.run_and_verify_merge(
     A_path, None, None, sbox.repo_url + '/A_COPY', None, None, None, None,
     None, None, None,
-    ".*Cannot reintegrate into a working copy with a switched subtree.*",
+    ".*Cannot merge into a working copy with a switched subtree.*",
     None, None, None, None, True, False, '--reintegrate', A_path)
 
 #----------------------------------------------------------------------
@@ -1319,7 +1319,7 @@ def reintegrate_with_subtree_mergeinfo(s
                            ' U   ' + A_COPY_path + '\n',
                            ' U   ' + D_COPY_path + '\n',
                            ' U   ' + gamma_moved_COPY_path + '\n']),
-    [], 'merge', sbox.repo_url + '/A',  A_COPY_path)
+    [], 'merge', '--allow-mixed-revisions', sbox.repo_url + '/A',  A_COPY_path)
   expected_output = wc.State(
     wc_dir,
     {'A_COPY'               : Item(verb='Sending'), # Mergeinfo update
@@ -1611,7 +1611,7 @@ def multiple_reintegrates_from_the_same_
     expected_merge_output([[2,3],[2,16]],
                           ['U    ' + psi_COPY_path + '\n',
                            ' U   ' + A_COPY_path   + '\n',]),
-    [], 'merge', sbox.repo_url + '/A', A_COPY_path)
+    [], 'merge', '--allow-mixed-revisions', sbox.repo_url + '/A', A_COPY_path)
 
 #----------------------------------------------------------------------
 # Test for a reintegrate bug which can occur when the merge source
@@ -2075,8 +2075,8 @@ def added_subtrees_with_mergeinfo_break_
 #----------------------------------------------------------------------
 # Test for issue #3648 '2-URL merges incorrectly reverse-merge mergeinfo
 # for merge target'.
-def two_URL_merge_removes_valid_mergefino_from_target(sbox):
-  "2-URL merge removes valid mergefino from target"
+def two_URL_merge_removes_valid_mergeinfo_from_target(sbox):
+  "2-URL merge removes valid mergeinfo from target"
 
   sbox.build()
   wc_dir = sbox.wc_dir
@@ -2254,7 +2254,7 @@ test_list = [ None,
                          server_has_mergeinfo),
               reintegrate_with_self_referential_mergeinfo,
               added_subtrees_with_mergeinfo_break_reintegrate,
-              two_URL_merge_removes_valid_mergefino_from_target,
+              two_URL_merge_removes_valid_mergeinfo_from_target,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_tests.py?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/merge_tests.py Thu Nov  4 20:48:21 2010
@@ -305,7 +305,10 @@ def textual_merges_galore(sbox):
                                        expected_skip,
                                        None,
                                        svntest.tree.detect_conflict_files,
-                                       list(tau_conflict_support_files))
+                                       (list(tau_conflict_support_files)),
+                                       None, None, False, True,
+                                       '--allow-mixed-revisions',
+                                       other_wc)
 
   # Now reverse merge r3 into A/D/G/rho, give it non-conflicting local
   # mods, then merge in the 2:3 change.  ### Not bothering to do the
@@ -315,6 +318,7 @@ def textual_merges_galore(sbox):
   #
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[-3]],
@@ -796,6 +800,7 @@ def merge_similar_unrelated_trees(sbox):
     })
 
   # run_and_verify_merge doesn't support 'svn merge URL URL path'
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'merge',
                                      '--ignore-ancestry',
@@ -1256,7 +1261,8 @@ def merge_binary_file(sbox):
                                        expected_status,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       1)
+                                       True, True, '--allow-mixed-revisions',
+                                       other_wc)
 
 #----------------------------------------------------------------------
 # Regression test for Issue #1297:
@@ -1529,7 +1535,8 @@ def merge_skips_obstructions(sbox):
                                        expected_status.copy(wc_dir),
                                        expected_skip,
                                        None, None, None, None, None,
-                                       1, 0)
+                                       True, False, '--allow-mixed-revisions',
+                                       wc_dir)
 
   # Revert the local mods, and commit a change to A/B/lambda (r4), and then
   # commit the deletion of the same file. (r5)
@@ -1593,7 +1600,8 @@ def merge_skips_obstructions(sbox):
                                        expected_status_short,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       1, 0)
+                                       True, False, '--allow-mixed-revisions',
+                                       wc_dir)
 
   # OK, so let's commit the new lambda (r6), and then delete the
   # working file.  Then re-run the -r3:4 merge, and see how svn deals
@@ -1639,7 +1647,8 @@ def merge_skips_obstructions(sbox):
                                        expected_status.copy(wc_dir),
                                        expected_skip,
                                        None, None, None, None, None,
-                                       1, 0, '--ignore-ancestry', wc_dir)
+                                       1, 0, '--ignore-ancestry', 
+                                       '--allow-mixed-revisions', wc_dir)
 
 #----------------------------------------------------------------------
 # At one time, a merge that added items with the same name as missing
@@ -1748,7 +1757,9 @@ def merge_into_missing(sbox):
                                        expected_skip,
                                        None, None, None, None, None,
                                        0, 0, '--dry-run',
-                                       '--ignore-ancestry', F_path)
+                                       '--ignore-ancestry',
+                                       '--allow-mixed-revisions',
+                                       F_path)
 
   expected_status = wc.State(F_path, {
     ''      : Item(status='  ', wc_rev=1),
@@ -1776,7 +1787,9 @@ def merge_into_missing(sbox):
                                        expected_skip,
                                        None, None, None, None, None,
                                        0, 0,
-                                       '--ignore-ancestry', F_path)
+                                       '--ignore-ancestry',
+                                       '--allow-mixed-revisions',
+                                       F_path)
 
   # This merge fails when it attempts to descend into the missing
   # directory.  That's OK, there is no real need to support merge into
@@ -2689,7 +2702,8 @@ def merge_dir_branches(sbox):
   ### TODO: We can use run_and_verify_merge() here now.
   expected_output = expected_merge_output(None, "A    " + foo_path + "\n")
   svntest.actions.run_and_verify_svn(None, expected_output, [],
-                                     'merge', C_url, F_url, wc_dir)
+                                     'merge', '--allow-mixed-revisions',
+                                     C_url, F_url, wc_dir)
 
   # Run info to check the copied rev to make sure it's right
   expected_info = {"Path" : re.escape(foo_path), # escape backslashes
@@ -3345,7 +3359,10 @@ def merge_file_replace_to_mixed_rev_wc(s
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
-                                       expected_skip)
+                                       expected_skip,
+                                       None, None, None, None, None,
+                                       True, False, '--allow-mixed-revisions',
+                                       wc_dir)
 
   # When issue #2522 was filed, svn used to break the WC if we didn't
   # update here. But nowadays, this no longer happens, so the separate
@@ -3431,7 +3448,7 @@ def merge_ignore_whitespace(sbox):
                                        expected_status,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       0, 0,
+                                       0, 0, '--allow-mixed-revisions',
                                        '-x', '-w', wc_dir)
 
 #----------------------------------------------------------------------
@@ -3513,7 +3530,7 @@ def merge_ignore_eolstyle(sbox):
                                        expected_status,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       0, 0,
+                                       0, 0, '--allow-mixed-revisions',
                                        '-x', '--ignore-eol-style', wc_dir)
 
 #----------------------------------------------------------------------
@@ -4684,6 +4701,7 @@ def mergeinfo_inheritance(sbox):
 
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(None, [], [], 'merge', '-c5',
                                      sbox.repo_url + '/A/B/E/beta',
                                      beta_COPY_path)
@@ -4768,6 +4786,7 @@ def mergeinfo_inheritance(sbox):
   expected_skip = wc.State(omega_COPY_path, { })
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[6]],
@@ -4891,6 +4910,7 @@ def mergeinfo_elision(sbox):
 
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[5]],
@@ -5068,6 +5088,7 @@ def mergeinfo_elision(sbox):
 
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[-5]],
@@ -5841,7 +5862,9 @@ def merge_to_path_with_switched_children
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status, expected_skip,
-                                       None, None, None, None, None, 1)
+                                       None, None, None, None, None,
+                                       True, False, '--allow-mixed-revisions',
+                                       A_COPY_H_path)
 
   # Non-inheritable mergeinfo ranges on a target do prevent repeat
   # merges on the target itself.
@@ -5894,7 +5917,9 @@ def merge_to_path_with_switched_children
                                        expected_elision_output,
                                        expected_disk_D,
                                        expected_status_D, expected_skip_D,
-                                       None, None, None, None, None, 1)
+                                       None, None, None, None, None,
+                                       True, False, '--allow-mixed-revisions',
+                                       A_COPY_D_path)
   # Repeated merge is a no-op, though we still see the notification reporting
   # the mergeinfo describing the merge has been recorded, though this time it
   # is a ' G' notification because there is a local mergeinfo change.
@@ -5909,7 +5934,9 @@ def merge_to_path_with_switched_children
                                        expected_elision_output,
                                        expected_disk_D,
                                        expected_status_D, expected_skip_D,
-                                       None, None, None, None, None, 1)
+                                       None, None, None, None, None,
+                                       True, False, '--allow-mixed-revisions',
+                                       A_COPY_D_path)
 
   # Test issue #3187 'Reverse merges don't work properly with
   # non-inheritable ranges'.
@@ -8528,6 +8555,7 @@ def cherry_picking(sbox):
   expected_skip = wc.State(rho_COPY_path, { })
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[3,4],[6]],
@@ -9495,12 +9523,14 @@ def new_subtrees_should_not_break_merge(
                                        None, None, None, None, None, 1)
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[8]],
                           ['U    ' + nu_COPY_path + '\n',
                            ' G   ' + nu_COPY_path + '\n']),
-    [], 'merge', '-c8', sbox.repo_url + '/A/D/H/nu', nu_COPY_path)
+    [], 'merge', '-c8', '--allow-mixed-revisions',
+    sbox.repo_url + '/A/D/H/nu', nu_COPY_path)
 
   # Merge -r4:6 to A_COPY, then reverse merge r6 from A_COPY/D.
   expected_output = wc.State(A_COPY_path, {
@@ -10020,7 +10050,8 @@ def dont_add_mergeinfo_from_own_history(
                                        expected_A_status,
                                        expected_A_skip,
                                        None, None, None, None,
-                                       None, 1)
+                                       None, True, False,
+                                       '--allow-mixed-revisions', A_path)
 
   # Revert all local mods
   svntest.actions.run_and_verify_svn(None,
@@ -10871,7 +10902,9 @@ def reverse_merge_away_all_mergeinfo(sbo
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status, expected_skip,
-                                       None, None, None, None, None, 1)
+                                       None, None, None, None, None,
+                                       True, False, '--allow-mixed-revisions',
+                                       A_COPY_H_path)
 
 #----------------------------------------------------------------------
 # Issue #3138
@@ -11189,6 +11222,7 @@ def dont_explicitly_record_implicit_merg
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.  Check the resulting mergeinfo with
   # a propget.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[5]], ['U    ' + A_copy_mu_path + '\n',
@@ -11401,6 +11435,7 @@ def dont_explicitly_record_implicit_merg
   expected_skip = wc.State(nu_copy_path, { })
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(
     None,
     expected_merge_output([[7]],
@@ -11830,7 +11865,7 @@ def subtree_merges_dont_intersect_with_t
 
   # Repeat the forward merge
   expected_output = expected_merge_output(
-    [[5],[8,9],[5,9]],
+    [[5],[8],[5,9]],
     ['U    %s\n' % (rho_COPY_2_path),
      'U    %s\n' % (psi_COPY_2_path),
      ' U   %s\n' % (H_COPY_2_path),
@@ -12388,10 +12423,11 @@ def svn_commit(path):
   svn_commit.repo_rev += 1
   return svn_commit.repo_rev
 
-def svn_merge(rev_spec, source, target, exp_out=None):
+def svn_merge(rev_spec, source, target, exp_out=None, *args):
   """Merge a single change from path 'source' to path 'target'.
   SRC_CHANGE_NUM is either a number (to cherry-pick that specific change)
-  or a command-line option revision range string such as '-r10:20'."""
+  or a command-line option revision range string such as '-r10:20'.
+  *ARGS are additional arguments passed to svn merge."""
   source = local_path(source)
   target = local_path(target)
   if isinstance(rev_spec, int):
@@ -12404,7 +12440,7 @@ def svn_merge(rev_spec, source, target, 
             target_re + ".*':"
     exp_out = svntest.verify.RegexOutput(exp_1 + "|" + exp_2 + "|" + exp_3)
   svntest.actions.run_and_verify_svn(None, exp_out, [],
-                                     'merge', rev_spec, source, target)
+                                     'merge', rev_spec, source, target, *args)
 
 def svn_propset(pname, pvalue, *paths):
   "Set property 'pname' to value 'pvalue' on each path in 'paths'"
@@ -12591,6 +12627,7 @@ def subtree_merges_dont_cause_spurious_c
                                        None, None, None, None, None, 1)
   # run_and_verify_merge doesn't support merging to a file WCPATH
   # so use run_and_verify_svn.
+  ### TODO: We can use run_and_verify_merge() here now.
   svntest.actions.run_and_verify_svn(None,
                                      expected_merge_output([[-3]],
                                        ['G    ' + psi_COPY_path + '\n',
@@ -12928,7 +12965,8 @@ def merge_two_edits_to_same_prop(sbox):
       % A_path,
       " U   A\n",
       "Summary of conflicts:\n",
-      "  Property conflicts: 1\n"])
+      "  Property conflicts: 1\n"],
+      '--allow-mixed-revisions')
 
   # Revert changes to source wc, to test next scenario of #3250
   svntest.actions.run_and_verify_svn(None, None, [],
@@ -12941,14 +12979,16 @@ def merge_two_edits_to_same_prop(sbox):
       "--- Recording mergeinfo for merge of r9 into '%s':\n" % A_path,
       " U   A\n",
       "Summary of conflicts:\n",
-      "  Property conflicts: 1\n"])
+      "  Property conflicts: 1\n"],
+      '--allow-mixed-revisions')
   svn_merge(rev4, A_COPY_path, A_path, [
       "--- Merging r10 into '%s':\n" % A_path,
       " C   %s\n" % mu_path,
       "--- Recording mergeinfo for merge of r10 into '%s':\n" % A_path,
       " G   A\n",
       "Summary of conflicts:\n",
-      "  Property conflicts: 1\n"])
+      "  Property conflicts: 1\n"],
+      '--allow-mixed-revisions')
 
   os.chdir(was_cwd)
 
@@ -12993,7 +13033,8 @@ def merge_an_eol_unification_and_set_svn
   svn_commit('A_COPY')
 
   # Merge the two changes together to the target branch.
-  svn_merge('-r'+str(rev1)+':'+str(rev3), 'A', 'A_COPY')
+  svn_merge('-r'+str(rev1)+':'+str(rev3), 'A', 'A_COPY', None,
+            '--allow-mixed-revisions')
 
   # That merge should succeed.
   # Surprise: setting svn:eol-style='LF' instead of 'native' doesn't fail.
@@ -13678,7 +13719,7 @@ def subtree_gets_changes_even_if_ultimat
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status, expected_skip,
-                                       None, None, None, None, None, 1)
+                                       None, None, None, None, None, 1, 0)
 
 #----------------------------------------------------------------------
 def no_self_referential_filtering_on_added_path(sbox):
@@ -13845,8 +13886,12 @@ def merge_range_prior_to_rename_source_e
   nu_path         = os.path.join(wc_dir, "A", "D", "H", "nu")
   nu_moved_path   = os.path.join(wc_dir, "A", "D", "H", "nu_moved")
   A_path          = os.path.join(wc_dir, "A")
+  alpha_path      = os.path.join(wc_dir, "A", "B", "E", "alpha")
   A_COPY_path     = os.path.join(wc_dir, "A_COPY")
+  A_COPY_2_path   = os.path.join(wc_dir, "A_COPY_2")
   B_COPY_path     = os.path.join(wc_dir, "A_COPY", "B")
+  B_COPY_2_path   = os.path.join(wc_dir, "A_COPY_2", "B")
+  alpha_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "E", "alpha")
   beta_COPY_path  = os.path.join(wc_dir, "A_COPY", "B", "E", "beta")
   gamma_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "gamma")
   rho_COPY_path   = os.path.join(wc_dir, "A_COPY", "D", "G", "rho")
@@ -13856,28 +13901,40 @@ def merge_range_prior_to_rename_source_e
 
   # Setup our basic 'trunk' and 'branch':
   # r2 - Copy A to A_COPY
-  # r3 - Text change to A/D/H/psi
-  # r4 - Text change to A/D/G/rho
-  # r5 - Text change to A/B/E/beta
-  # r6 - Text change to A/D/H/omega
-  wc_disk, wc_status = set_up_branch(sbox, False, 1)
+  # r3 - Copy A to A_COPY_2
+  # r4 - Text change to A/D/H/psi
+  # r5 - Text change to A/D/G/rho
+  # r6 - Text change to A/B/E/beta
+  # r7 - Text change to A/D/H/omega
+  wc_disk, wc_status = set_up_branch(sbox, False, 2)
+
+  # r8 - Text change to A/B/E/alpha  
+  svntest.main.file_write(alpha_path, "New content")
+  wc_status.tweak('A/B/E/alpha', wc_rev=8)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Text change', wc_dir)
 
-  # r7 - Add the file A/D/H/nu
+  # r9 - Add the file A/D/H/nu and make another change to A/B/E/alpha.
+  svntest.main.file_write(alpha_path, "Even newer content")
   svntest.main.file_write(nu_path, "This is the file 'nu'.\n")
   svntest.actions.run_and_verify_svn(None, None, [], 'add', nu_path)
-  expected_output = wc.State(wc_dir, {'A/D/H/nu' : Item(verb='Adding')})
-  wc_status.add({'A/D/H/nu' : Item(status='  ', wc_rev=7)})
+  expected_output = wc.State(wc_dir,
+                             {'A/D/H/nu'    : Item(verb='Adding'),
+                              'A/B/E/alpha' : Item(verb='Sending')})
+  wc_status.add({'A/D/H/nu' : Item(status='  ', wc_rev=9)})
+  wc_status.tweak('A/B/E/alpha', wc_rev=9)
   svntest.actions.run_and_verify_commit(wc_dir, expected_output,
                                         wc_status, None, wc_dir)
 
-  # r8 - Merge all available revisions (i.e. -r1:7) from A to A_COPY.
-  svntest.actions.run_and_verify_svn(None, ["At revision 7.\n"], [], 'up',
+  # r10 - Merge all available revisions (i.e. -r1:9) from A to A_COPY.
+  svntest.actions.run_and_verify_svn(None, ["At revision 9.\n"], [], 'up',
                                      wc_dir)
-  wc_status.tweak(wc_rev=7)
+  wc_status.tweak(wc_rev=9)
   svntest.actions.run_and_verify_svn(
     None,
-    expected_merge_output([[2,7]],
+    expected_merge_output([[2,9]],
                           ['A    ' + nu_COPY_path  + '\n',
+                           'U    ' + alpha_COPY_path + '\n',
                            'U    ' + beta_COPY_path  + '\n',
                            'U    ' + rho_COPY_path   + '\n',
                            'U    ' + omega_COPY_path + '\n',
@@ -13887,98 +13944,104 @@ def merge_range_prior_to_rename_source_e
   expected_output = wc.State(wc_dir,
                              {'A_COPY'           : Item(verb='Sending'),
                               'A_COPY/D/H/nu'    : Item(verb='Adding'),
+                              'A_COPY/B/E/alpha' : Item(verb='Sending'),
                               'A_COPY/B/E/beta'  : Item(verb='Sending'),
                               'A_COPY/D/G/rho'   : Item(verb='Sending'),
                               'A_COPY/D/H/omega' : Item(verb='Sending'),
                               'A_COPY/D/H/psi'   : Item(verb='Sending')})
   wc_status.tweak('A_COPY',
+                  'A_COPY/B/E/alpha',
                   'A_COPY/B/E/beta',
                   'A_COPY/D/G/rho',
                   'A_COPY/D/H/omega',
                   'A_COPY/D/H/psi',
-                  wc_rev=8)
-  wc_status.add({'A_COPY/D/H/nu' : Item(status='  ', wc_rev=8)})
+                  wc_rev=10)
+  wc_status.add({'A_COPY/D/H/nu' : Item(status='  ', wc_rev=10)})
   svntest.actions.run_and_verify_commit(wc_dir, expected_output,
                                         wc_status, None, wc_dir)
 
-  # r9 - Reverse merge -r7:1 from A/B to A_COPY/B
-  svntest.actions.run_and_verify_svn(None, ["At revision 8.\n"], [], 'up',
+  # r11 - Reverse merge -r9:1 from A/B to A_COPY/B
+  svntest.actions.run_and_verify_svn(None, ["At revision 10.\n"], [], 'up',
                                      wc_dir)
-  wc_status.tweak(wc_rev=8)
+  wc_status.tweak(wc_rev=10)
   svntest.actions.run_and_verify_svn(
     None,
-    expected_merge_output([[7,2]], ['U    ' + beta_COPY_path  + '\n',
+    expected_merge_output([[9,2]], ['U    ' + alpha_COPY_path + '\n',
+                                    'U    ' + beta_COPY_path  + '\n',
                                     ' G   ' + B_COPY_path     + '\n',]),
-    [], 'merge', sbox.repo_url + '/A/B', B_COPY_path, '-r7:1')
+    [], 'merge', sbox.repo_url + '/A/B', B_COPY_path, '-r9:1')
   expected_output = wc.State(wc_dir,
-                             {'A_COPY/B'        : Item(verb='Sending'),
-                              'A_COPY/B/E/beta' : Item(verb='Sending')})
+                             {'A_COPY/B'         : Item(verb='Sending'),
+                              'A_COPY/B/E/alpha' : Item(verb='Sending'),
+                              'A_COPY/B/E/beta'  : Item(verb='Sending')})
   wc_status.tweak('A_COPY/B',
-                  'A_COPY/B/E/beta',
-                  wc_rev=9)
+                  'A_COPY/B/E/alpha',
+                  'A_COPY/B/E/beta',                  
+                  wc_rev=11)
   svntest.actions.run_and_verify_commit(wc_dir, expected_output,
                                         wc_status, None, wc_dir)
 
-  # r10 - Move A/D/H/nu to A/D/H/nu_moved
+  # r12 - Move A/D/H/nu to A/D/H/nu_moved
   svntest.actions.run_and_verify_svn(None, ["\n",
-                                            "Committed revision 10.\n"], [],
+                                            "Committed revision 12.\n"], [],
                                      'move', sbox.repo_url + '/A/D/H/nu',
                                      sbox.repo_url + '/A/D/H/nu_moved',
                                      '-m', 'Move nu to nu_moved')
   svntest.actions.run_and_verify_svn(None,
                                      ["D    " + nu_path + "\n",
                                       "A    " + nu_moved_path + "\n",
-                                      "Updated to revision 10.\n"],
+                                      "Updated to revision 12.\n"],
                                      [], 'up', wc_dir)
 
-  # Now merge -r5:10 from A to A_COPY.
-  # A_COPY needs only -r7:10, which amounts only to the rename of nu.
-  # The subtree A_COPY/B needs the entire range -r5:10 because of
-  # the reverse merge we performed in r9; but none of these revisions
-  # is operative in A/B so there are no changes to A_COPY/B.
+  # Now merge -r7:12 from A to A_COPY.
+  # A_COPY needs only -r10:12, which amounts to the rename of nu.
+  # The subtree A_COPY/B needs the entire range -r7:12 because of
+  # the reverse merge we performed in r11; the only operative change
+  # here is the text mod to alpha made in r9.
   #
-  # This merge currently fails because the delete half of the A_COPY/D/H/nu
-  # to A_COPY/D/H/nu_moved move is reported in the notifications, but doesn't
+  # This merge previously failed because the delete half of the A_COPY/D/H/nu
+  # to A_COPY/D/H/nu_moved move was reported in the notifications, but didn't
   # actually happen.
   expected_output = wc.State(A_COPY_path, {
+    'B/E/alpha'    : Item(status='U '),
     'D/H/nu'       : Item(status='D '),
     'D/H/nu_moved' : Item(status='A '),
     })
   expected_mergeinfo_output = wc.State(A_COPY_path, {
-    '' : Item(status=' U'),
+    ''  : Item(status=' U'),
+    'B' : Item(status=' U'),
     })
   expected_elision_output = wc.State(A_COPY_path, {
     })
   expected_status = wc.State(A_COPY_path, {
-    ''             : Item(status=' M', wc_rev=10),
-    'B'            : Item(status=' M', wc_rev=10),
-    'mu'           : Item(status='  ', wc_rev=10),
-    'B/E'          : Item(status='  ', wc_rev=10),
-    'B/E/alpha'    : Item(status='  ', wc_rev=10),
-    'B/E/beta'     : Item(status='  ', wc_rev=10),
-    'B/lambda'     : Item(status='  ', wc_rev=10),
-    'B/F'          : Item(status='  ', wc_rev=10),
-    'C'            : Item(status='  ', wc_rev=10),
-    'D'            : Item(status='  ', wc_rev=10),
-    'D/G'          : Item(status='  ', wc_rev=10),
-    'D/G/pi'       : Item(status='  ', wc_rev=10),
-    'D/G/rho'      : Item(status='  ', wc_rev=10),
-    'D/G/tau'      : Item(status='  ', wc_rev=10),
-    'D/gamma'      : Item(status='  ', wc_rev=10),
-    'D/H'          : Item(status='  ', wc_rev=10),
-    'D/H/nu'       : Item(status='D ', wc_rev='10'),
+    ''             : Item(status=' M', wc_rev=12),
+    'B'            : Item(status=' M', wc_rev=12),
+    'mu'           : Item(status='  ', wc_rev=12),
+    'B/E'          : Item(status='  ', wc_rev=12),
+    'B/E/alpha'    : Item(status='M ', wc_rev=12),
+    'B/E/beta'     : Item(status='  ', wc_rev=12),
+    'B/lambda'     : Item(status='  ', wc_rev=12),
+    'B/F'          : Item(status='  ', wc_rev=12),
+    'C'            : Item(status='  ', wc_rev=12),
+    'D'            : Item(status='  ', wc_rev=12),
+    'D/G'          : Item(status='  ', wc_rev=12),
+    'D/G/pi'       : Item(status='  ', wc_rev=12),
+    'D/G/rho'      : Item(status='  ', wc_rev=12),
+    'D/G/tau'      : Item(status='  ', wc_rev=12),
+    'D/gamma'      : Item(status='  ', wc_rev=12),
+    'D/H'          : Item(status='  ', wc_rev=12),
+    'D/H/nu'       : Item(status='D ', wc_rev=12),
     'D/H/nu_moved' : Item(status='A ', wc_rev='-', copied='+'),
-    'D/H/chi'      : Item(status='  ', wc_rev=10),
-    'D/H/psi'      : Item(status='  ', wc_rev=10),
-    'D/H/omega'    : Item(status='  ', wc_rev=10),
+    'D/H/chi'      : Item(status='  ', wc_rev=12),
+    'D/H/psi'      : Item(status='  ', wc_rev=12),
+    'D/H/omega'    : Item(status='  ', wc_rev=12),
     })
   expected_disk = wc.State('', {
-    ''             : Item(props={SVN_PROP_MERGEINFO : '/A:2-10'}),
+    ''             : Item(props={SVN_PROP_MERGEINFO : '/A:2-12'}),
     'mu'           : Item("This is the file 'mu'.\n"),
-    # A_COPY/B wasn't touched by the merge so keeps its existing mergeinfo.
-    'B'            : Item(props={SVN_PROP_MERGEINFO : ''}),
+    'B'            : Item(props={SVN_PROP_MERGEINFO : '/A/B:8-12'}),
     'B/E'          : Item(),
-    'B/E/alpha'    : Item("This is the file 'alpha'.\n"),
+    'B/E/alpha'    : Item("Even newer content"),
     'B/E/beta'     : Item("This is the file 'beta'.\n"),
     'B/lambda'     : Item("This is the file 'lambda'.\n"),
     'B/F'          : Item(),
@@ -13996,7 +14059,138 @@ def merge_range_prior_to_rename_source_e
     'D/H/omega'    : Item("New content"),
     })
   expected_skip = wc.State(A_COPY_path, {})
-  svntest.actions.run_and_verify_merge(A_COPY_path, 5, 10,
+  svntest.actions.run_and_verify_merge(A_COPY_path, 7, 12,
+                                       sbox.repo_url + '/A', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1, 0)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'Merge -r7:12 from A to A_COPY', wc_dir)
+
+  # Now run a similar scenario as above on the second branch, but with
+  # a reverse merge this time.
+  #
+  # r14 - Merge all available revisions from A/B to A_COPY_B and then merge
+  # -r2:9 from A to A_COPY_2.  Among other things, this adds A_COPY_2/D/H/nu
+  # and leaves us with mergeinfo on the A_COPY_2 branch of:
+  #
+  #   Properties on 'A_COPY_2':
+  #     svn:mergeinfo
+  #       /A:3-9
+  #   Properties on 'A_COPY_2\B':
+  #     svn:mergeinfo
+  #       /A/B:3-13
+  svntest.actions.run_and_verify_svn(None, ["At revision 13.\n"], [], 'up',
+                                     wc_dir)
+  svntest.actions.run_and_verify_svn(None,
+                                     None, # Don't check stdout, we test this
+                                           # type of merge to death elsewhere.
+                                     [], 'merge', sbox.repo_url + '/A/B',
+                                     B_COPY_2_path)
+  svntest.actions.run_and_verify_svn(None, None,[], 'merge', '-r', '2:9',
+                                     sbox.repo_url + '/A', A_COPY_2_path)  
+  svntest.actions.run_and_verify_svn(
+    None, None, [], 'ci', '-m',
+    'Merge all from A/B to A_COPY_2/B\nMerge -r2:9 from A to A_COPY_2',
+    wc_dir)
+  svntest.actions.run_and_verify_svn(None, ["At revision 14.\n"], [], 'up',
+                                     wc_dir)
+
+  # Now reverse merge -r13:7 from A to A_COPY_2.
+  #
+  # Recall:
+  #
+  #   >svn log -r8:13 ^/A -v
+  #   ------------------------------------------------------------------------
+  #   r8 | jrandom | 2010-10-14 11:25:59 -0400 (Thu, 14 Oct 2010) | 1 line
+  #   Changed paths:
+  #      M /A/B/E/alpha
+  #
+  #   Text change
+  #   ------------------------------------------------------------------------
+  #   r9 | jrandom | 2010-10-14 11:25:59 -0400 (Thu, 14 Oct 2010) | 1 line
+  #   Changed paths:
+  #      M /A/B/E/alpha
+  #      A /A/D/H/nu
+  #
+  #   log msg
+  #   ------------------------------------------------------------------------
+  #   r12 | jrandom | 2010-10-14 11:26:01 -0400 (Thu, 14 Oct 2010) | 1 line
+  #   Changed paths:
+  #      D /A/D/H/nu
+  #      A /A/D/H/nu_moved (from /A/D/H/nu:11)
+  #
+  #   Move nu to nu_moved
+  #   ------------------------------------------------------------------------
+  #
+  # We can only reverse merge changes from the explicit mergeinfo or
+  # natural history of a target, but since all of these changes intersect with
+  # the target's explicit mergeinfo (including subtrees), all should be
+  # reverse merged, including the deletion of A_COPY/D/H/nu.  Like the forward
+  # merge performed earlier, this test previously failed when A_COPY/D/H/nu
+  # was reported as deleted, but still remained as a versioned item in the WC.
+  expected_output = wc.State(A_COPY_2_path, {
+    'B/E/alpha'    : Item(status='U '),
+    'D/H/nu'       : Item(status='D '),
+    })
+  expected_mergeinfo_output = wc.State(A_COPY_2_path, {
+    ''  : Item(status=' U'),
+    'B' : Item(status=' U'),
+    })
+  expected_elision_output = wc.State(A_COPY_2_path, {
+    'B' : Item(status=' U'),
+    })
+  expected_status = wc.State(A_COPY_2_path, {
+    ''             : Item(status=' M'),
+    'B'            : Item(status=' M'),
+    'mu'           : Item(status='  '),
+    'B/E'          : Item(status='  '),
+    'B/E/alpha'    : Item(status='M '),
+    'B/E/beta'     : Item(status='  '),
+    'B/lambda'     : Item(status='  '),
+    'B/F'          : Item(status='  '),
+    'C'            : Item(status='  '),
+    'D'            : Item(status='  '),
+    'D/G'          : Item(status='  '),
+    'D/G/pi'       : Item(status='  '),
+    'D/G/rho'      : Item(status='  '),
+    'D/G/tau'      : Item(status='  '),
+    'D/gamma'      : Item(status='  '),
+    'D/H'          : Item(status='  '),
+    'D/H/nu'       : Item(status='D '),
+    'D/H/chi'      : Item(status='  '),
+    'D/H/psi'      : Item(status='  '),
+    'D/H/omega'    : Item(status='  '),
+    })
+  expected_status.tweak(wc_rev=14)
+  expected_disk = wc.State('', {
+    ''             : Item(props={SVN_PROP_MERGEINFO : '/A:3-7'}),
+    'mu'           : Item("This is the file 'mu'.\n"),
+    'B'            : Item(),
+    'B/E'          : Item(),
+    'B/E/alpha'    : Item("This is the file 'alpha'.\n"),
+    'B/E/beta'     : Item("New content"),
+    'B/lambda'     : Item("This is the file 'lambda'.\n"),
+    'B/F'          : Item(),
+    'C'            : Item(),
+    'D'            : Item(),
+    'D/G'          : Item(),
+    'D/G/pi'       : Item("This is the file 'pi'.\n"),
+    'D/G/rho'      : Item("New content"),
+    'D/G/tau'      : Item("This is the file 'tau'.\n"),
+    'D/gamma'      : Item("This is the file 'gamma'.\n"),
+    'D/H'          : Item(),
+    'D/H/chi'      : Item("This is the file 'chi'.\n"),
+    'D/H/psi'      : Item("New content"),
+    'D/H/omega'    : Item("New content"),
+    })
+  expected_skip = wc.State(A_COPY_path, {})
+  svntest.actions.run_and_verify_merge(A_COPY_2_path, 13, 7,
                                        sbox.repo_url + '/A', None,
                                        expected_output,
                                        expected_mergeinfo_output,
@@ -14867,6 +15061,7 @@ def merge_automatic_conflict_resolution(
                                        list(psi_conflict_support_files),
                                        None, None, 1, 1,
                                        '--accept', 'postpone',
+                                       '--allow-mixed-revisions',
                                        A_COPY_path)
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'revert', '--recursive', wc_dir)
@@ -14886,6 +15081,7 @@ def merge_automatic_conflict_resolution(
                                        None, None, None,
                                        None, None, 1, 0,
                                        '--accept', 'mine-conflict',
+                                       '--allow-mixed-revisions',
                                        A_COPY_path)
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'revert', '--recursive', wc_dir)
@@ -14900,6 +15096,7 @@ def merge_automatic_conflict_resolution(
                                        None, None, None,
                                        None, None, 1, 0,
                                        '--accept', 'mine-full',
+                                       '--allow-mixed-revisions',
                                        A_COPY_path)
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'revert', '--recursive', wc_dir)
@@ -14919,6 +15116,7 @@ def merge_automatic_conflict_resolution(
                                        None, None, None,
                                        None, None, 1, 0,
                                        '--accept', 'theirs-conflict',
+                                       '--allow-mixed-revisions',
                                        A_COPY_path)
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'revert', '--recursive', wc_dir)
@@ -14933,6 +15131,7 @@ def merge_automatic_conflict_resolution(
                                        None, None, None,
                                        None, None, 1, 0,
                                        '--accept', 'theirs-full',
+                                       '--allow-mixed-revisions',
                                        A_COPY_path)
   svntest.actions.run_and_verify_svn(None, None, [],
                                      'revert', '--recursive', wc_dir)
@@ -14953,6 +15152,7 @@ def merge_automatic_conflict_resolution(
                                        None, None, None,
                                        None, None, 1, 0,
                                        '--accept', 'base',
+                                       '--allow-mixed-revisions',
                                        A_COPY_path)
 
 #----------------------------------------------------------------------
@@ -15224,7 +15424,8 @@ def committed_case_only_move_and_revert(
                                        expected_status,
                                        expected_skip,
                                        None, None, None, None,
-                                       None, 1, 0)
+                                       None, 1, 0,
+                                       '--allow-mixed-revisions', A_COPY_path)
 
 #----------------------------------------------------------------------
 # This is a test for issue #3221 'Unable to merge into working copy of
@@ -15390,7 +15591,7 @@ def foreign_repos_del_and_props(sbox):
 
   svntest.actions.run_and_verify_svn(None, None, [], 'merge',
                                       sbox.repo_url, wc2_dir,
-                                      '-r', '1:2')
+                                      '-r', '1:2', '--allow-mixed-revisions')
 
   expected_status.tweak('A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/tau', 'A/D/G/pi',
                          'A/D/gamma', 'A/D/H', 'A/D/H/psi', 'A/D/H/omega',
@@ -15892,6 +16093,138 @@ def merge_with_os_deleted_subtrees(sbox)
     svntest.verify.AnyOutput, [], 'merge', sbox.repo_url + '/A',
     A_COPY_path, '--depth=empty')
 
+#----------------------------------------------------------------------
+# Test for issue #3668 'inheritance can result in self-referential
+# mergeinfo' and issue #3669 'inheritance can result in mergeinfo
+# describing nonexistent sources'
+def no_self_referential_or_nonexistent_inherited_mergeinfo(sbox):
+  "don't inherit bogus mergeinfo"
+
+  # r1: Create a greek tree.
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # r2 - r6: Copy A to A_COPY and then make some text changes under A.
+  set_up_branch(sbox, nbr_of_branches=1)
+
+  # Some paths we'll care about
+  nu_path      = os.path.join(wc_dir, "A", "C", "nu")
+  nu_COPY_path = os.path.join(wc_dir, "A_COPY", "C", "nu")
+  J_path       = os.path.join(wc_dir, "A", "D", "J")
+  J_COPY_path  = os.path.join(wc_dir, "A_COPY", "D", "J")
+  zeta_path    = os.path.join(wc_dir, "A", "D", "J", "zeta")
+  A_COPY_path  = os.path.join(wc_dir, "A_COPY")
+
+  # r7 - Add the file A/C/nu
+  svntest.main.file_write(nu_path, "This is the file 'nu'.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'add', nu_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'commit',
+                                     '-m', 'Add file', wc_dir)
+
+  # r8 - Sync merge A to A_COPY
+  svntest.actions.run_and_verify_svn(
+    "Synch merge failed unexpectedly",
+    svntest.verify.AnyOutput, [], 'merge', sbox.repo_url + '/A',
+    A_COPY_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'commit',
+                                     '-m', 'Sync A_COPY with A', wc_dir)
+  
+  # r9 - Add the subtree A/D/J
+  #                      A/D/J/zeta
+  svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', J_path)
+  svntest.main.file_write(zeta_path, "This is the file 'zeta'.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'add', zeta_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'commit',
+                                     '-m', 'Add subtree', wc_dir)
+
+  # Update the WC in preparation for merges.
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+
+  # r10 - Sync merge A to A_COPY
+  svntest.actions.run_and_verify_svn(
+    "Synch merge failed unexpectedly",
+    svntest.verify.AnyOutput, [], 'merge', sbox.repo_url + '/A',
+    A_COPY_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'commit',
+                                     '-m', 'Sync A_COPY with A', wc_dir)
+
+  # r11 - Text changes to A/C/nu and A/D/J/zeta.
+  svntest.main.file_write(nu_path, "This is the EDITED file 'nu'.\n")
+  svntest.main.file_write(zeta_path, "This is the EDITED file 'zeta'.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'commit',
+                                     '-m', 'Edit added files', wc_dir)
+
+  # Update the WC in preparation for merges.
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+
+  # This test is marked as XFail because the following two merges
+  # create mergeinfo with both non-existent path-revs and self-referential
+  # mergeinfo.c
+  #
+  # Merge all available revisions from A/C/nu to A_COPY/C/nu.
+  # The target has no explicit mergeinfo of its own but inherits mergeinfo
+  # from A_COPY.  A_COPY has the mergeinfo '/A:2-9' so the naive mergeinfo
+  # A_COPY/C/nu inherits is '/A/C/nu:2-9'.  However, '/A/C/nu:2-6' don't
+  # actually exist (issue #3669) and '/A/C/nu:7-8' is self-referential
+  # (issue #3668).  Neither of these should be present in the resulting
+  # mergeinfo for A_COPY/C/nu, only '/A/C/nu:8-11'
+  expected_output = wc.State(nu_COPY_path, {
+    '' : Item(status='U '),
+    })
+  expected_mergeinfo_output = wc.State(nu_COPY_path, {
+    '' : Item(status=' G'),
+    })
+  expected_elision_output = wc.State(nu_COPY_path, {
+    })
+  expected_status = wc.State(nu_COPY_path, {
+    '' : Item(status='MM', wc_rev=11),
+    })
+  expected_disk = wc.State('', {
+    '' : Item(props={SVN_PROP_MERGEINFO : '/A/C/nu:8-11'}),
+    })
+  expected_skip = wc.State(nu_COPY_path, { })
+  svntest.actions.run_and_verify_merge(nu_COPY_path, None, None,
+                                       sbox.repo_url + '/A/C/nu', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1)
+
+  # Merge all available revisions from A/D/J to A_COPY/D/J.  Like the
+  # previous merge, the target should not have any non-existent ('/A/D/J:2-8')
+  # or self-referential mergeinfo ('/A/D/J:9') recorded on it post-merge.
+  expected_output = wc.State(J_COPY_path, {
+    'zeta' : Item(status='U '),    
+    })
+  expected_mergeinfo_output = wc.State(J_COPY_path, {
+    '' : Item(status=' G'),
+    })
+  expected_elision_output = wc.State(J_COPY_path, {
+    })
+  expected_status = wc.State(J_COPY_path, {
+    ''     : Item(status=' M', wc_rev=11),
+    'zeta' : Item(status='M ', wc_rev=11),
+    })
+  expected_disk = wc.State('', {
+    ''     : Item(props={SVN_PROP_MERGEINFO : '/A/D/J:10-11'}),
+    'zeta' : Item("This is the EDITED file 'zeta'.\n")
+    })
+  expected_skip = wc.State(J_COPY_path, { })
+  svntest.actions.run_and_verify_merge(J_COPY_path, None, None,
+                                       sbox.repo_url + '/A/D/J', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1)
+
 ########################################################################
 # Run the tests
 
@@ -16057,8 +16390,8 @@ test_list = [ None,
                          server_has_mergeinfo),
               SkipUnless(no_self_referential_filtering_on_added_path,
                          server_has_mergeinfo),
-              XFail(SkipUnless(merge_range_prior_to_rename_source_existence,
-                               server_has_mergeinfo)),
+              SkipUnless(merge_range_prior_to_rename_source_existence,
+                         server_has_mergeinfo),
               SkipUnless(dont_merge_gaps_in_history,
                          server_has_mergeinfo),
               SkipUnless(mergeinfo_deleted_by_a_merge_should_disappear,
@@ -16081,6 +16414,7 @@ test_list = [ None,
               merge_into_locally_added_file,
               merge_into_locally_added_directory,
               merge_with_os_deleted_subtrees,
+              XFail(no_self_referential_or_nonexistent_inherited_mergeinfo),
              ]
 
 if __name__ == '__main__':