def automatic_conflict_resolution(sbox): "resolve -R --accept [base | mf | tf]" sbox.build() wc_dir = sbox.wc_dir # Some paths we'll care about A_COPY_path = os.path.join(wc_dir, "A_COPY") psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi") # Branch A to A_COPY in r2, then make some changes under 'A' in r3-6. wc_disk, wc_status = set_up_branch(sbox) # Make a change on the A_COPY branch such that a subsequent merge # conflicts. svntest.main.file_write(psi_COPY_path, "Branch content.\n") svntest.actions.run_and_verify_svn(None, None, [], 'commit', '-m', 'log msg', wc_dir) def do_text_conflicting_merge(): svntest.actions.run_and_verify_svn(None, None, [], 'revert', '--recursive', A_COPY_path) svntest.actions.run_and_verify_svn( None, expected_merge_output([[3]], [ "C %s\n" % psi_COPY_path, " U %s\n" % A_COPY_path], target=A_COPY_path, text_conflicts=1), [], 'merge', '-c3', '--allow-mixed-revisions', sbox.repo_url + '/A', A_COPY_path) # Test 'svn resolve -R --accept base' do_text_conflicting_merge() svntest.actions.run_and_verify_resolve([psi_COPY_path], '-R', '--accept', 'base', A_COPY_path) wc_disk.tweak('A_COPY/D/H/psi', contents="This is the file 'psi'.\n") svntest.actions.verify_disk(wc_dir, wc_disk) # Test 'svn resolve -R --accept mine-full' do_text_conflicting_merge() svntest.actions.run_and_verify_resolve([psi_COPY_path], '-R', '--accept', 'mine-full', A_COPY_path) wc_disk.tweak('A_COPY/D/H/psi', contents="Branch content.\n") svntest.actions.verify_disk(wc_dir, wc_disk) # Test 'svn resolve -R --accept theirs-full' do_text_conflicting_merge() svntest.actions.run_and_verify_resolve([psi_COPY_path], '-R', '--accept', 'tf', A_COPY_path) wc_disk.tweak('A_COPY/D/H/psi', contents="New content") svntest.actions.verify_disk(wc_dir, wc_disk)
def non_inheritable_mergeinfo(sbox): "non-inheritable mergeinfo shows as merged" sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Some paths we'll care about A_COPY_path = os.path.join(wc_dir, "A_COPY") D_COPY_path = os.path.join(wc_dir, "A_COPY", "D") rho_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "G", "rho") # Update the WC, then merge r4 from A to A_COPY and r6 from A to A_COPY # at --depth empty and commit the merges as r7. svntest.actions.run_and_verify_svn(None, exp_noop_up_out(6), [], 'up', wc_dir) expected_status.tweak(wc_rev=6) svntest.actions.run_and_verify_svn( None, expected_merge_output([[4]], [ 'U ' + rho_COPY_path + '\n', ' U ' + A_COPY_path + '\n', ]), [], 'merge', '-c4', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn( None, expected_merge_output([[6]], ' G ' + A_COPY_path + '\n'), [], 'merge', '-c6', sbox.repo_url + '/A', A_COPY_path, '--depth', 'empty') expected_output = wc.State(wc_dir, { 'A_COPY': Item(verb='Sending'), 'A_COPY/D/G/rho': Item(verb='Sending'), }) expected_status.tweak('A_COPY', 'A_COPY/D/G/rho', wc_rev=7) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status, None, wc_dir) # Update the WC a last time to ensure full inheritance. svntest.actions.run_and_verify_svn(None, exp_noop_up_out(7), [], 'up', wc_dir) # Despite being non-inheritable, r6 should still show as merged to A_COPY # and not eligible for merging. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['4', '6*'], sbox.repo_url + '/A', A_COPY_path, '--show-revs', 'merged') svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['3', '5', '6*'], sbox.repo_url + '/A', A_COPY_path, '--show-revs', 'eligible') # But if we drop down to A_COPY/D, r6 should show as eligible because it # was only merged into A_COPY, no deeper. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['4'], sbox.repo_url + '/A/D', D_COPY_path, '--show-revs', 'merged') svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['3', '6'], sbox.repo_url + '/A/D', D_COPY_path, '--show-revs', 'eligible')
def automatic_conflict_resolution(sbox): "resolve -R --accept [base | mf | tf]" sbox.build() wc_dir = sbox.wc_dir # Some paths we'll care about A_COPY_path = os.path.join(wc_dir, "A_COPY") psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi") # Branch A to A_COPY in r2, then make some changes under 'A' in r3-6. wc_disk, wc_status = set_up_branch(sbox) # Make a change on the A_COPY branch such that a subsequent merge # conflicts. svntest.main.file_write(psi_COPY_path, "Branch content.\n") svntest.actions.run_and_verify_svn(None, [], 'commit', '-m', 'log msg', wc_dir) def do_text_conflicting_merge(): svntest.actions.run_and_verify_svn(None, [], 'revert', '--recursive', A_COPY_path) svntest.actions.run_and_verify_svn( expected_merge_output([[3]], [ "C %s\n" % psi_COPY_path, " U %s\n" % A_COPY_path], target=A_COPY_path, text_conflicts=1), [], 'merge', '-c3', '--allow-mixed-revisions', sbox.repo_url + '/A', A_COPY_path) # Test 'svn resolve -R --accept base' do_text_conflicting_merge() svntest.actions.run_and_verify_resolve([psi_COPY_path], '-R', '--accept', 'base', A_COPY_path) wc_disk.tweak('A_COPY/D/H/psi', contents="This is the file 'psi'.\n") svntest.actions.verify_disk(wc_dir, wc_disk) # Test 'svn resolve -R --accept mine-full' do_text_conflicting_merge() svntest.actions.run_and_verify_resolve([psi_COPY_path], '-R', '--accept', 'mine-full', A_COPY_path) wc_disk.tweak('A_COPY/D/H/psi', contents="Branch content.\n") svntest.actions.verify_disk(wc_dir, wc_disk) # Test 'svn resolve -R --accept theirs-full' do_text_conflicting_merge() svntest.actions.run_and_verify_resolve([psi_COPY_path], '-R', '--accept', 'tf', A_COPY_path) wc_disk.tweak('A_COPY/D/H/psi', contents="New content") svntest.actions.verify_disk(wc_dir, wc_disk)
def merge_sensitive_blame_and_empty_mergeinfo(sbox): "blame -g handles changes from empty mergeinfo" sbox.build() wc_dir = sbox.wc_dir wc_disk, wc_status = set_up_branch(sbox, True) A_COPY_path = os.path.join(wc_dir, 'A_COPY') psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') psi_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D', 'H', 'psi') # Make an edit to A/D/H/psi in r3. svntest.main.file_append(psi_path, "trunk edit in revision three.\n") sbox.simple_commit(message='trunk edit') # Merge r3 from A to A_COPY, reverse merge r3 from A/D/H/psi # to A_COPY/D/H/psi, and commit as r4. This results in empty # mergeinfo on A_COPY/D/H/psi. svntest.main.run_svn(None, 'up', wc_dir) svntest.main.run_svn(None, 'merge', '-c3', sbox.repo_url + '/A', A_COPY_path) svntest.main.run_svn(None, 'merge', '-c-3', sbox.repo_url + '/A/D/H/psi', psi_COPY_path) sbox.simple_commit( message='Sync merge A to A_COPY excepting A_COPY/D/H/psi') # Make an edit to A/D/H/psi in r5. svntest.main.file_append(psi_path, "trunk edit in revision five.\n") sbox.simple_commit(message='trunk edit') # Sync merge A/D/H/psi to A_COPY/D/H/psi and commit as r6. This replaces # the empty mergeinfo on A_COPY/D/H/psi with '/A/D/H/psi:2-5'. svntest.main.run_svn(None, 'up', wc_dir) svntest.main.run_svn(None, 'merge', sbox.repo_url + '/A/D/H/psi', psi_COPY_path) sbox.simple_commit(message='Sync merge A/D/H/psi to A_COPY/D/H/psi') # Check the blame -g output: # Currently this test fails because the trunk edit done in r3 is # reported as having been done in r5. # # >svn blame -g A_COPY\D\H\psi # 1 jrandom This is the file 'psi'. # G 5 jrandom trunk edit in revision three. # G 5 jrandom trunk edit in revision five. expected_output = [ " 1 jrandom This is the file 'psi'.\n", "G 3 jrandom trunk edit in revision three.\n", "G 5 jrandom trunk edit in revision five.\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'blame', '-g', psi_COPY_path)
def merge_sensitive_blame_and_empty_mergeinfo(sbox): "blame -g handles changes from empty mergeinfo" sbox.build() wc_dir = sbox.wc_dir wc_disk, wc_status = set_up_branch(sbox, True) A_COPY_path = os.path.join(wc_dir, 'A_COPY') psi_path = os.path.join(wc_dir, 'A', 'D', 'H', 'psi') psi_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D', 'H', 'psi') # Make an edit to A/D/H/psi in r3. svntest.main.file_append(psi_path, "trunk edit in revision three.\n") sbox.simple_commit(message='trunk edit') # Merge r3 from A to A_COPY, reverse merge r3 from A/D/H/psi # to A_COPY/D/H/psi, and commit as r4. This results in empty # mergeinfo on A_COPY/D/H/psi. svntest.main.run_svn(None, 'up', wc_dir) svntest.main.run_svn(None, 'merge', '-c3', sbox.repo_url + '/A', A_COPY_path) svntest.main.run_svn(None, 'merge', '-c-3', sbox.repo_url + '/A/D/H/psi', psi_COPY_path) sbox.simple_commit(message='Sync merge A to A_COPY excepting A_COPY/D/H/psi') # Make an edit to A/D/H/psi in r5. svntest.main.file_append(psi_path, "trunk edit in revision five.\n") sbox.simple_commit(message='trunk edit') # Sync merge A/D/H/psi to A_COPY/D/H/psi and commit as r6. This replaces # the empty mergeinfo on A_COPY/D/H/psi with '/A/D/H/psi:2-5'. svntest.main.run_svn(None, 'up', wc_dir) svntest.main.run_svn(None, 'merge', sbox.repo_url + '/A/D/H/psi', psi_COPY_path) sbox.simple_commit(message='Sync merge A/D/H/psi to A_COPY/D/H/psi') # Check the blame -g output: # Currently this test fails because the trunk edit done in r3 is # reported as having been done in r5. # # >svn blame -g A_COPY\D\H\psi # 1 jrandom This is the file 'psi'. # G 5 jrandom trunk edit in revision three. # G 5 jrandom trunk edit in revision five. expected_output = [ " 1 jrandom This is the file 'psi'.\n", "G 3 jrandom trunk edit in revision three.\n", "G 5 jrandom trunk edit in revision five.\n"] svntest.actions.run_and_verify_svn(expected_output, [], 'blame', '-g', psi_COPY_path)
def natural_history_is_not_eligible_nor_merged(sbox): "natural history is not eligible nor merged" sbox.build() wc_dir = sbox.wc_dir wc_disk, wc_status = set_up_branch(sbox) nu_path = os.path.join(wc_dir, 'A', 'C', 'nu') A_COPY_path = os.path.join(wc_dir, 'A_COPY') nu_COPY_path = os.path.join(wc_dir, 'A_COPY', 'C', 'nu') # r7 - Add a new file A/C/nu svntest.main.file_write(nu_path, "This is the file 'nu'.\n") svntest.actions.run_and_verify_svn(None, [], 'add', nu_path) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Add a file', wc_dir) # r8 - Sync merge ^/A to A_COPY svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Add a file', wc_dir) # r9 - Modify the file added in r7 svntest.main.file_write(nu_path, "Modification to file 'nu'.\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Modify added file', wc_dir) # r10 - Merge ^/A/C/nu to A_COPY/C/nu, creating subtree mergeinfo. svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A/C/nu', nu_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Add a file', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) # We've effectively merged everything from ^/A to A_COPY, check # that svn mergeinfo -R agrees. # # First check if there are eligible revisions, there should be none. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), [], sbox.repo_url + '/A', A_COPY_path, '--show-revs', 'eligible', '-R') # Now check that all operative revisions show as merged. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3','4','5','6','7','9'], sbox.repo_url + '/A', A_COPY_path, '--show-revs', 'merged', '-R')
def wc_target_inherits_mergeinfo_from_repos(sbox): "wc target inherits mergeinfo from repos" sbox.build() wc_dir = sbox.wc_dir wc_disk, wc_status = set_up_branch(sbox, nbr_of_branches=2) A_COPY_path = os.path.join(wc_dir, 'A_COPY') rho_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D', 'G', 'rho') gamma_2_path = os.path.join(wc_dir, 'A_COPY_2', 'D', 'gamma') tau_path = os.path.join(wc_dir, 'A', 'D', 'G', 'tau') D_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D') # Merge -c5 ^/A/D/G/rho A_COPY\D\G\rho # Merge -c7 ^/A A_COPY # Commit as r8 # # This gives us some explicit mergeinfo on the "branch" root and # one of its subtrees: # # Properties on 'A_COPY\D\G\rho': # svn:mergeinfo # /A/D/G/rho:5 # Properties on 'A_COPY': # svn:mergeinfo # /A:7 svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A/D/G/rho', rho_COPY_path, '-c5') svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A', A_COPY_path, '-c7') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Cherrypicks to branch subtree and root', wc_dir) # Checkout a new wc rooted at ^/A_COPY/D. subtree_wc = sbox.add_wc_path('D_COPY') svntest.actions.run_and_verify_svn(None, [], 'co', sbox.repo_url + '/A_COPY/D', subtree_wc) # Check the merged and eligible revisions both recursively and # non-recursively. # Eligible : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4','5'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'eligible') # Eligible : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'eligible', '-R') # Merged : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['7'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'merged') # Merged : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['5','7'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'merged', '-R') # Test that intersecting revisions in the 'svn mergeinfo' target # from one source don't show up as merged when asking about a different # source. # # In r9 make a change that effects two branches: svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) svntest.main.file_write(gamma_2_path, "New content.\n") svntest.main.file_write(tau_path, "New content.\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Make changes under both A and A_COPY_2', wc_dir) # In r10 merge r9 from A_COPY_2 to A_COPY. # # This gives us this mergeinfo: # # Properties on 'A_COPY': # svn:mergeinfo # /A:7 # /A_COPY_2:9 # Properties on 'A_COPY\D\G\rho': # svn:mergeinfo # /A/D/G/rho:5 svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A_COPY_2', A_COPY_path, '-c9') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Merge r8 from A_COPY_2 to A_COPY', wc_dir) def test_svn_mergeinfo_4_way(wc_target): # Eligible : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4','5','9'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'eligible') # Eligible : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4','9'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'eligible', '-R') # Merged : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['7'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'merged') # Merged : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['5','7'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'merged', '-R') # Test while the target is the full WC and then with the subtree WC: svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'up', subtree_wc) test_svn_mergeinfo_4_way(D_COPY_path) test_svn_mergeinfo_4_way(subtree_wc)
def mergeinfo_on_pegged_wc_path(sbox): "svn mergeinfo on pegged working copy target" sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Some paths we'll care about A_path = os.path.join(wc_dir, "A") A_COPY_path = os.path.join(wc_dir, "A_COPY") psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi") omega_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "omega") beta_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "E", "beta") # Do a couple merges # # r7 - Merge -c3,6 from A to A_COPY. svntest.actions.run_and_verify_svn( expected_merge_output([[3],[6]], ['U ' + psi_COPY_path + '\n', 'U ' + omega_COPY_path + '\n', ' U ' + A_COPY_path + '\n', ' G ' + A_COPY_path + '\n',]), [], 'merge', '-c3,6', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Merge r3 and r6') # r8 - Merge -c5 from A to A_COPY. svntest.actions.run_and_verify_svn( expected_merge_output([[5]], ['U ' + beta_COPY_path + '\n', ' U ' + A_COPY_path + '\n']), [], 'merge', '-c5', '--allow-mixed-revisions', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Merge r5') # Ask for merged and eligible revisions to A_COPY pegged at various values. # Prior to issue #3180 fix the peg revision was ignored. # # A_COPY pegged to non-existent revision svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version('.*No such revision 99'), [], A_path, A_COPY_path + '@99', '--show-revs', 'merged') # A_COPY@BASE svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3','5','6'], A_path, A_COPY_path + '@BASE', '--show-revs', 'merged') # A_COPY@HEAD svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3','5','6'], A_path, A_COPY_path + '@HEAD', '--show-revs', 'merged') # A_COPY@4 (Prior to any merges) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), [], A_path, A_COPY_path + '@4', '--show-revs', 'merged') # A_COPY@COMMITTED (r8) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3','5','6'], A_path, A_COPY_path + '@COMMITTED', '--show-revs', 'merged') # A_COPY@PREV (r7) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '6'], A_path, A_COPY_path + '@PREV', '--show-revs', 'merged') # A_COPY@BASE svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], A_path, A_COPY_path + '@BASE', '--show-revs', 'eligible') # A_COPY@HEAD svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], A_path, A_COPY_path + '@HEAD', '--show-revs', 'eligible') # A_COPY@4 (Prior to any merges) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '4', '5', '6'], A_path, A_COPY_path + '@4', '--show-revs', 'eligible') # A_COPY@COMMITTED (r8) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], A_path, A_COPY_path + '@COMMITTED', '--show-revs', 'eligible') # A_COPY@PREV (r7) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4', '5'], A_path, A_COPY_path + '@PREV', '--show-revs', 'eligible')
def recursive_mergeinfo(sbox): "test svn mergeinfo -R" sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Some paths we'll care about A_path = os.path.join(wc_dir, "A") A_COPY_path = os.path.join(wc_dir, "A_COPY") B_COPY_path = os.path.join(wc_dir, "A_COPY", "B") C_COPY_path = os.path.join(wc_dir, "A_COPY", "C") rho_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "G", "rho") H_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H") F_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "F") omega_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "omega") beta_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "E", "beta") A2_path = os.path.join(wc_dir, "A2") nu_path = os.path.join(wc_dir, "A2", "B", "F", "nu") nu_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "F", "nu") nu2_path = os.path.join(wc_dir, "A2", "C", "nu2") # Rename A to A2 in r7. svntest.actions.run_and_verify_svn(exp_noop_up_out(6), [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'ren', A_path, A2_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'rename A to A2') # Add the files A/B/F/nu and A/C/nu2 and commit them as r8. svntest.main.file_write(nu_path, "A new file.\n") svntest.main.file_write(nu2_path, "Another new file.\n") svntest.main.run_svn(None, "add", nu_path, nu2_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Add 2 new files') # Do several merges to create varied subtree mergeinfo # Merge r4 from A2 to A_COPY at depth empty svntest.actions.run_and_verify_svn(exp_noop_up_out(8), [], 'up', wc_dir) svntest.actions.run_and_verify_svn( expected_merge_output([[4]], ' U ' + A_COPY_path + '\n'), [], 'merge', '-c4', '--depth', 'empty', sbox.repo_url + '/A2', A_COPY_path) # Merge r6 from A2/D/H to A_COPY/D/H svntest.actions.run_and_verify_svn( expected_merge_output([[6]], ['U ' + omega_COPY_path + '\n', ' G ' + H_COPY_path + '\n']), [], 'merge', '-c6', sbox.repo_url + '/A2/D/H', H_COPY_path) # Merge r5 from A2 to A_COPY svntest.actions.run_and_verify_svn( expected_merge_output([[5]], ['U ' + beta_COPY_path + '\n', ' G ' + A_COPY_path + '\n', ' G ' + B_COPY_path + '\n', ' U ' + B_COPY_path + '\n',], # Elision elides=True), [], 'merge', '-c5', sbox.repo_url + '/A2', A_COPY_path) # Reverse merge -r5 from A2/C to A_COPY/C leaving empty mergeinfo on # A_COPY/C. svntest.actions.run_and_verify_svn( expected_merge_output([[-5]], ' G ' + C_COPY_path + '\n'), [], 'merge', '-c-5', sbox.repo_url + '/A2/C', C_COPY_path) # Merge r8 from A2/B/F to A_COPY/B/F svntest.actions.run_and_verify_svn( expected_merge_output([[8]], ['A ' + nu_COPY_path + '\n', ' G ' + F_COPY_path + '\n']), [], 'merge', '-c8', sbox.repo_url + '/A2/B/F', F_COPY_path) # Commit everything this far as r9 svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Many merges') svntest.actions.run_and_verify_svn(exp_noop_up_out(9), [], 'up', wc_dir) # Test svn mergeinfo -R / --depth infinity. # Asking for eligible revisions from A2 to A_COPY should show: # # r3 - Was never merged. # # r4 - Was merged at depth empty, so while there is mergeinfo for the # revision, the actual text change to A_COPY/D/G/rho hasn't yet # happened. # # r8* - Was only partially merged to the subtree at A_COPY/B/F. The # addition of A_COPY/C/nu2 is still outstanding. svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['3', '4*', '8*'], sbox.repo_url + '/A2', sbox.repo_url + '/A_COPY', '--show-revs', 'eligible', '-R') # Do the same as above, but test that we can request the revisions # in reverse order. svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['8*', '4*', '3'], sbox.repo_url + '/A2', sbox.repo_url + '/A_COPY', '--show-revs', 'eligible', '-R', '-r', '9:0') # Asking for merged revisions from A2 to A_COPY should show: # # r4* - Was merged at depth empty, so while there is mergeinfo for the # revision, the actual text change to A_COPY/D/G/rho hasn't yet # happened. # # r5 - Was merged at depth infinity to the root of the 'branch', so it # should show as fully merged. # # r6 - This was a subtree merge, but since the subtree A_COPY/D/H was # the ancestor of the only change made in r6 it is considered # fully merged. # # r8* - Was only partially merged to the subtree at A_COPY/B/F. The # addition of A_COPY/C/nu2 is still outstanding. svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['4*', '5', '6', '8*'], A2_path, A_COPY_path, '--show-revs', 'merged', '--depth', 'infinity') # Do the same as above, but test that we can request the revisions # in reverse order. svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['8*', '6', '5', '4*'], A2_path, A_COPY_path, '--show-revs', 'merged', '--depth', 'infinity', '-r', '9:0') # A couple tests of problems found with initial issue #3242 fixes. # We should be able to check for the merged revs from a URL to a URL # when the latter has explicit mergeinfo... svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['6'], sbox.repo_url + '/A2/D/H', sbox.repo_url + '/A_COPY/D/H', '--show-revs', 'merged') # ...and when the latter has inherited mergeinfo. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['6'], sbox.repo_url + '/A2/D/H/omega', sbox.repo_url + '/A_COPY/D/H/omega', '--show-revs', 'merged')
def non_inheritable_mergeinfo(sbox): "non-inheritable mergeinfo shows as merged" sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Some paths we'll care about A_COPY_path = os.path.join(wc_dir, "A_COPY") D_COPY_path = os.path.join(wc_dir, "A_COPY", "D") rho_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "G", "rho") # Update the WC, then merge r4 from A to A_COPY and r6 from A to A_COPY # at --depth empty and commit the merges as r7. svntest.actions.run_and_verify_svn(exp_noop_up_out(6), [], 'up', wc_dir) expected_status.tweak(wc_rev=6) svntest.actions.run_and_verify_svn( expected_merge_output([[4]], ['U ' + rho_COPY_path + '\n', ' U ' + A_COPY_path + '\n',]), [], 'merge', '-c4', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn( expected_merge_output([[6]], ' G ' + A_COPY_path + '\n'), [], 'merge', '-c6', sbox.repo_url + '/A', A_COPY_path, '--depth', 'empty') expected_output = wc.State(wc_dir, { 'A_COPY' : Item(verb='Sending'), 'A_COPY/D/G/rho' : Item(verb='Sending'), }) expected_status.tweak('A_COPY', 'A_COPY/D/G/rho', wc_rev=7) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Update the WC a last time to ensure full inheritance. svntest.actions.run_and_verify_svn(exp_noop_up_out(7), [], 'up', wc_dir) # Despite being non-inheritable, r6 should still show as merged to A_COPY # and not eligible for merging. svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['4','6*'], sbox.repo_url + '/A', A_COPY_path, '--show-revs', 'merged') svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['3','5','6*'], sbox.repo_url + '/A', A_COPY_path, '--show-revs', 'eligible') # But if we drop down to A_COPY/D, r6 should show as eligible because it # was only merged into A_COPY, no deeper. svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['4'], sbox.repo_url + '/A/D', D_COPY_path, '--show-revs', 'merged') svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""), ['3','6'], sbox.repo_url + '/A/D', D_COPY_path, '--show-revs', 'eligible')
def mergeinfo_and_skipped_paths(sbox): "skipped paths get overriding mergeinfo" # Test that we override the mergeinfo for child paths which weren't # actually merged because they were skipped. # # This test covers paths skipped because: # # 1) The source of a merge is inaccessible due to authz restrictions. # 2) Destination of merge is inaccessible due to authz restrictions. # 3) Source *and* destination of merge is inaccessible due to authz # restrictions. sbox.build() wc_dir = sbox.wc_dir wc_disk, wc_status = set_up_branch(sbox, False, 3) # Create a restrictive authz where part of the merge source and part # of the target are inaccesible. write_restrictive_svnserve_conf(sbox.repo_dir) write_authz_file(sbox, {"/" : svntest.main.wc_author +"=rw", # Make a directory in the merge source inaccessible. "/A/B/E" : svntest.main.wc_author + "=", # Make a file and dir in the merge destination # inaccessible. "/A_COPY_2/D/H/psi" : svntest.main.wc_author + "=", "/A_COPY_2/D/G" : svntest.main.wc_author + "=", # Make the source and destination inaccessible. "/A_COPY_3/B/E" : svntest.main.wc_author + "=", }) # Checkout just the branch under the newly restricted authz. wc_restricted = sbox.add_wc_path('restricted') svntest.actions.run_and_verify_svn(None, [], 'checkout', sbox.repo_url, wc_restricted) # Some paths we'll use in the second WC. A_COPY_path = os.path.join(wc_restricted, "A_COPY") A_COPY_2_path = os.path.join(wc_restricted, "A_COPY_2") A_COPY_2_H_path = os.path.join(wc_restricted, "A_COPY_2", "D", "H") A_COPY_3_path = os.path.join(wc_restricted, "A_COPY_3") omega_path = os.path.join(wc_restricted, "A_COPY", "D", "H", "omega") zeta_path = sbox.ospath("A/D/H/zeta") # Merge r4:8 into the restricted WC's A_COPY. # # We expect A_COPY/B/E to be skipped because we can't access the source # and A_COPY/D/H/omega because it is missing. Since we have A_COPY/B/E # we should override it's inherited mergeinfo, giving it just what it # inherited from A_COPY before the merge. expected_output = wc.State(A_COPY_path, { 'D/G/rho' : Item(status='U '), 'D/H/psi' : Item(status='U '), 'D/H/omega' : Item(status='U '), }) expected_mergeinfo_output = wc.State(A_COPY_path, { '' : Item(status=' U'), 'B/E' : Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_path, { }) expected_status = wc.State(A_COPY_path, { '' : Item(status=' M', wc_rev=8), 'D/H/chi' : Item(status=' ', wc_rev=8), 'D/H/psi' : Item(status='M ', wc_rev=8), 'D/H/omega' : Item(status='M ', wc_rev=8), 'D/H' : Item(status=' ', wc_rev=8), 'D/G/pi' : Item(status=' ', wc_rev=8), 'D/G/rho' : Item(status='M ', wc_rev=8), 'D/G/tau' : Item(status=' ', wc_rev=8), 'D/G' : Item(status=' ', wc_rev=8), 'D/gamma' : Item(status=' ', wc_rev=8), 'D' : Item(status=' ', wc_rev=8), 'B/lambda' : Item(status=' ', wc_rev=8), 'B/E' : Item(status=' M', wc_rev=8), 'B/E/alpha' : Item(status=' ', wc_rev=8), 'B/E/beta' : Item(status=' ', wc_rev=8), 'B/F' : Item(status=' ', wc_rev=8), 'B' : Item(status=' ', wc_rev=8), 'mu' : Item(status=' ', wc_rev=8), 'C' : Item(status=' ', wc_rev=8), }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A:5-8'}), 'D/H/psi' : Item("New content"), 'D/H/chi' : Item("This is the file 'chi'.\n"), 'D/H/omega' : Item("New content"), 'D/H' : 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/G' : Item(), 'D/gamma' : Item("This is the file 'gamma'.\n"), 'D' : Item(), 'B/lambda' : Item("This is the file 'lambda'.\n"), 'B/E' : Item(props={SVN_PROP_MERGEINFO : ''}), 'B/E/alpha' : Item("This is the file 'alpha'.\n"), 'B/E/beta' : Item("This is the file 'beta'.\n"), 'B/F' : Item(), 'B' : Item(), 'mu' : Item("This is the file 'mu'.\n"), 'C' : Item(), }) expected_skip = wc.State(A_COPY_path, { 'B/E' : Item(verb='Skipped missing target'), }) svntest.actions.run_and_verify_merge(A_COPY_path, '4', '8', sbox.repo_url + '/A', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, check_props=True) # Merge r4:8 into the restricted WC's A_COPY_2. # # As before we expect A_COPY_2/B/E to be skipped because we can't access the # source but now the destination paths A_COPY_2/D/G, A_COPY_2/D/G/rho, and # A_COPY_2/D/H/psi should also be skipped because our test user doesn't have # access. # # After the merge the parents of the missing dest paths, A_COPY_2/D and # A_COPY_2/D/H get non-inheritable mergeinfo. Those parents' children that # *are* present and are affected by the merge, only A_COPY_2/D/H/omega in # this case, get their own mergeinfo. Note that A_COPY_2/D/H is both the # parent of a missing child and the sibling of missing child, but the former # always takes precedence in terms of getting *non*-inheritable mergeinfo. expected_output = wc.State(A_COPY_2_path, { 'D/H/omega' : Item(status='U '), # Below the skip 'D/G/rho' : Item(status=' ', treeconflict='U'), }) expected_mergeinfo_output = wc.State(A_COPY_2_path, { '' : Item(status=' U'), 'D' : Item(status=' U'), 'D/H' : Item(status=' U'), 'D/H/omega' : Item(status=' U'), 'B/E' : Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_2_path, { }) expected_status = wc.State(A_COPY_2_path, { '' : Item(status=' M', wc_rev=8), 'D/H/chi' : Item(status=' ', wc_rev=8), 'D/H/omega' : Item(status='MM', wc_rev=8), 'D/H' : Item(status=' M', wc_rev=8), 'D/gamma' : Item(status=' ', wc_rev=8), 'D' : Item(status=' M', wc_rev=8), 'B/lambda' : Item(status=' ', wc_rev=8), 'B/E' : Item(status=' M', wc_rev=8), 'B/E/alpha' : Item(status=' ', wc_rev=8), 'B/E/beta' : Item(status=' ', wc_rev=8), 'B/F' : Item(status=' ', wc_rev=8), 'B' : Item(status=' ', wc_rev=8), 'mu' : Item(status=' ', wc_rev=8), 'C' : Item(status=' ', wc_rev=8), }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A:5-8'}), 'D/H/omega' : Item("New content", props={SVN_PROP_MERGEINFO : '/A/D/H/omega:5-8'}), 'D/H/chi' : Item("This is the file 'chi'.\n"), 'D/H' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-8*'}), 'D/gamma' : Item("This is the file 'gamma'.\n"), 'D' : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-8*'}), 'B/lambda' : Item("This is the file 'lambda'.\n"), 'B/E' : Item(props={SVN_PROP_MERGEINFO : ''}), 'B/E/alpha' : Item("This is the file 'alpha'.\n"), 'B/E/beta' : Item("This is the file 'beta'.\n"), 'B/F' : Item(), 'B' : Item(), 'mu' : Item("This is the file 'mu'.\n"), 'C' : Item(), }) expected_skip = wc.State(A_COPY_2_path, { 'B/E' : Item(verb='Skipped missing target'), 'D/G' : Item(verb='Skipped missing target'), 'D/H/psi' : Item(verb='Skipped missing target'), }) svntest.actions.run_and_verify_merge(A_COPY_2_path, '4', '8', sbox.repo_url + '/A', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, check_props=True) # Merge r5:7 into the restricted WC's A_COPY_3. # # Again A_COPY_3/B/E should be skipped, but because we can't access the # source *or* the destination we expect its parent A_COPY_3/B to get # non-inheritable mergeinfo. A_COPY_3B's two existing siblings, # A_COPY_3/B/F and A_COPY_3/B/lambda are untouched by the merge so # neither gets any mergeinfo recorded. expected_output = wc.State(A_COPY_3_path, { 'D/G/rho' : Item(status='U '), }) expected_mergeinfo_output = wc.State(A_COPY_3_path, { '' : Item(status=' U'), 'B' : Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_3_path, { }) expected_status = wc.State(A_COPY_3_path, { '' : Item(status=' M', wc_rev=8), 'D/H/chi' : Item(status=' ', wc_rev=8), 'D/H/omega' : Item(status=' ', wc_rev=8), 'D/H/psi' : Item(status=' ', wc_rev=8), 'D/H' : Item(status=' ', wc_rev=8), 'D/gamma' : Item(status=' ', wc_rev=8), 'D' : Item(status=' ', wc_rev=8), 'D/G' : Item(status=' ', wc_rev=8), 'D/G/pi' : Item(status=' ', wc_rev=8), 'D/G/rho' : Item(status='M ', wc_rev=8), 'D/G/tau' : Item(status=' ', wc_rev=8), 'B/lambda' : Item(status=' ', wc_rev=8), 'B/F' : Item(status=' ', wc_rev=8), 'B' : Item(status=' M', wc_rev=8), 'mu' : Item(status=' ', wc_rev=8), 'C' : Item(status=' ', wc_rev=8), }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A:6-7'}), 'D/H/omega' : Item("This is the file 'omega'.\n"), 'D/H/chi' : Item("This is the file 'chi'.\n"), 'D/H/psi' : Item("This is the file 'psi'.\n"), 'D/H' : Item(), 'D/gamma' : Item("This is the file 'gamma'.\n"), '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"), 'B/lambda' : Item("This is the file 'lambda'.\n"), 'B/F' : Item(), 'B' : Item(props={SVN_PROP_MERGEINFO : '/A/B:6-7*'}), 'mu' : Item("This is the file 'mu'.\n"), 'C' : Item(), }) expected_skip = wc.State(A_COPY_3_path, {'B/E' : Item(verb='Skipped missing target')}) svntest.actions.run_and_verify_merge(A_COPY_3_path, '5', '7', sbox.repo_url + '/A', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, check_props=True) svntest.actions.run_and_verify_svn(None, [], 'revert', '--recursive', wc_restricted) # Test issue #2997. If a merge requires two separate editor drives and the # first is non-operative we should still update the mergeinfo to reflect # this. # # Merge -c5 -c8 to the restricted WC's A_COPY_2/D/H. r5 gets merged first # but is a no-op, r8 get's merged next and is operative so the mergeinfo # should be updated on the merge target to reflect both merges. expected_output = wc.State(A_COPY_2_H_path, { 'omega' : Item(status='U '), }) expected_elision_output = wc.State(A_COPY_2_H_path, { }) expected_status = wc.State(A_COPY_2_H_path, { '' : Item(status=' M', wc_rev=8), 'chi' : Item(status=' ', wc_rev=8), 'omega' : Item(status='MM', wc_rev=8), }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'}), 'omega' : Item("New content", props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}), 'chi' : Item("This is the file 'chi'.\n"), }) expected_skip = wc.State(A_COPY_2_H_path, { 'psi' : Item(verb='Skipped missing target'), }) # Note we don't bother checking expected mergeinfo output because the # multiple merges being performed here, -c5 and -c8, will result in # first ' U' and then ' G' mergeinfo notifications. Our expected # tree structures can't handle checking for multiple values for the # same key. svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '4', '5', sbox.repo_url + '/A/D/H', None, expected_output, None, # expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, [], True, False, '-c5', '-c8', A_COPY_2_H_path) # Test issue #2829 'Improve handling for skipped paths encountered # during a merge' # Revert previous changes to restricted WC svntest.actions.run_and_verify_svn(None, [], 'revert', '--recursive', wc_restricted) # Add new path 'A/D/H/zeta' svntest.main.file_write(zeta_path, "This is the file 'zeta'.\n") svntest.actions.run_and_verify_svn(None, [], 'add', zeta_path) expected_output = wc.State(wc_dir, {'A/D/H/zeta' : Item(verb='Adding')}) wc_status.add({'A/D/H/zeta' : Item(status=' ', wc_rev=9)}) svntest.actions.run_and_verify_commit(wc_dir, expected_output, wc_status) # Merge -r7:9 to the restricted WC's A_COPY_2/D/H. # # r9 adds a path, 'A_COPY_2/D/H/zeta', which has a missing sibling 'psi', # but since 'psi' is untouched by the merge it isn't skipped, and since it # isn't skipped, its parent 'A_COPY_2/D/H' won't get non-inheritable # mergeinfo set on it to describe the merge, so none of the parent's # children will get explicit mergeinfo -- see issue #4056. expected_output = wc.State(A_COPY_2_H_path, { 'omega' : Item(status='U '), 'zeta' : Item(status='A '), }) expected_mergeinfo_output = wc.State(A_COPY_2_H_path, { '' : Item(status=' U'), 'omega' : Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_2_H_path, { 'omega' : Item(status=' U'), }) expected_status = wc.State(A_COPY_2_H_path, { '' : Item(status=' M', wc_rev=8), 'chi' : Item(status=' ', wc_rev=8), 'omega' : Item(status='M ', wc_rev=8), 'zeta' : Item(status='A ', copied='+', wc_rev='-'), }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9'}), 'omega' : Item("New content"), 'chi' : Item("This is the file 'chi'.\n"), 'zeta' : Item("This is the file 'zeta'.\n"), }) expected_skip = wc.State(A_COPY_2_H_path, {}) svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9', sbox.repo_url + '/A/D/H', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, check_props=True) # Merge -r4:9 to the restricted WC's A_COPY_2/D/H. # # r9 adds a path, 'A_COPY_2/D/H/zeta', which has a parent with # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing # and skipped). 'A_COPY_2/D/H/zeta' must therefore get its own explicit # mergeinfo from this merge. svntest.actions.run_and_verify_svn(None, [], 'revert', '--recursive', wc_restricted) expected_output = wc.State(A_COPY_2_H_path, { 'omega' : Item(status='U '), 'zeta' : Item(status='A '), }) expected_mergeinfo_output = wc.State(A_COPY_2_H_path, { '' : Item(status=' U'), 'omega' : Item(status=' U'), 'zeta' : Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_2_H_path, { }) expected_status = wc.State(A_COPY_2_H_path, { '' : Item(status=' M', wc_rev=8), 'chi' : Item(status=' ', wc_rev=8), 'omega' : Item(status='MM', wc_rev=8), 'zeta' : Item(status='A ', copied='+', wc_rev='-'), }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-9*'}), 'omega' : Item("New content", props={SVN_PROP_MERGEINFO : '/A/D/H/omega:5-9'}), 'chi' : Item("This is the file 'chi'.\n"), 'zeta' : Item("This is the file 'zeta'.\n", props={SVN_PROP_MERGEINFO : '/A/D/H/zeta:9'}), }) expected_skip = wc.State(A_COPY_2_H_path, { 'psi' : Item(verb='Skipped missing target'), }) svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '4', '9', sbox.repo_url + '/A/D/H', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, check_props=True)
def reintegrate_fails_if_no_root_access(sbox): "reintegrate fails if no root access" # If a user is authorized to a reintegrate source and target, they # should be able to reintegrate, regardless of what authorization # they have to parents of the source and target. # # See https://issues.apache.org/jira/browse/SVN-3242#desc78 # Some paths we'll care about wc_dir = sbox.wc_dir A_path = sbox.ospath('A') A_COPY_path = sbox.ospath('A_COPY') beta_COPY_path = sbox.ospath('A_COPY/B/E/beta') rho_COPY_path = sbox.ospath('A_COPY/D/G/rho') omega_COPY_path = sbox.ospath('A_COPY/D/H/omega') psi_COPY_path = sbox.ospath('A_COPY/D/H/psi') # Copy A@1 to A_COPY in r2, and then make some changes to A in r3-6. sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Make a change on the branch, to A_COPY/mu, commit in r7. svntest.main.file_write(sbox.ospath("A_COPY/mu"), "Changed on the branch.") expected_output = wc.State(wc_dir, {'A_COPY/mu' : Item(verb='Sending')}) expected_status.tweak('A_COPY/mu', wc_rev=7) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) expected_disk.tweak('A_COPY/mu', contents='Changed on the branch.') # Update the WC. svntest.main.run_svn(None, 'up', wc_dir) # Sync A_COPY with A. expected_output = expected_merge_output([[2,7]], ['U ' + beta_COPY_path + '\n', 'U ' + rho_COPY_path + '\n', 'U ' + omega_COPY_path + '\n', 'U ' + psi_COPY_path + '\n', # Mergeinfo notification ' U ' + A_COPY_path + '\n']) svntest.actions.run_and_verify_svn(expected_output, [], 'merge', sbox.repo_url + '/A', A_COPY_path) sbox.simple_commit(message='synch A_COPY with A') # Update so we are ready for reintegrate. svntest.main.run_svn(None, 'up', wc_dir) # Change authz file so everybody has access to everything but the root. if is_ra_type_svn() or is_ra_type_dav(): write_restrictive_svnserve_conf(sbox.repo_dir) write_authz_file(sbox, {"/" : "* =", "/A" : "* = rw", "/A_COPY" : "* = rw", "/iota" : "* = rw"}) # Now reintegrate A_COPY back to A. The lack of access to the root of the # repository shouldn't be a problem. expected_output = wc.State(A_path, { 'mu' : Item(status='U '), }) expected_mergeinfo_output = wc.State(A_path, { '' : Item(status=' U'), }) expected_elision_output = wc.State(A_path, { }) expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A_COPY:2-8'}), 'B' : Item(), 'B/lambda' : Item("This is the file 'lambda'.\n"), 'B/E' : Item(), 'B/E/alpha' : Item("This is the file 'alpha'.\n"), 'B/E/beta' : Item("New content"), 'B/F' : Item(), 'mu' : Item("Changed on the branch."), 'C' : Item(), 'D' : Item(), 'D/gamma' : Item("This is the file 'gamma'.\n"), '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/H' : Item(), 'D/H/chi' : Item("This is the file 'chi'.\n"), 'D/H/omega' : Item("New content"), 'D/H/psi' : Item("New content"), }) expected_status = wc.State(A_path, { "B" : Item(status=' ', wc_rev=8), "B/lambda" : Item(status=' ', wc_rev=8), "B/E" : Item(status=' ', wc_rev=8), "B/E/alpha" : Item(status=' ', wc_rev=8), "B/E/beta" : Item(status=' ', wc_rev=8), "B/F" : Item(status=' ', wc_rev=8), "mu" : Item(status='M ', wc_rev=8), "C" : Item(status=' ', wc_rev=8), "D" : Item(status=' ', wc_rev=8), "D/gamma" : Item(status=' ', wc_rev=8), "D/G" : Item(status=' ', wc_rev=8), "D/G/pi" : Item(status=' ', wc_rev=8), "D/G/rho" : Item(status=' ', wc_rev=8), "D/G/tau" : Item(status=' ', wc_rev=8), "D/H" : Item(status=' ', wc_rev=8), "D/H/chi" : Item(status=' ', wc_rev=8), "D/H/omega" : Item(status=' ', wc_rev=8), "D/H/psi" : Item(status=' ', wc_rev=8), "" : Item(status=' M', wc_rev=8), }) expected_skip = wc.State(A_path, {}) svntest.actions.run_and_verify_merge(A_path, None, None, sbox.repo_url + '/A_COPY', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, [], True, True, '--reintegrate', A_path)
def subtree_to_and_fro(sbox): "reintegrate considers source subtree mergeinfo" # A (-----o-o-o-o------------x # ( \ \ / # ( \ \ / # A_COPY ( o---------o--s--o-- # 2 3 4 5 6 7 8 9 # Some paths we'll care about. A_COPY_gamma_path = sbox.ospath('A_COPY/D/gamma') psi_path = sbox.ospath('A/D/H/psi') A_COPY_D_path = sbox.ospath('A_COPY/D') A_path = sbox.ospath('A') sbox.build() wc_dir = sbox.wc_dir # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then # make a few edits under A in r3-6 (edits r3, r4, r6 are under subtree 'D'): wc_disk, wc_status = set_up_branch(sbox) # r7 - Edit a file on the branch. svntest.main.file_write(A_COPY_gamma_path, "Branch edit to 'gamma'.\n") svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Edit a file on our branch') # r8 - Do a subtree sync merge from ^/A/D to A_COPY/D. # Note that among other things this changes A_COPY/D/H/psi. svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A/D', A_COPY_D_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Automatic subtree merge') # r9 - Make an edit to A/D/H/psi. svntest.main.file_write(psi_path, "Trunk Edit to 'psi'.\n") svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Edit a file on our trunk') # Now reintegrate ^/A_COPY back to A. Prior to issue #4258's fix, the # the subtree merge to A_COPY/D just looks like any other branch edit and # was not considered a merge. So the changes which exist on A/D and were # merged to A_COPY/D, were merged *back* to A, resulting in a conflict: # # C:\...\working_copies\merge_automatic_tests-18>svn merge ^^/A_COPY A # DBG: merge.c:11461: base on source: ^/A@1 # DBG: merge.c:11462: base on target: ^/A@1 # DBG: merge.c:11567: yca ^/A@1 # DBG: merge.c:11568: base ^/A@1 # DBG: merge.c:11571: right ^/A_COPY@8 # Conflict discovered in file 'A\D\H\psi'. # Select: (p) postpone, (df) diff-full, (e) edit, # (mc) mine-conflict, (tc) theirs-conflict, # (s) show all options: p # --- Merging r2 through r9 into 'A': # C A\D\H\psi # U A\D\gamma # --- Recording mergeinfo for merge of r2 through r9 into 'A': # U A # Summary of conflicts: # Text conflicts: 1 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) exit_code, out, err = svntest.actions.run_and_verify_svn( [], svntest.verify.AnyOutput, 'merge', sbox.repo_url + '/A_COPY', A_path) # Better to produce the same warning that explicitly using the # --reintegrate option would produce: svntest.verify.verify_outputs( "Automatic Reintegrate failed, but not " "in the way expected", err, None, "(svn: E195016: Reintegrate can only be used if " "revisions 2 through 9 were previously " "merged from .*/A to the reintegrate source, " "but this is not the case:\n)" "|( A_COPY\n)" "|( Missing ranges: /A:5\n)" "|(\n)" "|" + svntest.main.stack_trace_regexp, None, True) # Match *all* lines of stdout
def mergeinfo_on_pegged_wc_path(sbox): "svn mergeinfo on pegged working copy target" sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Some paths we'll care about A_path = os.path.join(wc_dir, "A") A_COPY_path = os.path.join(wc_dir, "A_COPY") psi_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "psi") omega_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "omega") beta_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "E", "beta") # Do a couple merges # # r7 - Merge -c3,6 from A to A_COPY. svntest.actions.run_and_verify_svn( expected_merge_output([[3], [6]], [ 'U ' + psi_COPY_path + '\n', 'U ' + omega_COPY_path + '\n', ' U ' + A_COPY_path + '\n', ' G ' + A_COPY_path + '\n', ]), [], 'merge', '-c3,6', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Merge r3 and r6') # r8 - Merge -c5 from A to A_COPY. svntest.actions.run_and_verify_svn( expected_merge_output( [[5]], ['U ' + beta_COPY_path + '\n', ' U ' + A_COPY_path + '\n']), [], 'merge', '-c5', '--allow-mixed-revisions', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Merge r5') # Ask for merged and eligible revisions to A_COPY pegged at various values. # Prior to issue #3180 fix the peg revision was ignored. # # A_COPY pegged to non-existent revision svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version('.*No such revision 99'), [], A_path, A_COPY_path + '@99', '--show-revs', 'merged') # A_COPY@BASE svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '5', '6'], A_path, A_COPY_path + '@BASE', '--show-revs', 'merged') # A_COPY@HEAD svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '5', '6'], A_path, A_COPY_path + '@HEAD', '--show-revs', 'merged') # A_COPY@4 (Prior to any merges) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), [], A_path, A_COPY_path + '@4', '--show-revs', 'merged') # A_COPY@COMMITTED (r8) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '5', '6'], A_path, A_COPY_path + '@COMMITTED', '--show-revs', 'merged') # A_COPY@PREV (r7) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '6'], A_path, A_COPY_path + '@PREV', '--show-revs', 'merged') # A_COPY@BASE svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], A_path, A_COPY_path + '@BASE', '--show-revs', 'eligible') # A_COPY@HEAD svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], A_path, A_COPY_path + '@HEAD', '--show-revs', 'eligible') # A_COPY@4 (Prior to any merges) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['3', '4', '5', '6'], A_path, A_COPY_path + '@4', '--show-revs', 'eligible') # A_COPY@COMMITTED (r8) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], A_path, A_COPY_path + '@COMMITTED', '--show-revs', 'eligible') # A_COPY@PREV (r7) svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4', '5'], A_path, A_COPY_path + '@PREV', '--show-revs', 'eligible')
def merge_to_reverse_cherry_subtree_to_merge_to(sbox): "sync merge considers target subtree mergeinfo" # A (--o-o-o-o------------------ # ( \ \ \ \ # ( \ \ \ \ # B ( o--o------x-------rc-----x # Some paths we'll care about. A_COPY_path = sbox.ospath('A_COPY') A_COPY_B_path = sbox.ospath('A_COPY/B') A_COPY_beta_path = sbox.ospath('A_COPY/B/E/beta') sbox.build() wc_dir = sbox.wc_dir # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then # make a few edits under A in r3-6: wc_disk, wc_status = set_up_branch(sbox) # Sync merge ^/A to A_COPY, then reverse merge r5 from ^/A/B to A_COPY/B. # This results in mergeinfo on the target which makes it appear that the # branch is synced up to r6, but the subtree mergeinfo on A_COPY/B reveals # that r5 has not been merged to that subtree: # # Properties on 'A_COPY': # svn:mergeinfo # /A:2-6 # Properties on 'A_COPY\B': # svn:mergeinfo # /A/B:2-4,6 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'merge', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, None, [], 'merge', '-c-5', sbox.repo_url + '/A/B', A_COPY_B_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m', 'sync merge and reverse subtree merge') # Try an automatic sync merge from ^/A to A_COPY. Revision 5 should be # merged to A_COPY/B as its subtree mergeinfo reveals that rev is missing, # like so: # # >svn merge ^/A A_COPY # --- Merging r5 into 'A_COPY\B': # U A_COPY\B\E\beta # --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY': # U A_COPY # --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY\B': # U A_COPY\B # --- Eliding mergeinfo from 'A_COPY\B': # U A_COPY\B # # But the merge ignores the subtree mergeinfo and considers # only the mergeinfo on the target itself (and thus is a no-op but for # the mergeinfo change on the root of the merge target): # # >svn merge ^/A A_COPY # --- Recording mergeinfo for merge of r7 into 'A_COPY': # U A_COPY # # >svn diff # Index: A_COPY # =================================================================== # --- A_COPY (revision 7) # +++ A_COPY (working copy) # # Property changes on: A_COPY # ___________________________________________________________________ # Modified: svn:mergeinfo # Merged /A:r7 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) expected_output = wc.State(A_COPY_path, { 'B/E/beta' : Item(status='U '), }) expected_mergeinfo_output = wc.State(A_COPY_path, { '' : Item(status=' U'), 'B' : Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_path, { 'B' : Item(status=' U'), }) expected_status = wc.State(A_COPY_path, { '' : Item(status=' M'), 'B' : Item(status=' M'), 'mu' : Item(status=' '), 'B/E' : Item(status=' '), 'B/E/alpha' : Item(status=' '), 'B/E/beta' : Item(status='M '), '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/chi' : Item(status=' '), 'D/H/psi' : Item(status=' '), 'D/H/omega' : Item(status=' '), }) expected_status.tweak(wc_rev='7') expected_disk = wc.State('', { '' : Item(props={SVN_PROP_MERGEINFO : '/A:2-7'}), 'B' : Item(), 'mu' : Item("This is the file 'mu'.\n"), '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_path, None, None, 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, A_COPY_path)
def subtree_to_and_fro(sbox): "reintegrate considers source subtree mergeinfo" # A (-----o-o-o-o------------x # ( \ \ / # ( \ \ / # A_COPY ( o---------o--s--o-- # 2 3 4 5 6 7 8 9 # Some paths we'll care about. A_COPY_gamma_path = sbox.ospath('A_COPY/D/gamma') psi_path = sbox.ospath('A/D/H/psi') A_COPY_D_path = sbox.ospath('A_COPY/D') A_path = sbox.ospath('A') sbox.build() wc_dir = sbox.wc_dir # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then # make a few edits under A in r3-6 (edits r3, r4, r6 are under subtree 'D'): wc_disk, wc_status = set_up_branch(sbox) # r7 - Edit a file on the branch. svntest.main.file_write(A_COPY_gamma_path, "Branch edit to 'gamma'.\n") svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m', 'Edit a file on our branch') # r8 - Do a subtree sync merge from ^/A/D to A_COPY/D. # Note that among other things this changes A_COPY/D/H/psi. svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, None, [], 'merge', sbox.repo_url + '/A/D', A_COPY_D_path) svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m', 'Automatic subtree merge') # r9 - Make an edit to A/D/H/psi. svntest.main.file_write(psi_path, "Trunk Edit to 'psi'.\n") svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m', 'Edit a file on our trunk') # Now reintegrate ^/A_COPY back to A. Prior to issue #4258's fix, the # the subtree merge to A_COPY/D just looks like any other branch edit and # was not considered a merge. So the changes which exist on A/D and were # merged to A_COPY/D, were merged *back* to A, resulting in a conflict: # # C:\...\working_copies\merge_automatic_tests-18>svn merge ^^/A_COPY A # DBG: merge.c:11461: base on source: ^/A@1 # DBG: merge.c:11462: base on target: ^/A@1 # DBG: merge.c:11567: yca ^/A@1 # DBG: merge.c:11568: base ^/A@1 # DBG: merge.c:11571: right ^/A_COPY@8 # Conflict discovered in file 'A\D\H\psi'. # Select: (p) postpone, (df) diff-full, (e) edit, # (mc) mine-conflict, (tc) theirs-conflict, # (s) show all options: p # --- Merging r2 through r9 into 'A': # C A\D\H\psi # U A\D\gamma # --- Recording mergeinfo for merge of r2 through r9 into 'A': # U A # Summary of conflicts: # Text conflicts: 1 svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir) exit_code, out, err = svntest.actions.run_and_verify_svn( None, [], svntest.verify.AnyOutput, 'merge', sbox.repo_url + '/A_COPY', A_path) # Better to produce the same warning that explicitly using the # --reintegrate option would produce: svntest.verify.verify_outputs("Automatic Reintegrate failed, but not " "in the way expected", err, None, "(svn: E195016: Reintegrate can only be used if " "revisions 2 through 9 were previously " "merged from .*/A to the reintegrate source, " "but this is not the case:\n)" "|( A_COPY\n)" "|( Missing ranges: /A:5\n)" "|(\n)" "|" + svntest.main.stack_trace_regexp, None, True) # Match *all* lines of stdout
def merge_to_reverse_cherry_subtree_to_merge_to(sbox): "sync merge considers target subtree mergeinfo" # A (--o-o-o-o------------------ # ( \ \ \ \ # ( \ \ \ \ # B ( o--o------x-------rc-----x # Some paths we'll care about. A_COPY_path = sbox.ospath('A_COPY') A_COPY_B_path = sbox.ospath('A_COPY/B') A_COPY_beta_path = sbox.ospath('A_COPY/B/E/beta') sbox.build() wc_dir = sbox.wc_dir # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then # make a few edits under A in r3-6: wc_disk, wc_status = set_up_branch(sbox) # Sync merge ^/A to A_COPY, then reverse merge r5 from ^/A/B to A_COPY/B. # This results in mergeinfo on the target which makes it appear that the # branch is synced up to r6, but the subtree mergeinfo on A_COPY/B reveals # that r5 has not been merged to that subtree: # # Properties on 'A_COPY': # svn:mergeinfo # /A:2-6 # Properties on 'A_COPY\B': # svn:mergeinfo # /A/B:2-4,6 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A', A_COPY_path) svntest.actions.run_and_verify_svn(None, [], 'merge', '-c-5', sbox.repo_url + '/A/B', A_COPY_B_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'sync merge and reverse subtree merge') # Try an automatic sync merge from ^/A to A_COPY. Revision 5 should be # merged to A_COPY/B as its subtree mergeinfo reveals that rev is missing, # like so: # # >svn merge ^/A A_COPY # --- Merging r5 into 'A_COPY\B': # U A_COPY\B\E\beta # --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY': # U A_COPY # --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY\B': # U A_COPY\B # --- Eliding mergeinfo from 'A_COPY\B': # U A_COPY\B # # But the merge ignores the subtree mergeinfo and considers # only the mergeinfo on the target itself (and thus is a no-op but for # the mergeinfo change on the root of the merge target): # # >svn merge ^/A A_COPY # --- Recording mergeinfo for merge of r7 into 'A_COPY': # U A_COPY # # >svn diff # Index: A_COPY # =================================================================== # --- A_COPY (revision 7) # +++ A_COPY (working copy) # # Property changes on: A_COPY # ___________________________________________________________________ # Modified: svn:mergeinfo # Merged /A:r7 svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) expected_output = wc.State(A_COPY_path, { 'B/E/beta': Item(status='U '), }) expected_mergeinfo_output = wc.State(A_COPY_path, { '': Item(status=' U'), 'B': Item(status=' U'), }) expected_elision_output = wc.State(A_COPY_path, { 'B': Item(status=' U'), }) expected_status = wc.State( A_COPY_path, { '': Item(status=' M'), 'B': Item(status=' M'), 'mu': Item(status=' '), 'B/E': Item(status=' '), 'B/E/alpha': Item(status=' '), 'B/E/beta': Item(status='M '), '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/chi': Item(status=' '), 'D/H/psi': Item(status=' '), 'D/H/omega': Item(status=' '), }) expected_status.tweak(wc_rev='7') expected_disk = wc.State( '', { '': Item(props={SVN_PROP_MERGEINFO: '/A:2-7'}), 'B': Item(), 'mu': Item("This is the file 'mu'.\n"), '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_path, None, None, sbox.repo_url + '/A', None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, [], True, False, A_COPY_path)
def recursive_mergeinfo(sbox): "test svn mergeinfo -R" sbox.build() wc_dir = sbox.wc_dir expected_disk, expected_status = set_up_branch(sbox) # Some paths we'll care about A_path = os.path.join(wc_dir, "A") A_COPY_path = os.path.join(wc_dir, "A_COPY") B_COPY_path = os.path.join(wc_dir, "A_COPY", "B") C_COPY_path = os.path.join(wc_dir, "A_COPY", "C") rho_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "G", "rho") H_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H") F_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "F") omega_COPY_path = os.path.join(wc_dir, "A_COPY", "D", "H", "omega") beta_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "E", "beta") A2_path = os.path.join(wc_dir, "A2") nu_path = os.path.join(wc_dir, "A2", "B", "F", "nu") nu_COPY_path = os.path.join(wc_dir, "A_COPY", "B", "F", "nu") nu2_path = os.path.join(wc_dir, "A2", "C", "nu2") # Rename A to A2 in r7. svntest.actions.run_and_verify_svn(exp_noop_up_out(6), [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'ren', A_path, A2_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'rename A to A2') # Add the files A/B/F/nu and A/C/nu2 and commit them as r8. svntest.main.file_write(nu_path, "A new file.\n") svntest.main.file_write(nu2_path, "Another new file.\n") svntest.main.run_svn(None, "add", nu_path, nu2_path) svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Add 2 new files') # Do several merges to create varied subtree mergeinfo # Merge r4 from A2 to A_COPY at depth empty svntest.actions.run_and_verify_svn(exp_noop_up_out(8), [], 'up', wc_dir) svntest.actions.run_and_verify_svn( expected_merge_output([[4]], ' U ' + A_COPY_path + '\n'), [], 'merge', '-c4', '--depth', 'empty', sbox.repo_url + '/A2', A_COPY_path) # Merge r6 from A2/D/H to A_COPY/D/H svntest.actions.run_and_verify_svn( expected_merge_output( [[6]], ['U ' + omega_COPY_path + '\n', ' G ' + H_COPY_path + '\n']), [], 'merge', '-c6', sbox.repo_url + '/A2/D/H', H_COPY_path) # Merge r5 from A2 to A_COPY svntest.actions.run_and_verify_svn( expected_merge_output( [[5]], [ 'U ' + beta_COPY_path + '\n', ' G ' + A_COPY_path + '\n', ' G ' + B_COPY_path + '\n', ' U ' + B_COPY_path + '\n', ], # Elision elides=True), [], 'merge', '-c5', sbox.repo_url + '/A2', A_COPY_path) # Reverse merge -r5 from A2/C to A_COPY/C leaving empty mergeinfo on # A_COPY/C. svntest.actions.run_and_verify_svn( expected_merge_output([[-5]], ' G ' + C_COPY_path + '\n'), [], 'merge', '-c-5', sbox.repo_url + '/A2/C', C_COPY_path) # Merge r8 from A2/B/F to A_COPY/B/F svntest.actions.run_and_verify_svn( expected_merge_output( [[8]], ['A ' + nu_COPY_path + '\n', ' G ' + F_COPY_path + '\n']), [], 'merge', '-c8', sbox.repo_url + '/A2/B/F', F_COPY_path) # Commit everything this far as r9 svntest.actions.run_and_verify_svn(None, [], 'ci', wc_dir, '-m', 'Many merges') svntest.actions.run_and_verify_svn(exp_noop_up_out(9), [], 'up', wc_dir) # Test svn mergeinfo -R / --depth infinity. # Asking for eligible revisions from A2 to A_COPY should show: # # r3 - Was never merged. # # r4 - Was merged at depth empty, so while there is mergeinfo for the # revision, the actual text change to A_COPY/D/G/rho hasn't yet # happened. # # r8* - Was only partially merged to the subtree at A_COPY/B/F. The # addition of A_COPY/C/nu2 is still outstanding. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['3', '4*', '8*'], sbox.repo_url + '/A2', sbox.repo_url + '/A_COPY', '--show-revs', 'eligible', '-R') # Do the same as above, but test that we can request the revisions # in reverse order. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['8*', '4*', '3'], sbox.repo_url + '/A2', sbox.repo_url + '/A_COPY', '--show-revs', 'eligible', '-R', '-r', '9:0') # Asking for merged revisions from A2 to A_COPY should show: # # r4* - Was merged at depth empty, so while there is mergeinfo for the # revision, the actual text change to A_COPY/D/G/rho hasn't yet # happened. # # r5 - Was merged at depth infinity to the root of the 'branch', so it # should show as fully merged. # # r6 - This was a subtree merge, but since the subtree A_COPY/D/H was # the ancestor of the only change made in r6 it is considered # fully merged. # # r8* - Was only partially merged to the subtree at A_COPY/B/F. The # addition of A_COPY/C/nu2 is still outstanding. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['4*', '5', '6', '8*'], A2_path, A_COPY_path, '--show-revs', 'merged', '--depth', 'infinity') # Do the same as above, but test that we can request the revisions # in reverse order. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(""), ['8*', '6', '5', '4*'], A2_path, A_COPY_path, '--show-revs', 'merged', '--depth', 'infinity', '-r', '9:0') # A couple tests of problems found with initial issue #3242 fixes. # We should be able to check for the merged revs from a URL to a URL # when the latter has explicit mergeinfo... svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['6'], sbox.repo_url + '/A2/D/H', sbox.repo_url + '/A_COPY/D/H', '--show-revs', 'merged') # ...and when the latter has inherited mergeinfo. svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['6'], sbox.repo_url + '/A2/D/H/omega', sbox.repo_url + '/A_COPY/D/H/omega', '--show-revs', 'merged')
def wc_target_inherits_mergeinfo_from_repos(sbox): "wc target inherits mergeinfo from repos" sbox.build() wc_dir = sbox.wc_dir wc_disk, wc_status = set_up_branch(sbox, nbr_of_branches=2) A_COPY_path = os.path.join(wc_dir, 'A_COPY') rho_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D', 'G', 'rho') gamma_2_path = os.path.join(wc_dir, 'A_COPY_2', 'D', 'gamma') tau_path = os.path.join(wc_dir, 'A', 'D', 'G', 'tau') D_COPY_path = os.path.join(wc_dir, 'A_COPY', 'D') # Merge -c5 ^/A/D/G/rho A_COPY\D\G\rho # Merge -c7 ^/A A_COPY # Commit as r8 # # This gives us some explicit mergeinfo on the "branch" root and # one of its subtrees: # # Properties on 'A_COPY\D\G\rho': # svn:mergeinfo # /A/D/G/rho:5 # Properties on 'A_COPY': # svn:mergeinfo # /A:7 svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A/D/G/rho', rho_COPY_path, '-c5') svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A', A_COPY_path, '-c7') svntest.actions.run_and_verify_svn( None, [], 'ci', '-m', 'Cherrypicks to branch subtree and root', wc_dir) # Checkout a new wc rooted at ^/A_COPY/D. subtree_wc = sbox.add_wc_path('D_COPY') svntest.actions.run_and_verify_svn(None, [], 'co', sbox.repo_url + '/A_COPY/D', subtree_wc) # Check the merged and eligible revisions both recursively and # non-recursively. # Eligible : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4', '5'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'eligible') # Eligible : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'eligible', '-R') # Merged : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['7'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'merged') # Merged : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['5', '7'], sbox.repo_url + '/A/D', subtree_wc, '--show-revs', 'merged', '-R') # Test that intersecting revisions in the 'svn mergeinfo' target # from one source don't show up as merged when asking about a different # source. # # In r9 make a change that effects two branches: svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) svntest.main.file_write(gamma_2_path, "New content.\n") svntest.main.file_write(tau_path, "New content.\n") svntest.actions.run_and_verify_svn( None, [], 'ci', '-m', 'Make changes under both A and A_COPY_2', wc_dir) # In r10 merge r9 from A_COPY_2 to A_COPY. # # This gives us this mergeinfo: # # Properties on 'A_COPY': # svn:mergeinfo # /A:7 # /A_COPY_2:9 # Properties on 'A_COPY\D\G\rho': # svn:mergeinfo # /A/D/G/rho:5 svntest.actions.run_and_verify_svn(None, [], 'merge', sbox.repo_url + '/A_COPY_2', A_COPY_path, '-c9') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'Merge r8 from A_COPY_2 to A_COPY', wc_dir) def test_svn_mergeinfo_4_way(wc_target): # Eligible : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4', '5', '9'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'eligible') # Eligible : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['4', '9'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'eligible', '-R') # Merged : Non-recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['7'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'merged') # Merged : Recursive svntest.actions.run_and_verify_mergeinfo( adjust_error_for_server_version(''), ['5', '7'], sbox.repo_url + '/A/D', wc_target, '--show-revs', 'merged', '-R') # Test while the target is the full WC and then with the subtree WC: svntest.actions.run_and_verify_svn(None, [], 'up', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'up', subtree_wc) test_svn_mergeinfo_4_way(D_COPY_path) test_svn_mergeinfo_4_way(subtree_wc)