You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2010/05/27 18:00:39 UTC
svn commit: r948873 [4/4] - in /subversion/trunk/subversion/tests/cmdline:
merge_reintegrate_tests.py merge_tests.py merge_tree_conflict_tests.py
Copied: subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py (from r948821, subversion/trunk/subversion/tests/cmdline/merge_tests.py)
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py?p2=subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py&p1=subversion/trunk/subversion/tests/cmdline/merge_tests.py&r1=948821&r2=948873&rev=948873&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py Thu May 27 16:00:39 2010
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# merge_tests.py: testing merge
+# merge_tests.py: testing tree conflicts during merge
#
# Subversion is a tool for revision control.
# See http://subversion.apache.org for more information.
@@ -40,496 +40,13 @@ SkipUnless = svntest.testcase.SkipUnless
from svntest.main import SVN_PROP_MERGEINFO
from svntest.main import server_has_mergeinfo
-from svntest.main import is_fs_case_insensitive
-from svntest.actions import fill_file_with_lines
-from svntest.actions import make_conflict_marker_text
-from svntest.actions import inject_conflict_into_expected_state
-
-def expected_merge_output(rev_ranges, additional_lines=None, foreign=False,
- elides=False, two_url=False):
- """Generate an (inefficient) regex representing the expected merge
- output and mergeinfo notifications from REV_RANGES (a list of 'range' lists
- of the form [start, end] or [single_rev] --> [single_rev - 1, single_rev]),
- and ADDITIONAL_LINES (a list of strings). If REV_RANGES is None then only
- the standard notification for a 3-way merge is expected. If ELIDES is true
- add to the regex an expression representing elision notification. If TWO_URL
- us true tweak the regex to expect the appropriate mergeinfo notification
- for a 3-way merge."""
- if rev_ranges is None:
- lines = [svntest.main.merge_notify_line(None, None, False, foreign)]
- else:
- lines = []
- for rng in rev_ranges:
- start_rev = rng[0]
- if len(rng) > 1:
- end_rev = rng[1]
- else:
- end_rev = None
- lines += [svntest.main.merge_notify_line(start_rev, end_rev,
- True, foreign)]
- lines += [svntest.main.mergeinfo_notify_line(start_rev, end_rev)]
-
- if (elides):
- lines += ["--- Eliding mergeinfo from .*\n"]
-
- if (two_url):
- lines += ["--- Recording mergeinfo for merge between repository URLs .*\n"]
-
- if isinstance(additional_lines, list):
- # Address "The Backslash Plague"
- #
- # If ADDITIONAL_LINES are present there are possibly paths in it with
- # multiple components and on Windows these components are separated with
- # '\'. These need to be escaped properly in the regexp for the match to
- # work correctly. See http://aspn.activestate.com/ASPN/docs/ActivePython
- # /2.2/howto/regex/regex.html#SECTION000420000000000000000.
- if sys.platform == 'win32':
- for i in range(0, len(additional_lines)):
- additional_lines[i] = additional_lines[i].replace("\\", "\\\\")
- lines.extend(additional_lines)
- else:
- if sys.platform == 'win32' and additional_lines != None:
- additional_lines = additional_lines.replace("\\", "\\\\")
- lines.append(str(additional_lines))
- return "|".join(lines)
-
-def check_mergeinfo_recursively(root_path, subpaths_mergeinfo):
- """Check that the mergeinfo properties on and under ROOT_PATH are those in
- SUBPATHS_MERGEINFO, a {path: mergeinfo-prop-val} dictionary."""
- expected = svntest.verify.UnorderedOutput(
- [path + ' - ' + subpaths_mergeinfo[path] + '\n'
- for path in subpaths_mergeinfo])
- svntest.actions.run_and_verify_svn(None, expected, [],
- 'propget', '-R', SVN_PROP_MERGEINFO,
- root_path)
-
-######################################################################
-# Tests
-#
-# Each test must return on success or raise on failure.
-
-
-#----------------------------------------------------------------------
-
-def textual_merges_galore(sbox):
- "performing a merge, with mixed results"
-
- ## The Plan:
- ##
- ## The goal is to test that "svn merge" does the right thing in the
- ## following cases:
- ##
- ## 1 : _ : Received changes already present in unmodified local file
- ## 2 : U : No local mods, received changes folded in without trouble
- ## 3 : G : Received changes already exist as local mods
- ## 4 : G : Received changes do not conflict with local mods
- ## 5 : C : Received changes conflict with local mods
- ##
- ## So first modify these files and commit:
- ##
- ## Revision 2:
- ## -----------
- ## A/mu ............... add ten or so lines
- ## A/D/G/rho .......... add ten or so lines
- ##
- ## Now check out an "other" working copy, from revision 2.
- ##
- ## Next further modify and commit some files from the original
- ## working copy:
- ##
- ## Revision 3:
- ## -----------
- ## A/B/lambda ......... add ten or so lines
- ## A/D/G/pi ........... add ten or so lines
- ## A/D/G/tau .......... add ten or so lines
- ## A/D/G/rho .......... add an additional ten or so lines
- ##
- ## In the other working copy (which is at rev 2), update rho back
- ## to revision 1, while giving other files local mods. This sets
- ## things up so that "svn merge -r 1:3" will test all of the above
- ## cases except case 4:
- ##
- ## case 1: A/mu .......... do nothing, the only change was in rev 2
- ## case 2: A/B/lambda .... do nothing, so we accept the merge easily
- ## case 3: A/D/G/pi ...... add same ten lines as committed in rev 3
- ## case 5: A/D/G/tau ..... add ten or so lines at the end
- ## [none]: A/D/G/rho ..... ignore what happens to this file for now
- ##
- ## Now run
- ##
- ## $ cd wc.other
- ## $ svn merge -r 1:3 url-to-repo
- ##
- ## ...and expect the right output.
- ##
- ## Now revert rho, then update it to revision 2, then *prepend* a
- ## bunch of lines, which will be separated by enough distance from
- ## the changes about to be received that the merge will be clean.
- ##
- ## $ cd wc.other/A/D/G
- ## $ svn merge -r 2:3 url-to-repo/A/D/G
- ##
- ## Which tests case 4. (Ignore the changes to the other files,
- ## we're only interested in rho here.)
-
- sbox.build()
- wc_dir = sbox.wc_dir
- # url = os.path.join(svntest.main.test_area_url, sbox.repo_dir)
-
- # Change mu and rho for revision 2
- mu_path = os.path.join(wc_dir, 'A', 'mu')
- rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
- mu_text = fill_file_with_lines(mu_path, 2)
- rho_text = fill_file_with_lines(rho_path, 2)
-
- # Create expected output tree for initial commit
- expected_output = wc.State(wc_dir, {
- 'A/mu' : Item(verb='Sending'),
- 'A/D/G/rho' : Item(verb='Sending'),
- })
-
- # Create expected status tree; all local revisions should be at 1,
- # but mu and rho should be at revision 2.
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=2)
-
- # Initial commit.
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
-
- # Make the "other" working copy
- other_wc = sbox.add_wc_path('other')
- svntest.actions.duplicate_dir(wc_dir, other_wc)
-
- # Now commit some more mods from the original working copy, to
- # produce revision 3.
- lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
- pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
- tau_path = os.path.join(wc_dir, 'A', 'D', 'G', 'tau')
-
- lambda_text = fill_file_with_lines(lambda_path, 2)
- pi_text = fill_file_with_lines(pi_path, 2)
- tau_text = fill_file_with_lines(tau_path, 2)
- additional_rho_text = fill_file_with_lines(rho_path, 2)
-
- # Created expected output tree for 'svn ci'
- expected_output = wc.State(wc_dir, {
- 'A/B/lambda' : Item(verb='Sending'),
- 'A/D/G/pi' : Item(verb='Sending'),
- 'A/D/G/tau' : Item(verb='Sending'),
- 'A/D/G/rho' : Item(verb='Sending'),
- })
-
- # Create expected status tree.
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.tweak('A/mu', wc_rev=2)
- expected_status.tweak('A/B/lambda', 'A/D/G/pi', 'A/D/G/tau', 'A/D/G/rho',
- wc_rev=3)
-
- # Commit revision 3.
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
-
- # Make local mods in wc.other
- other_pi_path = os.path.join(other_wc, 'A', 'D', 'G', 'pi')
- other_rho_path = os.path.join(other_wc, 'A', 'D', 'G', 'rho')
- other_tau_path = os.path.join(other_wc, 'A', 'D', 'G', 'tau')
-
- # For A/mu and A/B/lambda, we do nothing. For A/D/G/pi, we add the
- # same ten lines as were already committed in revision 3.
- # (Remember, wc.other is only at revision 2, so it doesn't have
- # these changes.)
- svntest.main.file_append(other_pi_path, pi_text)
-
- # We skip A/D/G/rho in this merge; it will be tested with a separate
- # merge command. Temporarily put it back to revision 1, so this
- # merge succeeds cleanly.
- svntest.actions.run_and_verify_svn(None, None, [],
- 'up', '-r', '1', other_rho_path)
-
- # For A/D/G/tau, we append few different lines, to conflict with the
- # few lines appended in revision 3.
- other_tau_text = fill_file_with_lines(other_tau_path, 2,
- line_descrip="Conflicting line")
-
- # Do the first merge, revs 1:3. This tests all the cases except
- # case 4, which we'll handle in a second pass.
- expected_output = wc.State(other_wc, {'A/B/lambda' : Item(status='U '),
- 'A/D/G/rho' : Item(status='U '),
- 'A/D/G/tau' : Item(status='C '),
- })
- expected_mergeinfo_output = wc.State(other_wc, {'' : Item(status=' U')})
- expected_elision_output = wc.State(other_wc, {})
- expected_disk = svntest.main.greek_state.copy()
- expected_disk.tweak('A/mu',
- contents=expected_disk.desc['A/mu'].contents
- + mu_text)
- expected_disk.tweak('A/B/lambda',
- contents=expected_disk.desc['A/B/lambda'].contents
- + lambda_text)
- expected_disk.tweak('A/D/G/rho',
- contents=expected_disk.desc['A/D/G/rho'].contents
- + rho_text + additional_rho_text)
- expected_disk.tweak('A/D/G/pi',
- contents=expected_disk.desc['A/D/G/pi'].contents
- + pi_text)
-
- expected_status = svntest.actions.get_virginal_state(other_wc, 1)
- expected_status.tweak('', status=' M')
- expected_status.tweak('A/mu', wc_rev=2)
- expected_status.tweak('A/B/lambda', status='M ')
- expected_status.tweak('A/D/G/pi', status='M ')
- expected_status.tweak('A/D/G/rho', status='M ')
-
- inject_conflict_into_expected_state('A/D/G/tau', expected_disk,
- expected_status, other_tau_text, tau_text,
- 3)
-
- expected_skip = wc.State('', { })
-
- tau_conflict_support_files = ["tau\.working",
- "tau\.merge-right\.r3",
- "tau\.merge-left\.r1"]
-
- svntest.actions.run_and_verify_merge(other_wc, '1', '3',
- sbox.repo_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None,
- svntest.tree.detect_conflict_files,
- list(tau_conflict_support_files))
-
- # 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
- # whole expected_foo routine for these intermediate operations;
- # they're not what we're here to test, after all, so it's enough to
- # know that they worked. Is this a bad practice? ###
- #
- # run_and_verify_merge doesn't support merging to a file WCPATH
- # so use run_and_verify_svn.
- svntest.actions.run_and_verify_svn(
- None,
- expected_merge_output([[-3]],
- ['G ' + other_rho_path + '\n',
- ' G ' + other_rho_path + '\n',]),
- [], 'merge', '-c-3',
- sbox.repo_url + '/A/D/G/rho',
- other_rho_path)
-
- # Now *prepend* ten or so lines to A/D/G/rho. Since rho had ten
- # lines appended in revision 2, and then another ten in revision 3,
- # these new local mods will be separated from the rev 3 changes by
- # enough distance that they won't conflict, so the merge should be
- # clean.
- other_rho_text = ""
- for x in range(1,10):
- other_rho_text = other_rho_text + 'Unobtrusive line ' + repr(x) + ' in rho\n'
- current_other_rho_text = open(other_rho_path).read()
- svntest.main.file_write(other_rho_path,
- other_rho_text + current_other_rho_text)
-
- # We expect no merge attempt for pi and tau because they inherit
- # mergeinfo from the WC root. There is explicit mergeinfo on rho
- # ('/A/D/G/rho:2') so expect it to be merged (cleanly).
- G_path = os.path.join(other_wc, 'A', 'D', 'G')
- expected_output = wc.State(os.path.join(other_wc, 'A', 'D', 'G'),
- {'rho' : Item(status='G ')})
- expected_mergeinfo_output = wc.State(G_path, {
- '' : Item(status=' G'),
- 'rho' : Item(status=' G')
- })
- expected_elision_output = wc.State(G_path, {
- '' : Item(status=' U'),
- 'rho' : Item(status=' U')
- })
- expected_disk = wc.State("", {
- 'pi' : Item("This is the file 'pi'.\n"),
- 'rho' : Item("This is the file 'rho'.\n"),
- 'tau' : Item("This is the file 'tau'.\n"),
- })
- expected_disk.tweak('rho',
- contents=other_rho_text
- + expected_disk.desc['rho'].contents
- + rho_text
- + additional_rho_text)
- expected_disk.tweak('pi',
- contents=expected_disk.desc['pi'].contents
- + pi_text)
-
- expected_status = wc.State(os.path.join(other_wc, 'A', 'D', 'G'),
- { '' : Item(wc_rev=1, status=' '),
- 'rho' : Item(wc_rev=1, status='M '),
- 'pi' : Item(wc_rev=1, status='M '),
- 'tau' : Item(wc_rev=1, status='C '),
- })
-
- inject_conflict_into_expected_state('tau', expected_disk, expected_status,
- other_tau_text, tau_text, 3)
-
- # Do the merge, but check svn:mergeinfo props separately since
- # run_and_verify_merge would attempt to proplist tau's conflict
- # files if we asked it to check props.
- svntest.actions.run_and_verify_merge(
- os.path.join(other_wc, 'A', 'D', 'G'),
- '2', '3',
- sbox.repo_url + '/A/D/G', None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None,
- svntest.tree.detect_conflict_files, list(tau_conflict_support_files))
-
-
- svntest.actions.run_and_verify_svn(None, [], [],
- 'propget', SVN_PROP_MERGEINFO,
- os.path.join(other_wc,
- "A", "D", "G", "rho"))
-
-
-#----------------------------------------------------------------------
-
-# Merge should copy-with-history when adding files or directories
-
-def add_with_history(sbox):
- "merge and add new files/dirs with history"
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- C_path = os.path.join(wc_dir, 'A', 'C')
- F_path = os.path.join(wc_dir, 'A', 'B', 'F')
- F_url = sbox.repo_url + '/A/B/F'
-
- Q_path = os.path.join(F_path, 'Q')
- Q2_path = os.path.join(F_path, 'Q2')
- foo_path = os.path.join(F_path, 'foo')
- foo2_path = os.path.join(F_path, 'foo2')
- bar_path = os.path.join(F_path, 'Q', 'bar')
- bar2_path = os.path.join(F_path, 'Q', 'bar2')
-
- svntest.main.run_svn(None, 'mkdir', Q_path)
- svntest.main.run_svn(None, 'mkdir', Q2_path)
- svntest.main.file_append(foo_path, "foo")
- svntest.main.file_append(foo2_path, "foo2")
- svntest.main.file_append(bar_path, "bar")
- svntest.main.file_append(bar2_path, "bar2")
- svntest.main.run_svn(None, 'add', foo_path, foo2_path, bar_path, bar2_path)
- svntest.main.run_svn(None, 'propset', 'x', 'x', Q2_path)
- svntest.main.run_svn(None, 'propset', 'y', 'y', foo2_path)
- svntest.main.run_svn(None, 'propset', 'z', 'z', bar2_path)
-
- expected_output = wc.State(wc_dir, {
- 'A/B/F/Q' : Item(verb='Adding'),
- 'A/B/F/Q2' : Item(verb='Adding'),
- 'A/B/F/Q/bar' : Item(verb='Adding'),
- 'A/B/F/Q/bar2': Item(verb='Adding'),
- 'A/B/F/foo' : Item(verb='Adding'),
- 'A/B/F/foo2' : Item(verb='Adding'),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- 'A/B/F/Q' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q2' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q/bar' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q/bar2': Item(status=' ', wc_rev=2),
- 'A/B/F/foo' : Item(status=' ', wc_rev=2),
- 'A/B/F/foo2' : Item(status=' ', wc_rev=2),
- })
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
-
- expected_output = wc.State(C_path, {
- 'Q' : Item(status='A '),
- 'Q2' : Item(status='A '),
- 'Q/bar' : Item(status='A '),
- 'Q/bar2' : Item(status='A '),
- 'foo' : Item(status='A '),
- 'foo2' : Item(status='A '),
- })
- expected_mergeinfo_output = wc.State(C_path, {
- '' : Item(status=' U'),
- })
- expected_elision_output = wc.State(C_path, {
- })
- expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
- 'Q' : Item(),
- 'Q2' : Item(props={'x' : 'x'}),
- 'Q/bar' : Item("bar"),
- 'Q/bar2' : Item("bar2", props={'z' : 'z'}),
- 'foo' : Item("foo"),
- 'foo2' : Item("foo2", props={'y' : 'y'}),
- })
- expected_status = wc.State(C_path, {
- '' : Item(status=' M', wc_rev=1),
- 'Q' : Item(status='A ', wc_rev='-', copied='+'),
- 'Q2' : Item(status='A ', wc_rev='-', copied='+'),
- 'Q/bar' : Item(status=' ', wc_rev='-', copied='+'),
- 'Q/bar2' : Item(status=' ', wc_rev='-', copied='+'),
- 'foo' : Item(status='A ', wc_rev='-', copied='+'),
- 'foo2' : Item(status='A ', wc_rev='-', copied='+'),
- })
-
- expected_skip = wc.State(C_path, { })
-
- svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None,
- 1) # check props
-
- expected_output = svntest.wc.State(wc_dir, {
- 'A/C' : Item(verb='Sending'),
- 'A/C/Q' : Item(verb='Adding'),
- 'A/C/Q2' : Item(verb='Adding'),
- 'A/C/foo' : Item(verb='Adding'),
- 'A/C/foo2' : Item(verb='Adding'),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- 'A/C' : Item(status=' ', wc_rev=3),
- 'A/B/F/Q' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q2' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q/bar' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q/bar2': Item(status=' ', wc_rev=2),
- 'A/B/F/foo' : Item(status=' ', wc_rev=2),
- 'A/B/F/foo2' : Item(status=' ', wc_rev=2),
- 'A/C/Q' : Item(status=' ', wc_rev=3),
- 'A/C/Q2' : Item(status=' ', wc_rev=3),
- 'A/C/Q/bar' : Item(status=' ', wc_rev=3),
- 'A/C/Q/bar2' : Item(status=' ', wc_rev=3),
- 'A/C/foo' : Item(status=' ', wc_rev=3),
- 'A/C/foo2' : Item(status=' ', wc_rev=3),
- })
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
+from merge_tests import set_up_branch
+from merge_tests import svn_commit
+from merge_tests import svn_delete
+from merge_tests import svn_copy
+from merge_tests import svn_merge
#----------------------------------------------------------------------
-
-# This test involves tree conflicts.
def delete_file_and_dir(sbox):
"merge that deletes items"
@@ -640,229 +157,8 @@ def delete_file_and_dir(sbox):
None, None, None, None, None,
True)
-
-#----------------------------------------------------------------------
-
-# Issue 953
-def simple_property_merges(sbox):
- "some simple property merges"
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # Add a property to a file and a directory
- alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
- beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
- E_path = os.path.join(wc_dir, 'A', 'B', 'E')
-
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'foo', 'foo_val',
- alpha_path)
- # A binary, non-UTF8 property value
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'foo', 'foo\201val',
- beta_path)
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'foo', 'foo_val',
- E_path)
-
- # Commit change as rev 2
- expected_output = svntest.wc.State(wc_dir, {
- 'A/B/E' : Item(verb='Sending'),
- 'A/B/E/alpha' : Item(verb='Sending'),
- 'A/B/E/beta' : Item(verb='Sending'),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
- wc_rev=2, status=' ')
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output, expected_status,
- None, wc_dir)
- svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
- # Copy B to B2 as rev 3
- B_url = sbox.repo_url + '/A/B'
- B2_url = sbox.repo_url + '/A/B2'
-
- svntest.actions.run_and_verify_svn(None, None, [],
- 'copy', '-m', 'copy B to B2',
- B_url, B2_url)
- svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
- # Modify a property and add a property for the file and directory
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'foo', 'mod_foo', alpha_path)
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'bar', 'bar_val', alpha_path)
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'foo', 'mod\201foo', beta_path)
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'bar', 'bar\201val', beta_path)
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'foo', 'mod_foo', E_path)
- svntest.actions.run_and_verify_svn(None, None, [],
- 'propset', 'bar', 'bar_val', E_path)
-
- # Commit change as rev 4
- expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
- expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
- wc_rev=4, status=' ')
- expected_status.add({
- 'A/B2' : Item(status=' ', wc_rev=3),
- 'A/B2/E' : Item(status=' ', wc_rev=3),
- 'A/B2/E/alpha' : Item(status=' ', wc_rev=3),
- 'A/B2/E/beta' : Item(status=' ', wc_rev=3),
- 'A/B2/F' : Item(status=' ', wc_rev=3),
- 'A/B2/lambda' : Item(status=' ', wc_rev=3),
- })
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output, expected_status,
- None, wc_dir)
- svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
- pristine_status = expected_status
- pristine_status.tweak(wc_rev=4)
-
- # Merge B 3:4 into B2
- B2_path = os.path.join(wc_dir, 'A', 'B2')
- expected_output = wc.State(B2_path, {
- 'E' : Item(status=' U'),
- 'E/alpha' : Item(status=' U'),
- 'E/beta' : Item(status=' U'),
- })
- expected_mergeinfo_output = wc.State(B2_path, {
- '' : Item(status=' U'),
- })
- expected_elision_output = wc.State(B2_path, {
- })
- expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:4'}),
- 'E' : Item(),
- 'E/alpha' : Item("This is the file 'alpha'.\n"),
- 'E/beta' : Item("This is the file 'beta'.\n"),
- 'F' : Item(),
- 'lambda' : Item("This is the file 'lambda'.\n"),
- })
- expected_disk.tweak('E', 'E/alpha',
- props={'foo' : 'mod_foo', 'bar' : 'bar_val'})
- expected_disk.tweak('E/beta',
- props={'foo' : 'mod\201foo', 'bar' : 'bar\201val'})
- expected_status = wc.State(B2_path, {
- '' : Item(status=' M'),
- 'E' : Item(status=' M'),
- 'E/alpha' : Item(status=' M'),
- 'E/beta' : Item(status=' M'),
- 'F' : Item(status=' '),
- 'lambda' : Item(status=' '),
- })
- expected_status.tweak(wc_rev=4)
- expected_skip = wc.State('', { })
- svntest.actions.run_and_verify_merge(B2_path, '3', '4', B_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None, 1)
-
- # Revert merge
- svntest.actions.run_and_verify_svn(None, None, [],
- 'revert', '--recursive', wc_dir)
- svntest.actions.run_and_verify_status(wc_dir, pristine_status)
-
- # Merge B 2:1 into B2 (B2's mergeinfo should get elided away)
- expected_status.tweak('', status=' ')
- expected_disk.remove('')
- expected_disk.tweak('E', 'E/alpha', 'E/beta', props={})
- expected_elision_output = wc.State(B2_path, {
- '' : Item(status=' U'),
- })
- svntest.actions.run_and_verify_merge(B2_path, '2', '1', B_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None, 1)
-
- def error_message(property, old_value, new_value):
- return "Trying to change property '%s' from '%s' to '%s',\n" \
- "but it has been locally deleted.\n" % (property, old_value, new_value)
-
- # Merge B 3:4 into B2 now causes a conflict
- expected_disk.add({
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:4'}),
- 'E/dir_conflicts.prej'
- : Item(error_message('foo', 'foo_val', 'mod_foo')),
- 'E/alpha.prej'
- : Item(error_message('foo', 'foo_val', 'mod_foo')),
- 'E/beta.prej'
- : Item(error_message('foo', 'foo?\\129val', 'mod?\\129foo')),
- })
- expected_disk.tweak('E', 'E/alpha', props={'bar' : 'bar_val'})
- expected_disk.tweak('E/beta', props={'bar' : 'bar\201val'})
- expected_status.tweak('', status=' M')
- expected_status.tweak('E', 'E/alpha', 'E/beta', status=' C')
- expected_output.tweak('E', 'E/alpha', 'E/beta', status=' C')
- expected_elision_output = wc.State(B2_path, {
- })
- svntest.actions.run_and_verify_merge(B2_path, '3', '4', B_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None, 1)
-
- # issue 1109 : single file property merge. This test performs a merge
- # that should be a no-op (adding properties that are already present).
- svntest.actions.run_and_verify_svn(None, None, [],
- 'revert', '--recursive', wc_dir)
- svntest.actions.run_and_verify_status(wc_dir, pristine_status)
-
- # Copy A at rev 4 to A2 to make revision 5.
- A_url = sbox.repo_url + '/A'
- A2_url = sbox.repo_url + '/A2'
- svntest.actions.run_and_verify_svn(None,
- ['\n', 'Committed revision 5.\n'], [],
- 'copy', '-m', 'copy A to A2',
- A_url, A2_url)
-
- # Re-root the WC at A2.
- svntest.actions.run_and_verify_svn(None, None, [], 'switch', A2_url, wc_dir)
-
- # Attempt to re-merge rev 4 of the original A's alpha. Mergeinfo
- # inherited from A2 (created by its copy from A) allows us to avoid
- # a repeated merge.
- alpha_url = sbox.repo_url + '/A/B/E/alpha'
- alpha_path = os.path.join(wc_dir, 'B', 'E', 'alpha')
-
- # Cannot use run_and_verify_merge with a file target
- svntest.actions.run_and_verify_svn(None, [], [], 'merge', '-r', '3:4',
- alpha_url, alpha_path)
-
- exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
- 'pl', alpha_path)
-
- saw_foo = 0
- saw_bar = 0
- for line in output:
- if re.match("\\s*foo\\s*$", line):
- saw_foo = 1
- if re.match("\\s*bar\\s*$", line):
- saw_bar = 1
-
- if not saw_foo or not saw_bar:
- raise svntest.Failure("Expected properties not found")
-
-
#----------------------------------------------------------------------
# This is a regression for issue #1176.
-
-# This test involves tree conflicts.
def merge_catches_nonexistent_target(sbox):
"merge should not die if a target file is absent"
@@ -964,10 +260,7 @@ def merge_catches_nonexistent_target(sbo
})
svntest.actions.run_and_verify_unquiet_status('', expected_status)
-
#----------------------------------------------------------------------
-
-# This test involves tree conflicts.
def merge_tree_deleted_in_target(sbox):
"merge on deleted directory in target"
@@ -1042,620 +335,38 @@ def merge_tree_deleted_in_target(sbox):
svntest.actions.run_and_verify_unquiet_status(I_path, expected_status)
#----------------------------------------------------------------------
-# Issue #2515
-
-# This test involves tree conflicts.
-def merge_added_dir_to_deleted_in_target(sbox):
- "merge an added dir on a deleted dir in target"
+# Regression test for issue #2403: Incorrect 3-way merge of "added"
+# binary file which already exists (unmodified) in the WC
+def three_way_merge_add_of_existing_binary_file(sbox):
+ "3-way merge of 'file add' into existing binary"
sbox.build()
wc_dir = sbox.wc_dir
- # copy B to a new directory, I.
- # delete F in I.
- # add J to B/F.
- # merge add to I.
-
- B_url = sbox.repo_url + '/A/B'
- I_url = sbox.repo_url + '/A/I'
- F_url = sbox.repo_url + '/A/I/F'
- J_url = sbox.repo_url + '/A/B/F/J'
- I_path = os.path.join(wc_dir, 'A', 'I')
-
-
- svntest.actions.run_and_verify_svn(None, None, [],
- 'cp', B_url, I_url, '-m', 'rev 2')
-
+ # Create a branch of A, creating revision 2.
+ A_url = sbox.repo_url + "/A"
+ branch_A_url = sbox.repo_url + "/copy-of-A"
svntest.actions.run_and_verify_svn(None, None, [],
- 'rm', F_url, '-m', 'rev 3')
+ "cp",
+ A_url, branch_A_url,
+ "-m", "Creating copy-of-A")
- svntest.actions.run_and_verify_svn(None, None, [],
- 'mkdir', '-m', 'rev 4', J_url)
+ # Add a binary file to the WC.
+ theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
+ # Write PNG file data into 'A/theta'.
+ A_path = os.path.join(wc_dir, 'A')
+ theta_path = os.path.join(wc_dir, 'A', 'theta')
+ svntest.main.file_write(theta_path, theta_contents, 'wb')
- svntest.actions.run_and_verify_svn(None, None, [],
- 'up', os.path.join(wc_dir,'A'))
+ svntest.main.run_svn(None, "add", theta_path)
- expected_output = wc.State(I_path, {
- 'F' : Item(status=' ', treeconflict='C'),
- })
- expected_mergeinfo_output = wc.State(I_path, {
- '' : Item(status=' U'),
- })
- expected_elision_output = wc.State(I_path, {
+ # Commit the new binary file to the repos, creating revision 3.
+ expected_output = svntest.wc.State(wc_dir, {
+ "A/theta" : Item(verb="Adding (bin)"),
})
- expected_disk = wc.State('', {
- 'E' : Item(),
- 'E/alpha' : Item("This is the file 'alpha'.\n"),
- 'E/beta' : Item("This is the file 'beta'.\n"),
- 'lambda' : Item("This is the file 'lambda'.\n"),
- })
- expected_skip = wc.State(I_path, {
- })
-
- svntest.actions.run_and_verify_merge(I_path, '2', '4', B_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- None,
- expected_skip,
- None, None, None, None, None,
- 0, 0)
-
-#----------------------------------------------------------------------
-# This is a regression for issue #1176.
-
-def merge_similar_unrelated_trees(sbox):
- "merging similar trees ancestrally unrelated"
-
- ## See http://subversion.tigris.org/issues/show_bug.cgi?id=1249. ##
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # Simple test. Make three directories with the same content.
- # Modify some stuff in the second one. Now merge
- # (firstdir:seconddir->thirddir).
-
- base1_path = os.path.join(wc_dir, 'base1')
- base2_path = os.path.join(wc_dir, 'base2')
- apply_path = os.path.join(wc_dir, 'apply')
-
- base1_url = os.path.join(sbox.repo_url + '/base1')
- base2_url = os.path.join(sbox.repo_url + '/base2')
-
- # Make a tree of stuff ...
- os.mkdir(base1_path)
- svntest.main.file_append(os.path.join(base1_path, 'iota'),
- "This is the file iota\n")
- os.mkdir(os.path.join(base1_path, 'A'))
- svntest.main.file_append(os.path.join(base1_path, 'A', 'mu'),
- "This is the file mu\n")
- os.mkdir(os.path.join(base1_path, 'A', 'B'))
- svntest.main.file_append(os.path.join(base1_path, 'A', 'B', 'alpha'),
- "This is the file alpha\n")
- svntest.main.file_append(os.path.join(base1_path, 'A', 'B', 'beta'),
- "This is the file beta\n")
-
- # ... Copy it twice ...
- shutil.copytree(base1_path, base2_path)
- shutil.copytree(base1_path, apply_path)
-
- # ... Gonna see if merge is naughty or nice!
- svntest.main.file_append(os.path.join(base2_path, 'A', 'mu'),
- "A new line in mu.\n")
- os.rename(os.path.join(base2_path, 'A', 'B', 'beta'),
- os.path.join(base2_path, 'A', 'B', 'zeta'))
-
- svntest.actions.run_and_verify_svn(None, None, [],
- 'add', base1_path, base2_path, apply_path)
-
- svntest.actions.run_and_verify_svn(None, None, [],
- 'ci', '-m', 'rev 2', wc_dir)
-
- expected_output = wc.State(apply_path, {
- 'A/mu' : Item(status='U '),
- 'A/B/zeta' : Item(status='A '),
- 'A/B/beta' : Item(status='D '),
- })
-
- # run_and_verify_merge doesn't support 'svn merge URL URL path'
- svntest.actions.run_and_verify_svn(None, None, [],
- 'merge',
- '--ignore-ancestry',
- base1_url, base2_url,
- apply_path)
-
- expected_status = wc.State(apply_path, {
- '' : Item(status=' '),
- 'A' : Item(status=' '),
- 'A/mu' : Item(status='M '),
- 'A/B' : Item(status=' '),
- 'A/B/zeta' : Item(status='A ', copied='+'),
- 'A/B/alpha' : Item(status=' '),
- 'A/B/beta' : Item(status='D '),
- 'iota' : Item(status=' '),
- })
- expected_status.tweak(wc_rev=2)
- expected_status.tweak('A/B/zeta', wc_rev='-')
- svntest.actions.run_and_verify_status(apply_path, expected_status)
-
-#----------------------------------------------------------------------
-def merge_one_file_helper(sbox, arg_flav, record_only = 0):
- "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
-
- if arg_flav not in ('r', 'c', '*'):
- raise svntest.Failure("Unrecognized flavor of merge argument")
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- rho_rel_path = os.path.join('A', 'D', 'G', 'rho')
- rho_path = os.path.join(wc_dir, rho_rel_path)
- G_path = os.path.join(wc_dir, 'A', 'D', 'G')
- rho_url = sbox.repo_url + '/A/D/G/rho'
-
- # Change rho for revision 2
- svntest.main.file_append(rho_path, 'A new line in rho.\n')
-
- expected_output = wc.State(wc_dir, { rho_rel_path : Item(verb='Sending'), })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.tweak('A/D/G/rho', wc_rev=2)
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
-
- # Backdate rho to revision 1, so we can merge in the rev 2 changes.
- svntest.actions.run_and_verify_svn(None, None, [],
- 'up', '-r', '1', rho_path)
-
- # Try one merge with an explicit target; it should succeed.
- ### Yes, it would be nice to use run_and_verify_merge(), but it
- # appears to be impossible to get the expected_foo trees working
- # right. I think something is still assuming a directory target.
- if arg_flav == 'r':
- svntest.actions.run_and_verify_svn(
- None,
- expected_merge_output([[2]],
- ['U ' + rho_path + '\n',
- ' U ' + rho_path + '\n']),
- [], 'merge', '-r', '1:2', rho_url, rho_path)
- elif arg_flav == 'c':
- svntest.actions.run_and_verify_svn(
- None,
- expected_merge_output([[2]],
- ['U ' + rho_path + '\n',
- ' U ' + rho_path + '\n']),
- [], 'merge', '-c', '2', rho_url, rho_path)
- elif arg_flav == '*':
- svntest.actions.run_and_verify_svn(
- None,
- expected_merge_output([[2]],
- ['U ' + rho_path + '\n',
- ' U ' + rho_path + '\n']),
- [], 'merge', rho_url, rho_path)
-
- expected_status.tweak(wc_rev=1)
- expected_status.tweak('A/D/G/rho', status='MM')
- svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
- # Inspect rho, make sure it's right.
- rho_text = svntest.tree.get_text(rho_path)
- if rho_text != "This is the file 'rho'.\nA new line in rho.\n":
- raise svntest.Failure("Unexpected text in merged '" + rho_path + "'")
-
- # Restore rho to pristine revision 1, for another merge.
- svntest.actions.run_and_verify_svn(None, None, [], 'revert', rho_path)
- expected_status.tweak('A/D/G/rho', status=' ')
- svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
- # Cd into the directory and run merge with no targets.
- # It should still merge into rho.
- saved_cwd = os.getcwd()
- os.chdir(G_path)
-
- # Cannot use run_and_verify_merge with a file target
- merge_cmd = ['merge']
- if arg_flav == 'r':
- merge_cmd += ['-r', '1:2']
- elif arg_flav == 'c':
- merge_cmd += ['-c', '2']
-
- if record_only:
- expected_output = expected_merge_output([[2]],
- [' U rho\n'])
- merge_cmd.append('--record-only')
- rho_expected_status = ' M'
- else:
- expected_output = expected_merge_output([[2]],
- ['U rho\n',
- ' U rho\n'])
- rho_expected_status = 'MM'
- merge_cmd.append(rho_url)
-
- svntest.actions.run_and_verify_svn(None, expected_output, [], *merge_cmd)
-
- # Inspect rho, make sure it's right.
- rho_text = svntest.tree.get_text('rho')
- if record_only:
- expected_text = "This is the file 'rho'.\n"
- else:
- expected_text = "This is the file 'rho'.\nA new line in rho.\n"
- if rho_text != expected_text:
- print("")
- raise svntest.Failure("Unexpected text merged to 'rho' in '" +
- G_path + "'")
- os.chdir(saved_cwd)
-
- expected_status.tweak('A/D/G/rho', status=rho_expected_status)
- svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
-def merge_one_file_using_r(sbox):
- "merge one file (issue #1150) using the -r option"
- merge_one_file_helper(sbox, 'r')
-
-def merge_one_file_using_c(sbox):
- "merge one file (issue #1150) using the -c option"
- merge_one_file_helper(sbox, 'c')
-
-def merge_one_file_using_implicit_revs(sbox):
- "merge one file without explicit revisions"
- merge_one_file_helper(sbox, '*')
-
-def merge_record_only(sbox):
- "mark a revision range as merged"
- merge_one_file_helper(sbox, 'r', 1)
-
-#----------------------------------------------------------------------
-# This is a regression for the enhancement added in issue #785.
-
-def merge_with_implicit_target_helper(sbox, arg_flav):
- "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
-
- if arg_flav not in ('r', 'c', '*'):
- raise svntest.Failure("Unrecognized flavor of merge argument")
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # Change mu for revision 2
- mu_path = os.path.join(wc_dir, 'A', 'mu')
- orig_mu_text = svntest.tree.get_text(mu_path)
- added_mu_text = ""
- for x in range(2,11):
- added_mu_text = added_mu_text + 'This is line ' + repr(x) + ' in mu\n'
- svntest.main.file_append(mu_path, added_mu_text)
-
- # Create expected output tree for initial commit
- expected_output = wc.State(wc_dir, {
- 'A/mu' : Item(verb='Sending'),
- })
-
- # Create expected status tree; all local revisions should be at 1,
- # but mu should be at revision 2.
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.tweak('A/mu', wc_rev=2)
-
- # Initial commit.
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
-
- # Make the "other" working copy, at r1
- other_wc = sbox.add_wc_path('other')
- svntest.actions.duplicate_dir(wc_dir, other_wc)
- svntest.main.run_svn(None, 'up', '-r', 1, other_wc)
-
- # Try the merge without an explicit target; it should succeed.
- # Can't use run_and_verify_merge cuz it expects a directory argument.
- mu_url = sbox.repo_url + '/A/mu'
-
- os.chdir(os.path.join(other_wc, 'A'))
-
- # merge using filename for sourcepath
- # Cannot use run_and_verify_merge with a file target
- if arg_flav == 'r':
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[2]],
- ['U mu\n',
- ' U mu\n']),
- [],
- 'merge', '-r', '1:2', 'mu')
- elif arg_flav == 'c':
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[2]],
- ['U mu\n',
- ' U mu\n']),
- [],
- 'merge', '-c', '2', 'mu')
-
- elif arg_flav == '*':
- # Without a peg revision, the default merge range of BASE:1 (which
- # is a no-op) will be chosen. Let's do it both ways (no-op first,
- # of course).
- svntest.actions.run_and_verify_svn(None, None, [], 'merge', 'mu')
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[2]],
- ['U mu\n',
- ' U mu\n']),
- [],
- 'merge', 'mu@2')
-
- # sanity-check resulting file
- if svntest.tree.get_text('mu') != orig_mu_text + added_mu_text:
- raise svntest.Failure("Unexpected text in 'mu'")
-
- # merge using URL for sourcepath
- if arg_flav == 'r':
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[-2]],
- ['G mu\n',
- ' U mu\n',
- ' G mu\n',],
- elides=True),
- [],
- 'merge', '-r', '2:1', mu_url)
- elif arg_flav == 'c':
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[-2]],
- ['G mu\n',
- ' U mu\n',
- ' G mu\n'],
- elides=True),
- [],
- 'merge', '-c', '-2', mu_url)
- elif arg_flav == '*':
- # Implicit merge source URL and revision range detection is for
- # forward merges only (e.g. non-reverts). Undo application of
- # r2 to enable continuation of the test case.
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[-2]],
- ['G mu\n',
- ' U mu\n',
- ' G mu\n'],
- elides=True),
- [],
- 'merge', '-c', '-2', mu_url)
-
- # sanity-check resulting file
- if svntest.tree.get_text('mu') != orig_mu_text:
- raise svntest.Failure("Unexpected text '%s' in 'mu', expected '%s'" %
- (svntest.tree.get_text('mu'), orig_mu_text))
-
-
-
-def merge_with_implicit_target_using_r(sbox):
- "merging a file w/no explicit target path using -r"
- merge_with_implicit_target_helper(sbox, 'r')
-
-def merge_with_implicit_target_using_c(sbox):
- "merging a file w/no explicit target path using -c"
- merge_with_implicit_target_helper(sbox, 'c')
-
-def merge_with_implicit_target_and_revs(sbox):
- "merging a file w/no explicit target path or revs"
- merge_with_implicit_target_helper(sbox, '*')
-
-
-#----------------------------------------------------------------------
-
-def merge_with_prev(sbox):
- "merge operations using PREV revision"
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # Change mu for revision 2
- mu_path = os.path.join(wc_dir, 'A', 'mu')
- orig_mu_text = svntest.tree.get_text(mu_path)
- added_mu_text = ""
- for x in range(2,11):
- added_mu_text = added_mu_text + '\nThis is line ' + repr(x) + ' in mu'
- added_mu_text += "\n"
- svntest.main.file_append(mu_path, added_mu_text)
-
- zot_path = os.path.join(wc_dir, 'A', 'zot')
-
- svntest.main.file_append(zot_path, "bar")
- svntest.main.run_svn(None, 'add', zot_path)
-
- # Create expected output tree for initial commit
- expected_output = wc.State(wc_dir, {
- 'A/mu' : Item(verb='Sending'),
- 'A/zot' : Item(verb='Adding'),
- })
-
- # Create expected status tree; all local revisions should be at 1,
- # but mu should be at revision 2.
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.tweak('A/mu', wc_rev=2)
- expected_status.add({'A/zot' : Item(status=' ', wc_rev=2)})
-
- # Initial commit.
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
- wc_dir)
-
- # Make some other working copies
- other_wc = sbox.add_wc_path('other')
- svntest.actions.duplicate_dir(wc_dir, other_wc)
-
- another_wc = sbox.add_wc_path('another')
- svntest.actions.duplicate_dir(wc_dir, another_wc)
-
- was_cwd = os.getcwd()
-
- os.chdir(os.path.join(other_wc, 'A'))
-
- # Try to revert the last change to mu via svn merge
- # Cannot use run_and_verify_merge with a file target
- svntest.actions.run_and_verify_svn(None,
- expected_merge_output([[-2]],
- ['U mu\n',
- ' U mu\n'],
- elides=True),
- [],
- 'merge', '-r', 'HEAD:PREV', 'mu')
-
- # sanity-check resulting file
- if svntest.tree.get_text('mu') != orig_mu_text:
- raise svntest.Failure("Unexpected text in 'mu'")
-
- os.chdir(was_cwd)
-
- other_status = expected_status
- other_status.wc_dir = other_wc
- other_status.tweak('A/mu', status='M ', wc_rev=2)
- other_status.tweak('A/zot', wc_rev=2)
- svntest.actions.run_and_verify_status(other_wc, other_status)
-
- os.chdir(another_wc)
-
- # ensure 'A' will be at revision 2
- svntest.actions.run_and_verify_svn(None, None, [], 'up')
-
- # now try a revert on a directory, and verify that it removed the zot
- # file we had added previously
- svntest.actions.run_and_verify_svn(None, None, [],
- 'merge', '-r', 'COMMITTED:PREV',
- 'A', 'A')
-
- if svntest.tree.get_text('A/zot') != None:
- raise svntest.Failure("Unexpected text in 'A/zot'")
-
- os.chdir(was_cwd)
-
- another_status = expected_status
- another_status.wc_dir = another_wc
- another_status.tweak(wc_rev=2)
- another_status.tweak('A/mu', status='M ')
- another_status.tweak('A/zot', status='D ')
- svntest.actions.run_and_verify_status(another_wc, another_status)
-
-#----------------------------------------------------------------------
-# Regression test for issue #1319: 'svn merge' should *not* 'C' when
-# merging a change into a binary file, unless it has local mods, or has
-# different contents from the left side of the merge.
-
-def merge_binary_file(sbox):
- "merge change into unchanged binary file"
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # Add a binary file to the project
- theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
- # Write PNG file data into 'A/theta'.
- theta_path = os.path.join(wc_dir, 'A', 'theta')
- svntest.main.file_write(theta_path, theta_contents, 'wb')
-
- svntest.main.run_svn(None, 'add', theta_path)
-
- # Commit the new binary file, creating revision 2.
- expected_output = svntest.wc.State(wc_dir, {
- 'A/theta' : Item(verb='Adding (bin)'),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- 'A/theta' : Item(status=' ', wc_rev=2),
- })
- svntest.actions.run_and_verify_commit(wc_dir, expected_output,
- expected_status, None,
- wc_dir)
-
- # Make the "other" working copy
- other_wc = sbox.add_wc_path('other')
- svntest.actions.duplicate_dir(wc_dir, other_wc)
-
- # Change the binary file in first working copy, commit revision 3.
- svntest.main.file_append(theta_path, "some extra junk")
- expected_output = wc.State(wc_dir, {
- 'A/theta' : Item(verb='Sending'),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- 'A/theta' : Item(status=' ', wc_rev=3),
- })
- svntest.actions.run_and_verify_commit(wc_dir, expected_output,
- expected_status, None,
- wc_dir)
-
- # In second working copy, attempt to 'svn merge -r 2:3'.
- # We should *not* see a conflict during the update, but a 'U'.
- # And after the merge, the status should be 'M'.
- expected_output = wc.State(other_wc, {
- 'A/theta' : Item(status='U '),
- })
- expected_mergeinfo_output = wc.State(other_wc, {
- '' : Item(status=' U'),
- })
- expected_elision_output = wc.State(other_wc, {
- })
- expected_disk = svntest.main.greek_state.copy()
- expected_disk.add({
- '' : Item(props={SVN_PROP_MERGEINFO : '/:3'}),
- 'A/theta' : Item(theta_contents + "some extra junk",
- props={'svn:mime-type' : 'application/octet-stream'}),
- })
- expected_status = svntest.actions.get_virginal_state(other_wc, 1)
- expected_status.add({
- '' : Item(status=' M', wc_rev=1),
- 'A/theta' : Item(status='M ', wc_rev=2),
- })
- expected_skip = wc.State('', { })
-
- svntest.actions.run_and_verify_merge(other_wc, '2', '3',
- sbox.repo_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None,
- 1)
-
-#----------------------------------------------------------------------
-# Regression test for issue #2403: Incorrect 3-way merge of "added"
-# binary file which already exists (unmodified) in the WC
-
-# This test involves tree conflicts.
-def three_way_merge_add_of_existing_binary_file(sbox):
- "3-way merge of 'file add' into existing binary"
-
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # Create a branch of A, creating revision 2.
- A_url = sbox.repo_url + "/A"
- branch_A_url = sbox.repo_url + "/copy-of-A"
- svntest.actions.run_and_verify_svn(None, None, [],
- "cp",
- A_url, branch_A_url,
- "-m", "Creating copy-of-A")
-
- # Add a binary file to the WC.
- theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
- # Write PNG file data into 'A/theta'.
- A_path = os.path.join(wc_dir, 'A')
- theta_path = os.path.join(wc_dir, 'A', 'theta')
- svntest.main.file_write(theta_path, theta_contents, 'wb')
-
- svntest.main.run_svn(None, "add", theta_path)
-
- # Commit the new binary file to the repos, creating revision 3.
- expected_output = svntest.wc.State(wc_dir, {
- "A/theta" : Item(verb="Adding (bin)"),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- "A/theta" : Item(status=" ", wc_rev=3),
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.add({
+ "A/theta" : Item(status=" ", wc_rev=3),
})
svntest.actions.run_and_verify_commit(wc_dir, expected_output,
expected_status, None,
@@ -1708,17527 +419,1450 @@ def three_way_merge_add_of_existing_bina
1)
#----------------------------------------------------------------------
-# Regression test for Issue #1297:
-# A merge that creates a new file followed by an immediate diff
-# The diff should succeed.
-
-def merge_in_new_file_and_diff(sbox):
- "diff after merge that creates a new file"
+# Issue #2515
+def merge_added_dir_to_deleted_in_target(sbox):
+ "merge an added dir on a deleted dir in target"
sbox.build()
wc_dir = sbox.wc_dir
- trunk_url = sbox.repo_url + '/A/B/E'
+ # copy B to a new directory, I.
+ # delete F in I.
+ # add J to B/F.
+ # merge add to I.
+
+ B_url = sbox.repo_url + '/A/B'
+ I_url = sbox.repo_url + '/A/I'
+ F_url = sbox.repo_url + '/A/I/F'
+ J_url = sbox.repo_url + '/A/B/F/J'
+ I_path = os.path.join(wc_dir, 'A', 'I')
- # Create a branch
- svntest.actions.run_and_verify_svn(None, None, [], 'cp',
- trunk_url,
- sbox.repo_url + '/branch',
- '-m', "Creating the Branch")
- # Update to revision 2.
svntest.actions.run_and_verify_svn(None, None, [],
- 'update', wc_dir)
+ 'cp', B_url, I_url, '-m', 'rev 2')
- new_file_path = os.path.join(wc_dir, 'A', 'B', 'E', 'newfile')
- svntest.main.file_write(new_file_path, "newfile\n")
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'rm', F_url, '-m', 'rev 3')
- # Add the new file, and commit revision 3.
- svntest.actions.run_and_verify_svn(None, None, [], "add", new_file_path)
svntest.actions.run_and_verify_svn(None, None, [],
- 'ci', '-m',
- "Changing the trunk.", wc_dir)
+ 'mkdir', '-m', 'rev 4', J_url)
- branch_path = os.path.join(wc_dir, "branch")
- url_branch_path = branch_path.replace(os.path.sep, '/')
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'up', os.path.join(wc_dir,'A'))
- # Merge our addition into the branch.
- expected_output = svntest.wc.State(branch_path, {
- 'newfile' : Item(status='A '),
+ expected_output = wc.State(I_path, {
+ 'F' : Item(status=' ', treeconflict='C'),
})
- expected_mergeinfo_output = svntest.wc.State(branch_path, {
+ expected_mergeinfo_output = wc.State(I_path, {
'' : Item(status=' U'),
})
- expected_elision_output = wc.State(branch_path, {
+ expected_elision_output = wc.State(I_path, {
})
expected_disk = wc.State('', {
- 'alpha' : Item("This is the file 'alpha'.\n"),
- 'beta' : Item("This is the file 'beta'.\n"),
- 'newfile' : Item("newfile\n"),
+ 'E' : Item(),
+ 'E/alpha' : Item("This is the file 'alpha'.\n"),
+ 'E/beta' : Item("This is the file 'beta'.\n"),
+ 'lambda' : Item("This is the file 'lambda'.\n"),
})
- expected_status = wc.State(branch_path, {
- '' : Item(status=' M', wc_rev=2),
- 'alpha' : Item(status=' ', wc_rev=2),
- 'beta' : Item(status=' ', wc_rev=2),
- 'newfile' : Item(status='A ', wc_rev='-', copied='+')
+ expected_skip = wc.State(I_path, {
})
- expected_skip = wc.State('', { })
- svntest.actions.run_and_verify_merge(branch_path,
- '1', 'HEAD', trunk_url, None,
+ svntest.actions.run_and_verify_merge(I_path, '2', '4', B_url, None,
expected_output,
expected_mergeinfo_output,
expected_elision_output,
expected_disk,
- expected_status,
- expected_skip)
-
- # Finally, run diff.
- expected_output = [
- "\n",
- "Property changes on: " + branch_path + "\n",
- "___________________________________________________________________\n",
- "Added: " + SVN_PROP_MERGEINFO + "\n",
- " Merged /A/B/E:r2-3\n",
- "Index: " + url_branch_path + "/newfile\n",
- "===================================================================\n",
- "--- "+ url_branch_path + "/newfile (revision 0)\n",
- "+++ "+ url_branch_path + "/newfile (working copy)\n",
- "@@ -0,0 +1 @@\n",
- "+newfile\n"]
- svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
- '--show-copies-as-adds', branch_path)
-
+ None,
+ expected_skip,
+ None, None, None, None, None,
+ 0, 0)
#----------------------------------------------------------------------
-
-# Issue #1425: 'svn merge' should skip over any unversioned obstructions.
-
-# This test involves tree conflicts. - but attempting to test for pre-tree-conflict behaviour
-def merge_skips_obstructions(sbox):
- "merge should skip over unversioned obstructions"
+# Issue 2584
+def merge_add_over_versioned_file_conflicts(sbox):
+ "conflict from merge of add over versioned file"
sbox.build()
wc_dir = sbox.wc_dir
- C_path = os.path.join(wc_dir, 'A', 'C')
- F_path = os.path.join(wc_dir, 'A', 'B', 'F')
- F_url = sbox.repo_url + '/A/B/F'
-
- Q_path = os.path.join(F_path, 'Q')
- foo_path = os.path.join(F_path, 'foo')
- bar_path = os.path.join(F_path, 'Q', 'bar')
-
- svntest.main.run_svn(None, 'mkdir', Q_path)
- svntest.main.file_append(foo_path, "foo")
- svntest.main.file_append(bar_path, "bar")
- svntest.main.run_svn(None, 'add', foo_path, bar_path)
+ E_path = os.path.join(wc_dir, 'A', 'B', 'E')
+ alpha_path = os.path.join(E_path, 'alpha')
+ new_alpha_path = os.path.join(wc_dir, 'A', 'C', 'alpha')
- expected_output = wc.State(wc_dir, {
- 'A/B/F/Q' : Item(verb='Adding'),
- 'A/B/F/Q/bar' : Item(verb='Adding'),
- 'A/B/F/foo' : Item(verb='Adding'),
+ # Create a new "alpha" file, with enough differences to cause a conflict.
+ svntest.main.file_write(new_alpha_path, 'new alpha content\n')
+
+ # Add and commit the new "alpha" file, creating revision 2.
+ svntest.main.run_svn(None, "add", new_alpha_path)
+
+ expected_output = svntest.wc.State(wc_dir, {
+ 'A/C/alpha' : Item(verb='Adding'),
})
expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
expected_status.add({
- 'A/B/F/Q' : Item(status=' ', wc_rev=2),
- 'A/B/F/Q/bar' : Item(status=' ', wc_rev=2),
- 'A/B/F/foo' : Item(status=' ', wc_rev=2),
+ 'A/C/alpha' : Item(status=' ', wc_rev=2),
})
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None,
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status, None,
wc_dir)
- pre_merge_status = expected_status
-
- # Revision 2 now has A/B/F/foo, A/B/F/Q, A/B/F/Q/bar. Let's merge
- # those 'F' changes into empty dir 'C'. But first, create an
- # unversioned 'foo' within C, and make sure 'svn merge' doesn't
- # error when the addition of foo is obstructed.
-
- expected_output = wc.State(C_path, {
- 'Q' : Item(status='A '),
- 'Q/bar' : Item(status='A '),
+ # Merge r1:2 from A/C to A/B/E. This will attempt to add A/C/alpha,
+ # but since A/B/E/alpha already exists we get a tree conflict.
+ expected_output = wc.State(E_path, {
+ 'alpha' : Item(status=' ', treeconflict='C'),
})
- expected_mergeinfo_output = wc.State(C_path, {
+ expected_mergeinfo_output = wc.State(E_path, {
'' : Item(status=' U'),
})
- expected_elision_output = wc.State(C_path, {
+ expected_elision_output = wc.State(E_path, {
})
expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
- 'Q' : Item(),
- 'Q/bar' : Item("bar"),
- 'foo' : Item("foo"),
+ 'alpha' : Item("This is the file 'alpha'.\n"),
+ 'beta' : Item("This is the file 'beta'.\n"),
})
- expected_status = wc.State(C_path, {
+ expected_status = wc.State(E_path, {
'' : Item(status=' M', wc_rev=1),
- 'Q' : Item(status='A ', wc_rev='-', copied='+'),
- 'Q/bar' : Item(status=' ', wc_rev='-', copied='+'),
- })
- expected_skip = wc.State(C_path, {
- 'foo' : Item(),
+ 'alpha' : Item(status=' ', wc_rev=1, treeconflict='C'),
+ 'beta' : Item(status=' ', wc_rev=1),
})
- # Unversioned:
- svntest.main.file_append(os.path.join(C_path, "foo"), "foo")
-
- svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
+ expected_skip = wc.State(E_path, { })
+ svntest.actions.run_and_verify_merge(E_path, '1', '2',
+ sbox.repo_url + '/A/C', None,
expected_output,
expected_mergeinfo_output,
expected_elision_output,
expected_disk,
expected_status,
- expected_skip,
- None, None, None, None, None,
- 1, 0)
-
- # Revert the local mods, and this time make "Q" obstructed. An
- # unversioned file called "Q" will obstruct the adding of the
- # directory of the same name.
-
- svntest.actions.run_and_verify_svn(None, None, [],
- 'revert', '-R', wc_dir)
- os.unlink(os.path.join(C_path, "foo"))
- svntest.main.safe_rmtree(os.path.join(C_path, "Q"))
- svntest.main.file_append(os.path.join(C_path, "Q"), "foo") # unversioned
- svntest.actions.run_and_verify_status(wc_dir, pre_merge_status)
+ expected_skip)
- expected_output = wc.State(C_path, {
- 'foo' : Item(status='A '),
- })
- expected_mergeinfo_output = wc.State(C_path, {
- '' : Item(status=' U'),
- })
- expected_elision_output = wc.State(C_path, {
- })
- expected_disk = wc.State('', {
- '' : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
- 'Q' : Item("foo"),
- 'foo' : Item("foo"),
- })
- expected_status = wc.State(C_path, {
- '' : Item(status=' M', wc_rev=1),
- 'foo' : Item(status='A ', wc_rev='-', copied='+'),
- })
- expected_skip = wc.State(C_path, {
- 'Q' : Item(),
- 'Q/bar' : Item(),
- })
+#----------------------------------------------------------------------
+def mergeinfo_recording_in_skipped_merge(sbox):
+ "mergeinfo recording in skipped merge"
- svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None,
- 1, 0)
+ ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2829. ##
- # Revert the local mods, and commit the deletion of iota and A/D/G. (r3)
- os.unlink(os.path.join(C_path, "foo"))
- svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
- svntest.actions.run_and_verify_status(wc_dir, pre_merge_status)
+ # Create a WC with a single branch
+ sbox.build()
+ wc_dir = sbox.wc_dir
+ wc_disk, wc_status = set_up_branch(sbox, True, 1)
- iota_path = os.path.join(wc_dir, 'iota')
- G_path = os.path.join(wc_dir, 'A', 'D', 'G')
- svntest.actions.run_and_verify_svn(None, None, [], 'rm', iota_path, G_path)
+ # Some paths we'll care about
+ A_url = sbox.repo_url + '/A'
+ A_COPY_path = os.path.join(wc_dir, 'A_COPY')
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
+ A_COPY_B_E_path = os.path.join(wc_dir, 'A_COPY', 'B', 'E')
+ A_COPY_alpha_path = os.path.join(wc_dir, 'A_COPY', 'B', 'E', 'alpha')
+ A_COPY_beta_path = os.path.join(wc_dir, 'A_COPY', 'B', 'E', 'beta')
- expected_output = wc.State(wc_dir, {
- 'A/D/G' : Item(verb='Deleting'),
- 'iota' : Item(verb='Deleting'),
- })
- expected_status = pre_merge_status
- expected_status.remove('iota', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None, wc_dir)
+ # Make a modification to A/mu
+ svntest.main.file_write(mu_path, "This is the file 'mu' modified.\n")
+ expected_output = wc.State(wc_dir, {'A/mu' : Item(verb='Sending')})
+ wc_status.add({'A/mu' : Item(status=' ', wc_rev=3)})
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ wc_status, None, wc_dir)
- # Now create unversioned iota and A/D/G, try running a merge -r2:3.
- # The merge process should skip over these targets, since they're
- # unversioned.
+ # Make a modification to A/B/E/alpha
+ svntest.main.file_write(alpha_path, "This is the file 'alpha' modified.\n")
+ expected_output = wc.State(wc_dir, {'A/B/E/alpha' : Item(verb='Sending')})
+ wc_status.add({'A/B/E/alpha' : Item(status=' ', wc_rev=4)})
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ wc_status, None, wc_dir)
- svntest.main.file_append(iota_path, "foo") # unversioned
- os.mkdir(G_path) # unversioned
+ # Delete A_COPY/B/E
+ svntest.actions.run_and_verify_svn(None, None, [], 'rm',
+ A_COPY_B_E_path)
- expected_output = wc.State(wc_dir, {
+ # Merge /A to /A_COPY ie., r1 to r4
+ expected_output = wc.State(A_COPY_path, {
+ 'mu' : Item(status='U '),
+ 'B/E' : Item(status=' ', treeconflict='C'),
})
- expected_mergeinfo_output = wc.State(wc_dir, {
+ expected_mergeinfo_output = wc.State(A_COPY_path, {
'' : Item(status=' U'),
})
- expected_elision_output = wc.State(wc_dir, {
+ expected_elision_output = wc.State(A_COPY_path, {
})
- expected_disk = svntest.main.greek_state.copy()
- expected_disk.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
- expected_disk.add({
- '' : Item(props={SVN_PROP_MERGEINFO : '/:3'}),
- 'A/B/F/Q' : Item(),
- 'A/B/F/Q/bar' : Item("bar"),
- 'A/B/F/foo' : Item("foo"),
- 'A/C/Q' : Item("foo"),
+ expected_status = wc.State(A_COPY_path, {
+ '' : Item(status=' M', wc_rev=2),
+ 'mu' : Item(status='M ', wc_rev=2),
+ 'B' : Item(status=' ', wc_rev=2),
+ 'B/lambda' : Item(status=' ', wc_rev=2),
+ 'B/F' : Item(status=' ', wc_rev=2),
+ 'B/E' : Item(status='D ', wc_rev=2, treeconflict='C'),
+ 'B/E/alpha': Item(status='D ', wc_rev=2),
+ 'B/E/beta' : Item(status='D ', wc_rev=2),
+ 'C' : Item(status=' ', wc_rev=2),
+ 'D' : Item(status=' ', wc_rev=2),
+ 'D/gamma' : Item(status=' ', wc_rev=2),
+ 'D/G' : Item(status=' ', wc_rev=2),
+ 'D/G/pi' : Item(status=' ', wc_rev=2),
+ 'D/G/rho' : Item(status=' ', wc_rev=2),
+ 'D/G/tau' : Item(status=' ', wc_rev=2),
+ 'D/H' : Item(status=' ', wc_rev=2),
+ 'D/H/chi' : Item(status=' ', wc_rev=2),
+ 'D/H/omega': Item(status=' ', wc_rev=2),
+ 'D/H/psi' : Item(status=' ', wc_rev=2),
})
- expected_disk.tweak('iota', contents="foo")
- # No-op merge still sets mergeinfo
- expected_status.tweak('', status=' M')
- expected_skip = wc.State(wc_dir, {
- 'iota' : Item(),
- 'A/D/G' : Item(),
+ expected_disk = wc.State('', {
+ '' : Item(props={SVN_PROP_MERGEINFO : '/A:2-4'}),
+ 'mu' : Item("This is the file 'mu' modified.\n"),
+ 'C' : Item(),
+ 'D' : Item(),
+ 'B' : Item(),
+ 'B/lambda' : Item(contents="This is the file 'lambda'.\n"),
+ 'B/F' : Item(),
+ 'B/E' : 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("This is the file 'rho'.\n"),
+ '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("This is the file 'omega'.\n"),
+ 'D/H/psi' : Item("This is the file 'psi'.\n"),
})
- svntest.actions.run_and_verify_merge(wc_dir, '2', '3',
- sbox.repo_url, None,
+ expected_skip = wc.State(A_COPY_path, {})
+ svntest.actions.run_and_verify_merge(A_COPY_path, None, None,
+ A_url, None,
expected_output,
expected_mergeinfo_output,
expected_elision_output,
expected_disk,
- expected_status.copy(wc_dir),
+ expected_status,
expected_skip,
None, None, None, None, None,
- 1, 0)
-
- # Revert the local mods, and commit a change to A/B/lambda (r4), and then
- # commit the deletion of the same file. (r5)
- svntest.main.safe_rmtree(G_path)
- svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
- expected_status.tweak('', status=' ')
- svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
- lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
- svntest.main.file_append(lambda_path, "more text")
- expected_output = wc.State(wc_dir, {
- 'A/B/lambda' : Item(verb='Sending'),
- })
- expected_status.tweak('A/B/lambda', wc_rev=4)
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None, wc_dir)
-
- svntest.actions.run_and_verify_svn(None, None, [], 'rm', lambda_path)
+ 1, 1)
- expected_output = wc.State(wc_dir, {
- 'A/B/lambda' : Item(verb='Deleting'),
- })
- expected_status.remove('A/B/lambda')
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None, wc_dir)
+#----------------------------------------------------------------------
+def del_differing_file(sbox):
+ "merge tries to delete a file of different content"
- # lambda is gone, so create an unversioned lambda in its place.
- # Then attempt to merge -r3:4, which is a change to lambda. The merge
- # should simply skip the unversioned file.
+ # Setup a standard greek tree in r1.
+ sbox.build()
+ svn_commit.repo_rev = 1
- svntest.main.file_append(lambda_path, "foo") # unversioned
+ saved_cwd = os.getcwd()
+ os.chdir(sbox.wc_dir)
- expected_output = wc.State(wc_dir, { })
- expected_mergeinfo_output = wc.State(wc_dir, {
- '' : Item(status=' U'),
- })
- expected_elision_output = wc.State(wc_dir, {
- })
- expected_disk.add({
- 'A/B/lambda' : Item("foo"),
- })
- expected_disk.remove('A/D/G')
- expected_disk.tweak('', props={SVN_PROP_MERGEINFO : '/:4'})
- expected_skip = wc.State(wc_dir, {
- 'A/B/lambda' : Item(),
- })
- # No-op merge still sets mergeinfo.
- expected_status_short = expected_status.copy(wc_dir)
- expected_status_short.tweak('', status=' M')
+ source = 'A/D/G'
+ s_rev_orig = 1
- svntest.actions.run_and_verify_merge(wc_dir, '3', '4',
- sbox.repo_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status_short,
- expected_skip,
- None, None, None, None, None,
- 1, 0)
+ # Delete files in the source
+ svn_delete(source+"/tau")
+ s_rev_tau = svn_commit(source)
+ svn_delete(source+"/pi")
+ s_rev_pi = svn_commit(source)
- # 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
- # with a file being under version control, but missing.
+ # Copy a file, modify it, and merge a deletion to it.
+ target = 'A/D/G2'
+ svn_copy(s_rev_orig, source, target)
+ svntest.main.file_append(target+"/tau", "An extra line in the target.\n")
+ svntest.actions.run_and_verify_svn(None, None, [], 'propset',
+ 'newprop', 'v', target+"/pi")
- svntest.actions.run_and_verify_svn(None, None, [], 'add', lambda_path)
+ dir_D = os.path.join('A','D')
+ dir_G2 = os.path.join(dir_D, 'G2')
+ tau = os.path.join(dir_D,'G2','tau')
+ pi = os.path.join(dir_D, 'G2', 'pi')
+ # Should complain and "skip" it.
+ svn_merge(s_rev_tau, source, target, [
+ "--- Merging r2 into '%s':\n" % dir_G2,
+ " C %s\n" % tau,
+ "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G2),
+ " U %s\n" % (dir_G2),
+ "Summary of conflicts:\n",
+ " Tree conflicts: 1\n"])
- # Mergeinfo prop changed so update to avoid out of date error.
- svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+ svn_merge(s_rev_pi, source, target, [
+ "--- Merging r3 into '%s':\n" % dir_G2,
+ " C %s\n" % pi,
+ "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G2),
+ " G %s\n" % (dir_G2),
+ "Summary of conflicts:\n",
+ " Tree conflicts: 1\n"])
- expected_output = wc.State(wc_dir, {
- '' : Item(verb='Sending'),
- 'A/B/lambda' : Item(verb='Adding'),
- })
- expected_mergeinfo_output = wc.State(wc_dir, {})
- expected_elision_output = wc.State(wc_dir, {})
- expected_status.tweak(wc_rev=5)
- expected_status.add({
- 'A/B/lambda' : Item(wc_rev=6, status=' '),
- })
- expected_status.tweak('', status=' ', wc_rev=6)
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None, wc_dir)
- os.unlink(lambda_path)
- expected_output = wc.State(wc_dir, { })
- expected_disk.remove('A/B/lambda')
- expected_status.tweak('A/B/lambda', status='! ')
- expected_status.tweak('', status=' ')
- # Why do we need to --ignore-ancestry? Because the previous merge of r4,
- # despite being inoperative, set mergeinfo for r4 on the WC. With the
- # advent of merge tracking this repeat merge attempt would not be attempted.
- # By using --ignore-ancestry we disregard the mergeinfo and *really* try to
- # merge into a missing path. This is another facet of issue #2898.
- svntest.actions.run_and_verify_merge(wc_dir, '3', '4',
- sbox.repo_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status.copy(wc_dir),
- expected_skip,
- None, None, None, None, None,
- 1, 0, '--ignore-ancestry')
+ # Copy a file, modify it, commit, and merge a deletion to it.
+ target = 'A/D/G3'
+ svn_copy(s_rev_orig, source, target)
+ svntest.main.file_append(target+"/tau", "An extra line in the target.\n")
+ svntest.actions.run_and_verify_svn(None, None, [], 'propset',
+ 'newprop', 'v', target+"/pi")
+ svn_commit(target)
-#----------------------------------------------------------------------
-# At one time, a merge that added items with the same name as missing
-# items would attempt to add the items and fail, leaving the working
-# copy locked and broken.
-
-# This test involves tree conflicts.
-def merge_into_missing(sbox):
- "merge into missing must not break working copy"
- sbox.build()
- wc_dir = sbox.wc_dir
+ dir_G3 = os.path.join(dir_D, 'G3')
+ tau = os.path.join(dir_D,'G3','tau')
+ pi = os.path.join(dir_D, 'G3', 'pi')
- F_path = os.path.join(wc_dir, 'A', 'B', 'F')
- F_url = sbox.repo_url + '/A/B/F'
- Q_path = os.path.join(F_path, 'Q')
- foo_path = os.path.join(F_path, 'foo')
-
- svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', Q_path)
- svntest.main.file_append(foo_path, "foo")
- svntest.actions.run_and_verify_svn(None, None, [], 'add', foo_path)
+ # Should complain and "skip" it.
+ svn_merge(s_rev_tau, source, target, [
+ "--- Merging r2 into '%s':\n" % dir_G3,
+ " C %s\n" % tau,
+ "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G3),
+ " U %s\n" % (dir_G3),
+ "Summary of conflicts:\n",
+ " Tree conflicts: 1\n"])
- expected_output = wc.State(wc_dir, {
- 'A/B/F/Q' : Item(verb='Adding'),
- 'A/B/F/foo' : Item(verb='Adding'),
- })
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- 'A/B/F/Q' : Item(status=' ', wc_rev=2),
- 'A/B/F/foo' : Item(status=' ', wc_rev=2),
- })
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None, wc_dir)
-
- R_path = os.path.join(Q_path, 'R')
- bar_path = os.path.join(R_path, 'bar')
- baz_path = os.path.join(Q_path, 'baz')
- svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', R_path)
- svntest.main.file_append(bar_path, "bar")
- svntest.actions.run_and_verify_svn(None, None, [], 'add', bar_path)
- svntest.main.file_append(baz_path, "baz")
- svntest.actions.run_and_verify_svn(None, None, [], 'add', baz_path)
-
- expected_output = wc.State(wc_dir, {
- 'A/B/F/Q/R' : Item(verb='Adding'),
- 'A/B/F/Q/R/bar' : Item(verb='Adding'),
- 'A/B/F/Q/baz' : Item(verb='Adding'),
- })
- expected_status.add({
- 'A/B/F/Q/R' : Item(status=' ', wc_rev=3),
- 'A/B/F/Q/R/bar' : Item(status=' ', wc_rev=3),
- 'A/B/F/Q/baz' : Item(status=' ', wc_rev=3),
- })
- svntest.actions.run_and_verify_commit(wc_dir,
- expected_output,
- expected_status,
- None, wc_dir)
-
- os.unlink(foo_path)
- svntest.main.safe_rmtree(Q_path)
-
- expected_output = wc.State(F_path, {
- })
- expected_mergeinfo_output = wc.State(F_path, {
- })
- expected_elision_output = wc.State(F_path, {
- })
- expected_disk = wc.State('', {
- })
- expected_status = wc.State(F_path, {
- '' : Item(status=' ', wc_rev=1),
- 'foo' : Item(status='! ', wc_rev=2),
- 'Q' : Item(status='! ', wc_rev='2', entry_rev='?'),
- })
- expected_skip = wc.State(F_path, {
- 'Q' : Item(),
- 'foo' : Item(),
- })
-
- ### Need to real and dry-run separately since real merge notifies Q
- ### twice!
- svntest.actions.run_and_verify_merge(F_path, '1', '2', F_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None,
- 0, 0, '--dry-run')
-
- expected_status = wc.State(F_path, {
- '' : Item(status=' M', wc_rev=1),
- 'foo' : Item(status='!M', wc_rev=2),
- 'Q' : Item(status='! ', wc_rev='2', entry_rev='?'),
- })
- expected_mergeinfo_output = wc.State(F_path, {
- '' : Item(status=' U'),
- 'foo' : Item(status=' U'), # Mergeinfo is set on missing/obstructed files.
- })
- svntest.actions.run_and_verify_merge(F_path, '1', '2', F_url, None,
- expected_output,
- expected_mergeinfo_output,
- expected_elision_output,
- expected_disk,
- expected_status,
- expected_skip,
- None, None, None, None, None,
- 0, 0)
-
- # This merge fails when it attempts to descend into the missing
- # directory. That's OK, there is no real need to support merge into
- # an incomplete working copy, so long as when it fails it doesn't
- # break the working copy.
- svntest.main.run_svn('Working copy not locked',
- 'merge', '-r1:3', '--dry-run', F_url, F_path)
-
- svntest.main.run_svn('Working copy not locked',
- 'merge', '-r1:3', F_url, F_path)
+ svn_merge(s_rev_pi, source, target, [
+ "--- Merging r3 into '%s':\n" % dir_G3,
+ " C %s\n" % pi,
+ "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G3),
+ " G %s\n" % (dir_G3),
+ "Summary of conflicts:\n",
+ " Tree conflicts: 1\n"])
- # Check working copy is not locked.
- expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
- expected_status.add({
- 'A/B/F' : Item(status=' M', wc_rev=1),
- 'A/B/F/foo' : Item(status='!M', wc_rev=2),
- 'A/B/F/Q' : Item(status='! ', wc_rev='2', entry_rev='?'),
- })
- svntest.actions.run_and_verify_status(wc_dir, expected_status)
+ os.chdir(saved_cwd)
#----------------------------------------------------------------------
-# A test for issue 1738
+# This test used to involve tree conflicts, hence its name.
+def tree_conflicts_and_obstructions(sbox):
+ "tree conflicts and obstructions"
-def dry_run_adds_file_with_prop(sbox):
- "merge --dry-run adding a new file with props"
+ ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3146. ##
sbox.build()
wc_dir = sbox.wc_dir
- # Commit a new file which has a property.
- zig_path = os.path.join(wc_dir, 'A', 'B', 'E', 'zig')
- svntest.main.file_append(zig_path, "zig contents")
- svntest.actions.run_and_verify_svn(None, None, [], 'add', zig_path)
+ trunk_url = sbox.repo_url + '/A/B/E'
+ branch_path = os.path.join(wc_dir, 'branch')
+ br_alpha_moved = os.path.join(branch_path, 'alpha-moved')
+
+ # Create a branch
+ svntest.actions.run_and_verify_svn(None, None, [], 'cp',
+ trunk_url,
+ sbox.repo_url + '/branch',
[... 18148 lines stripped ...]