3 # merge_tests.py: testing merge
5 # Subversion is a tool for revision control.
6 # See http://subversion.tigris.org for more information.
8 # ====================================================================
9 # Copyright (c) 2000-2007 CollabNet. All rights reserved.
11 # This software is licensed as described in the file COPYING, which
12 # you should have received as part of this distribution. The terms
13 # are also available at http://subversion.tigris.org/license-1.html.
14 # If newer versions of this license are posted there, you may use a
15 # newer version instead, at your option.
17 ######################################################################
20 import shutil
, sys
, re
, os
25 from svntest
import wc
29 XFail
= svntest
.testcase
.XFail
30 Skip
= svntest
.testcase
.Skip
31 SkipUnless
= svntest
.testcase
.SkipUnless
33 from svntest
.main
import SVN_PROP_MERGEINFO
34 from svntest
.main
import server_has_mergeinfo
35 from svntest
.actions
import fill_file_with_lines
36 from svntest
.actions
import make_conflict_marker_text
37 from svntest
.actions
import inject_conflict_into_expected_state
39 def shorten_path_kludge(path
):
40 '''Search for the comment entitled "The Merge Kluge" elsewhere in
41 this file, to understand why we shorten, and subsequently chdir()
42 after calling this function.'''
43 shorten_by
= len(svntest
.main
.work_dir
) + len(os
.sep
)
44 return path
[shorten_by
:]
46 def expected_merge_output(rev_ranges
, additional_lines
=None):
47 """Generate an (inefficient) regex representing the expected merge
48 output from REV_RANGES (a list of 'range' lists of the form [start, end] or
49 [single_rev] --> [single_rev - 1, single_rev]), and ADDITIONAL_LINES (a list
50 of strings). If REV_RANGES is None then only the standard notification for
51 a 3-way merge is expected."""
52 if rev_ranges
is None:
53 lines
= [svntest
.main
.merge_notify_line(None, None, False)]
56 for rng
in rev_ranges
:
62 lines
+= [svntest
.main
.merge_notify_line(start_rev
, end_rev
, True)]
63 if isinstance(additional_lines
, list):
64 # Address "The Backslash Plague"
66 # If ADDITIONAL_LINES are present there are possibly paths in it with
67 # multiple components and on Windows these components are separated with
68 # '\'. These need to be escaped properly in the regexp for the match to
69 # work correctly. See http://aspn.activestate.com/ASPN/docs/ActivePython
70 # /2.2/howto/regex/regex.html#SECTION000420000000000000000.
71 if sys
.platform
== 'win32':
72 for i
in range(0, len(additional_lines
)):
73 additional_lines
[i
] = additional_lines
[i
].replace("\\", "\\\\")
74 lines
.extend(additional_lines
)
76 if sys
.platform
== 'win32' and additional_lines
!= None:
77 additional_lines
= additional_lines
.replace("\\", "\\\\")
78 lines
.append(str(additional_lines
))
79 return "|".join(lines
)
81 ######################################################################
84 # Each test must return on success or raise on failure.
87 #----------------------------------------------------------------------
89 def textual_merges_galore(sbox
):
90 "performing a merge, with mixed results"
94 ## The goal is to test that "svn merge" does the right thing in the
97 ## 1 : _ : Received changes already present in unmodified local file
98 ## 2 : U : No local mods, received changes folded in without trouble
99 ## 3 : G : Received changes already exist as local mods
100 ## 4 : G : Received changes do not conflict with local mods
101 ## 5 : C : Received changes conflict with local mods
103 ## So first modify these files and commit:
107 ## A/mu ............... add ten or so lines
108 ## A/D/G/rho .......... add ten or so lines
110 ## Now check out an "other" working copy, from revision 2.
112 ## Next further modify and commit some files from the original
117 ## A/B/lambda ......... add ten or so lines
118 ## A/D/G/pi ........... add ten or so lines
119 ## A/D/G/tau .......... add ten or so lines
120 ## A/D/G/rho .......... add an additional ten or so lines
122 ## In the other working copy (which is at rev 2), update rho back
123 ## to revision 1, while giving other files local mods. This sets
124 ## things up so that "svn merge -r 1:3" will test all of the above
125 ## cases except case 4:
127 ## case 1: A/mu .......... do nothing, the only change was in rev 2
128 ## case 2: A/B/lambda .... do nothing, so we accept the merge easily
129 ## case 3: A/D/G/pi ...... add same ten lines as committed in rev 3
130 ## case 5: A/D/G/tau ..... add ten or so lines at the end
131 ## [none]: A/D/G/rho ..... ignore what happens to this file for now
136 ## $ svn merge -r 1:3 url-to-repo
138 ## ...and expect the right output.
140 ## Now revert rho, then update it to revision 2, then *prepend* a
141 ## bunch of lines, which will be separated by enough distance from
142 ## the changes about to be received that the merge will be clean.
144 ## $ cd wc.other/A/D/G
145 ## $ svn merge -r 2:3 url-to-repo/A/D/G
147 ## Which tests case 4. (Ignore the changes to the other files,
148 ## we're only interested in rho here.)
152 # url = os.path.join(svntest.main.test_area_url, sbox.repo_dir)
154 # Change mu and rho for revision 2
155 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
156 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
157 mu_text
= fill_file_with_lines(mu_path
, 2)
158 rho_text
= fill_file_with_lines(rho_path
, 2)
160 # Create expected output tree for initial commit
161 expected_output
= wc
.State(wc_dir
, {
162 'A/mu' : Item(verb
='Sending'),
163 'A/D/G/rho' : Item(verb
='Sending'),
166 # Create expected status tree; all local revisions should be at 1,
167 # but mu and rho should be at revision 2.
168 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
169 expected_status
.tweak('A/mu', 'A/D/G/rho', wc_rev
=2)
172 svntest
.actions
.run_and_verify_commit(wc_dir
,
178 # Make the "other" working copy
179 other_wc
= sbox
.add_wc_path('other')
180 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
182 # Now commit some more mods from the original working copy, to
183 # produce revision 3.
184 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
185 pi_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'pi')
186 tau_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'tau')
188 lambda_text
= fill_file_with_lines(lambda_path
, 2)
189 pi_text
= fill_file_with_lines(pi_path
, 2)
190 tau_text
= fill_file_with_lines(tau_path
, 2)
191 additional_rho_text
= fill_file_with_lines(rho_path
, 2)
193 # Created expected output tree for 'svn ci'
194 expected_output
= wc
.State(wc_dir
, {
195 'A/B/lambda' : Item(verb
='Sending'),
196 'A/D/G/pi' : Item(verb
='Sending'),
197 'A/D/G/tau' : Item(verb
='Sending'),
198 'A/D/G/rho' : Item(verb
='Sending'),
201 # Create expected status tree.
202 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
203 expected_status
.tweak('A/mu', wc_rev
=2)
204 expected_status
.tweak('A/B/lambda', 'A/D/G/pi', 'A/D/G/tau', 'A/D/G/rho',
208 svntest
.actions
.run_and_verify_commit(wc_dir
,
214 # Make local mods in wc.other
215 other_pi_path
= os
.path
.join(other_wc
, 'A', 'D', 'G', 'pi')
216 other_rho_path
= os
.path
.join(other_wc
, 'A', 'D', 'G', 'rho')
217 other_tau_path
= os
.path
.join(other_wc
, 'A', 'D', 'G', 'tau')
219 # For A/mu and A/B/lambda, we do nothing. For A/D/G/pi, we add the
220 # same ten lines as were already committed in revision 3.
221 # (Remember, wc.other is only at revision 2, so it doesn't have
223 svntest
.main
.file_append(other_pi_path
, pi_text
)
225 # We skip A/D/G/rho in this merge; it will be tested with a separate
226 # merge command. Temporarily put it back to revision 1, so this
227 # merge succeeds cleanly.
228 svntest
.actions
.run_and_verify_svn(None, None, [],
229 'up', '-r', '1', other_rho_path
)
231 # For A/D/G/tau, we append ten different lines, to conflict with the
232 # ten lines appended in revision 3.
233 other_tau_text
= fill_file_with_lines(other_tau_path
, 2,
234 line_descrip
="Conflicting line")
236 # Do the first merge, revs 1:3. This tests all the cases except
237 # case 4, which we'll handle in a second pass.
238 expected_output
= wc
.State(other_wc
, {'A/B/lambda' : Item(status
='U '),
239 'A/D/G/rho' : Item(status
='U '),
240 'A/D/G/tau' : Item(status
='C '),
243 expected_disk
= svntest
.main
.greek_state
.copy()
244 expected_disk
.tweak('A/mu',
245 contents
=expected_disk
.desc
['A/mu'].contents
247 expected_disk
.tweak('A/B/lambda',
248 contents
=expected_disk
.desc
['A/B/lambda'].contents
250 expected_disk
.tweak('A/D/G/rho',
251 contents
=expected_disk
.desc
['A/D/G/rho'].contents
252 + rho_text
+ additional_rho_text
)
253 expected_disk
.tweak('A/D/G/pi',
254 contents
=expected_disk
.desc
['A/D/G/pi'].contents
257 expected_status
= svntest
.actions
.get_virginal_state(other_wc
, 1)
258 expected_status
.tweak('', status
=' M')
259 expected_status
.tweak('A/mu', wc_rev
=2)
260 expected_status
.tweak('A/B/lambda', status
='M ')
261 expected_status
.tweak('A/D/G/pi', status
='M ')
262 expected_status
.tweak('A/D/G/rho', status
='M ')
264 inject_conflict_into_expected_state('A/D/G/tau', expected_disk
,
265 expected_status
, other_tau_text
, tau_text
,
268 expected_skip
= wc
.State('', { })
270 tau_conflict_support_files
= ["tau\.working",
271 "tau\.merge-right\.r3",
272 "tau\.merge-left\.r1"]
274 svntest
.actions
.run_and_verify_merge(other_wc
, '1', '3',
281 svntest
.tree
.detect_conflict_files
,
282 list(tau_conflict_support_files
))
284 # Now reverse merge r3 into A/D/G/rho, give it non-conflicting local
285 # mods, then merge in the 2:3 change. ### Not bothering to do the
286 # whole expected_foo routine for these intermediate operations;
287 # they're not what we're here to test, after all, so it's enough to
288 # know that they worked. Is this a bad practice? ###
290 # run_and_verify_merge doesn't support merging to a file WCPATH
291 # so use run_and_verify_svn.
292 svntest
.actions
.run_and_verify_svn(None,
293 expected_merge_output([[-3]], 'G ' +
297 sbox
.repo_url
+ '/A/D/G/rho',
300 # Now *prepend* ten or so lines to A/D/G/rho. Since rho had ten
301 # lines appended in revision 2, and then another ten in revision 3,
302 # these new local mods will be separated from the rev 3 changes by
303 # enough distance that they won't conflict, so the merge should be
306 for x
in range(1,10):
307 other_rho_text
= other_rho_text
+ 'Unobtrusive line ' + `x`
+ ' in rho\n'
308 current_other_rho_text
= svntest
.main
.file_read(other_rho_path
)
309 svntest
.main
.file_write(other_rho_path
,
310 other_rho_text
+ current_other_rho_text
)
312 # We expect no merge attempt for pi and tau because they inherit
313 # mergeinfo from the WC root. There is explicit mergeinfo on rho
314 # ('/A/D/G/rho:2') so expect it to be merged (cleanly).
315 expected_output
= wc
.State(os
.path
.join(other_wc
, 'A', 'D', 'G'),
316 {'rho' : Item(status
='G ')})
317 expected_disk
= wc
.State("", {
318 'pi' : Item("This is the file 'pi'.\n"),
319 'rho' : Item("This is the file 'rho'.\n"),
320 'tau' : Item("This is the file 'tau'.\n"),
322 expected_disk
.tweak('rho',
323 contents
=other_rho_text
324 + expected_disk
.desc
['rho'].contents
326 + additional_rho_text
)
327 expected_disk
.tweak('pi',
328 contents
=expected_disk
.desc
['pi'].contents
331 expected_status
= wc
.State(os
.path
.join(other_wc
, 'A', 'D', 'G'),
332 { '' : Item(wc_rev
=1, status
=' '),
333 'rho' : Item(wc_rev
=1, status
='M '),
334 'pi' : Item(wc_rev
=1, status
='M '),
335 'tau' : Item(wc_rev
=1, status
='C '),
338 inject_conflict_into_expected_state('tau', expected_disk
, expected_status
,
339 other_tau_text
, tau_text
, 3)
341 # Do the merge, but check svn:mergeinfo props separately since
342 # run_and_verify_merge would attempt to proplist tau's conflict
343 # files if we asked it to check props.
344 svntest
.actions
.run_and_verify_merge(
345 os
.path
.join(other_wc
, 'A', 'D', 'G'),
347 sbox
.repo_url
+ '/A/D/G',
353 svntest
.tree
.detect_conflict_files
, list(tau_conflict_support_files
))
356 svntest
.actions
.run_and_verify_svn(None, [], [],
357 'propget', SVN_PROP_MERGEINFO
,
358 os
.path
.join(other_wc
,
359 "A", "D", "G", "rho"))
362 #----------------------------------------------------------------------
364 # Merge should copy-with-history when adding files or directories
366 def add_with_history(sbox
):
367 "merge and add new files/dirs with history"
372 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
373 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
374 F_url
= sbox
.repo_url
+ '/A/B/F'
376 Q_path
= os
.path
.join(F_path
, 'Q')
377 Q2_path
= os
.path
.join(F_path
, 'Q2')
378 foo_path
= os
.path
.join(F_path
, 'foo')
379 foo2_path
= os
.path
.join(F_path
, 'foo2')
380 bar_path
= os
.path
.join(F_path
, 'Q', 'bar')
381 bar2_path
= os
.path
.join(F_path
, 'Q', 'bar2')
383 svntest
.main
.run_svn(None, 'mkdir', Q_path
)
384 svntest
.main
.run_svn(None, 'mkdir', Q2_path
)
385 svntest
.main
.file_append(foo_path
, "foo")
386 svntest
.main
.file_append(foo2_path
, "foo2")
387 svntest
.main
.file_append(bar_path
, "bar")
388 svntest
.main
.file_append(bar2_path
, "bar2")
389 svntest
.main
.run_svn(None, 'add', foo_path
, foo2_path
, bar_path
, bar2_path
)
390 svntest
.main
.run_svn(None, 'propset', 'x', 'x', Q2_path
)
391 svntest
.main
.run_svn(None, 'propset', 'y', 'y', foo2_path
)
392 svntest
.main
.run_svn(None, 'propset', 'z', 'z', bar2_path
)
394 expected_output
= wc
.State(wc_dir
, {
395 'A/B/F/Q' : Item(verb
='Adding'),
396 'A/B/F/Q2' : Item(verb
='Adding'),
397 'A/B/F/Q/bar' : Item(verb
='Adding'),
398 'A/B/F/Q/bar2': Item(verb
='Adding'),
399 'A/B/F/foo' : Item(verb
='Adding'),
400 'A/B/F/foo2' : Item(verb
='Adding'),
402 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
403 expected_status
.add({
404 'A/B/F/Q' : Item(status
=' ', wc_rev
=2),
405 'A/B/F/Q2' : Item(status
=' ', wc_rev
=2),
406 'A/B/F/Q/bar' : Item(status
=' ', wc_rev
=2),
407 'A/B/F/Q/bar2': Item(status
=' ', wc_rev
=2),
408 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
409 'A/B/F/foo2' : Item(status
=' ', wc_rev
=2),
411 svntest
.actions
.run_and_verify_commit(wc_dir
,
417 ### "The Merge Kluge"
419 ### *****************************************************
421 ### *** Before erasing this comment, please check ***
422 ### *** for references to "The Merge Kluge" ***
423 ### *** elsewhere in this file, update_tests.py ***
424 ### *** and switch_tests.py. ***
426 ### *****************************************************
428 ### The shortening of C_path and the chdir() below are a kluge to
431 ### http://subversion.tigris.org/issues/show_bug.cgi?id=767#desc16
433 ### Note that the problem isn't simply that 'svn merge' sometimes
434 ### puts temp files in cwd. That's bad enough, but even if svn
435 ### were to choose /tmp or some other static place blessed by
436 ### apr_get_temp_dir(), we'd still experience the error
439 ### svn: Can't move 'tmp.2' to '.../.svn/tmp/text-base/file1.svn-base':
440 ### Invalid cross-device link
442 ### when running the tests on a ramdisk. After all, there's no
443 ### reason why apr_get_temp_dir() would return a path inside
444 ### svn-test-work/, which is the mount point for the ramdisk.
446 ### http://subversion.tigris.org/issues/show_bug.cgi?id=767#desc20
447 ### starts a discussion on how to solve this in Subversion itself.
448 ### However, until that's settled, we still want to be able to run
449 ### the tests in a ramdisk, hence this kluge.
451 short_C_path
= shorten_path_kludge(C_path
)
452 expected_output
= wc
.State(short_C_path
, {
453 'Q' : Item(status
='A '),
454 'Q2' : Item(status
='A '),
455 'Q/bar' : Item(status
='A '),
456 'Q/bar2' : Item(status
='A '),
457 'foo' : Item(status
='A '),
458 'foo2' : Item(status
='A '),
460 expected_disk
= wc
.State('', {
461 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2'}),
463 'Q2' : Item(props
={'x' : 'x'}),
464 'Q/bar' : Item("bar"),
465 'Q/bar2' : Item("bar2", props
={'z' : 'z'}),
467 'foo2' : Item("foo2", props
={'y' : 'y'}),
469 expected_status
= wc
.State(short_C_path
, {
470 '' : Item(status
=' M', wc_rev
=1),
471 'Q' : Item(status
='A ', wc_rev
='-', copied
='+'),
472 'Q2' : Item(status
='A ', wc_rev
='-', copied
='+'),
473 'Q/bar' : Item(status
='A ', wc_rev
='-', copied
='+'),
474 'Q/bar2' : Item(status
='A ', wc_rev
='-', copied
='+'),
475 'foo' : Item(status
='A ', wc_rev
='-', copied
='+'),
476 'foo2' : Item(status
='A ', wc_rev
='-', copied
='+'),
478 expected_skip
= wc
.State(short_C_path
, { })
480 saved_cwd
= os
.getcwd()
482 os
.chdir(svntest
.main
.work_dir
)
483 svntest
.actions
.run_and_verify_merge(short_C_path
, '1', '2', F_url
,
488 None, None, None, None, None,
492 expected_output
= svntest
.wc
.State(wc_dir
, {
493 'A/C' : Item(verb
='Sending'),
494 'A/C/Q' : Item(verb
='Adding'),
495 'A/C/Q2' : Item(verb
='Adding'),
496 'A/C/Q/bar' : Item(verb
='Adding'),
497 'A/C/Q/bar2': Item(verb
='Adding'),
498 'A/C/foo' : Item(verb
='Adding'),
499 'A/C/foo2' : Item(verb
='Adding'),
501 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
502 expected_status
.add({
503 'A/C' : Item(status
=' ', wc_rev
=3),
504 'A/B/F/Q' : Item(status
=' ', wc_rev
=2),
505 'A/B/F/Q2' : Item(status
=' ', wc_rev
=2),
506 'A/B/F/Q/bar' : Item(status
=' ', wc_rev
=2),
507 'A/B/F/Q/bar2': Item(status
=' ', wc_rev
=2),
508 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
509 'A/B/F/foo2' : Item(status
=' ', wc_rev
=2),
510 'A/C/Q' : Item(status
=' ', wc_rev
=3),
511 'A/C/Q2' : Item(status
=' ', wc_rev
=3),
512 'A/C/Q/bar' : Item(status
=' ', wc_rev
=3),
513 'A/C/Q/bar2' : Item(status
=' ', wc_rev
=3),
514 'A/C/foo' : Item(status
=' ', wc_rev
=3),
515 'A/C/foo2' : Item(status
=' ', wc_rev
=3),
517 svntest
.actions
.run_and_verify_commit(wc_dir
,
523 #----------------------------------------------------------------------
525 def delete_file_and_dir(sbox
):
526 "merge that deletes items"
532 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
533 B2_path
= os
.path
.join(wc_dir
, 'A', 'B2')
534 B_url
= sbox
.repo_url
+ '/A/B'
536 svntest
.actions
.run_and_verify_svn(None, None, [],
537 'copy', B_path
, B2_path
)
539 expected_output
= wc
.State(wc_dir
, {
540 'A/B2' : Item(verb
='Adding'),
542 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
543 expected_status
.add({
544 'A/B2' : Item(status
=' ', wc_rev
=2),
545 'A/B2/E' : Item(status
=' ', wc_rev
=2),
546 'A/B2/E/alpha' : Item(status
=' ', wc_rev
=2),
547 'A/B2/E/beta' : Item(status
=' ', wc_rev
=2),
548 'A/B2/F' : Item(status
=' ', wc_rev
=2),
549 'A/B2/lambda' : Item(status
=' ', wc_rev
=2),
551 svntest
.actions
.run_and_verify_commit(wc_dir
,
557 # Rev 3 delete E and lambda from B
558 E_path
= os
.path
.join(B_path
, 'E')
559 lambda_path
= os
.path
.join(B_path
, 'lambda')
560 svntest
.actions
.run_and_verify_svn(None, None, [],
561 'delete', E_path
, lambda_path
)
563 expected_output
= wc
.State(wc_dir
, {
564 'A/B/E' : Item(verb
='Deleting'),
565 'A/B/lambda' : Item(verb
='Deleting'),
567 expected_status
.remove('A/B/E',
571 svntest
.actions
.run_and_verify_commit(wc_dir
,
578 B2_E_path
= os
.path
.join(B2_path
, 'E')
579 B2_lambda_path
= os
.path
.join(B2_path
, 'lambda')
580 svntest
.actions
.run_and_verify_svn(None, None, [],
581 'propset', 'foo', 'foo_val',
582 B2_E_path
, B2_lambda_path
)
583 expected_status
.tweak(
584 'A/B2/E', 'A/B2/lambda', status
=' M'
586 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
588 # Merge rev 3 into B2
590 # The local mods to the paths modified in r3 cause the paths to be
591 # skipped (without --force), resulting in no changes to the WC.
592 expected_output
= wc
.State(B2_path
, { })
593 expected_disk
= wc
.State('', {
595 'E/alpha' : Item("This is the file 'alpha'.\n"),
596 'E/beta' : Item("This is the file 'beta'.\n"),
598 'lambda' : Item("This is the file 'lambda'.\n"),
600 expected_status
= wc
.State(B2_path
, {
601 '' : Item(status
=' '),
602 'E' : Item(status
=' M'),
603 'E/alpha' : Item(status
=' '),
604 'E/beta' : Item(status
=' '),
605 'F' : Item(status
=' '),
606 'lambda' : Item(status
=' M'),
608 expected_status
.tweak(wc_rev
=2)
609 expected_skip
= wc
.State(B2_path
, {
613 svntest
.actions
.run_and_verify_merge(B2_path
, '2', '3', B_url
,
619 expected_output
= wc
.State(B2_path
, {
620 'E' : Item(status
='D '),
621 'lambda' : Item(status
='D '),
623 expected_disk
.remove('E/alpha', 'E/beta', 'lambda')
624 expected_status
.tweak('E', 'E/alpha', 'E/beta', 'lambda', status
='D ')
625 expected_status
.tweak('', status
=' M')
626 expected_skip
.remove('lambda', 'E')
628 ### Full-to-dry-run automatic comparison disabled because a) dry-run
629 ### doesn't descend into deleted directories, and b) the full merge
630 ### notifies deleted directories twice.
631 svntest
.actions
.run_and_verify_merge(B2_path
, '2', '3', B_url
,
636 None, None, None, None, None,
641 #----------------------------------------------------------------------
644 def simple_property_merges(sbox
):
645 "some simple property merges"
650 # Add a property to a file and a directory
651 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
652 beta_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'beta')
653 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
655 svntest
.actions
.run_and_verify_svn(None, None, [],
656 'propset', 'foo', 'foo_val',
658 # A binary, non-UTF8 property value
659 svntest
.actions
.run_and_verify_svn(None, None, [],
660 'propset', 'foo', 'foo\201val',
662 svntest
.actions
.run_and_verify_svn(None, None, [],
663 'propset', 'foo', 'foo_val',
666 # Commit change as rev 2
667 expected_output
= svntest
.wc
.State(wc_dir
, {
668 'A/B/E' : Item(verb
='Sending'),
669 'A/B/E/alpha' : Item(verb
='Sending'),
670 'A/B/E/beta' : Item(verb
='Sending'),
672 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
673 expected_status
.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
674 wc_rev
=2, status
=' ')
675 svntest
.actions
.run_and_verify_commit(wc_dir
,
676 expected_output
, expected_status
,
678 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
680 # Copy B to B2 as rev 3
681 B_url
= sbox
.repo_url
+ '/A/B'
682 B2_url
= sbox
.repo_url
+ '/A/B2'
684 svntest
.actions
.run_and_verify_svn(None, None, [],
685 'copy', '-m', 'copy B to B2',
687 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
689 # Modify a property and add a property for the file and directory
690 svntest
.actions
.run_and_verify_svn(None, None, [],
691 'propset', 'foo', 'mod_foo', alpha_path
)
692 svntest
.actions
.run_and_verify_svn(None, None, [],
693 'propset', 'bar', 'bar_val', alpha_path
)
694 svntest
.actions
.run_and_verify_svn(None, None, [],
695 'propset', 'foo', 'mod\201foo', beta_path
)
696 svntest
.actions
.run_and_verify_svn(None, None, [],
697 'propset', 'bar', 'bar\201val', beta_path
)
698 svntest
.actions
.run_and_verify_svn(None, None, [],
699 'propset', 'foo', 'mod_foo', E_path
)
700 svntest
.actions
.run_and_verify_svn(None, None, [],
701 'propset', 'bar', 'bar_val', E_path
)
703 # Commit change as rev 4
704 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 3)
705 expected_status
.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
706 wc_rev
=4, status
=' ')
707 expected_status
.add({
708 'A/B2' : Item(status
=' ', wc_rev
=3),
709 'A/B2/E' : Item(status
=' ', wc_rev
=3),
710 'A/B2/E/alpha' : Item(status
=' ', wc_rev
=3),
711 'A/B2/E/beta' : Item(status
=' ', wc_rev
=3),
712 'A/B2/F' : Item(status
=' ', wc_rev
=3),
713 'A/B2/lambda' : Item(status
=' ', wc_rev
=3),
715 svntest
.actions
.run_and_verify_commit(wc_dir
,
716 expected_output
, expected_status
,
718 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
720 pristine_status
= expected_status
721 pristine_status
.tweak(wc_rev
=4)
723 # Merge B 3:4 into B2
724 B2_path
= os
.path
.join(wc_dir
, 'A', 'B2')
725 expected_output
= wc
.State(B2_path
, {
726 'E' : Item(status
=' U'),
727 'E/alpha' : Item(status
=' U'),
728 'E/beta' : Item(status
=' U'),
730 expected_disk
= wc
.State('', {
731 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:4'}),
733 'E/alpha' : Item("This is the file 'alpha'.\n"),
734 'E/beta' : Item("This is the file 'beta'.\n"),
736 'lambda' : Item("This is the file 'lambda'.\n"),
738 expected_disk
.tweak('E', 'E/alpha',
739 props
={'foo' : 'mod_foo', 'bar' : 'bar_val'})
740 expected_disk
.tweak('E/beta',
741 props
={'foo' : 'mod\201foo', 'bar' : 'bar\201val'})
742 expected_status
= wc
.State(B2_path
, {
743 '' : Item(status
=' M'),
744 'E' : Item(status
=' M'),
745 'E/alpha' : Item(status
=' M'),
746 'E/beta' : Item(status
=' M'),
747 'F' : Item(status
=' '),
748 'lambda' : Item(status
=' '),
750 expected_status
.tweak(wc_rev
=4)
751 expected_skip
= wc
.State('', { })
752 svntest
.actions
.run_and_verify_merge(B2_path
, '3', '4', B_url
,
757 None, None, None, None, None, 1)
760 svntest
.actions
.run_and_verify_svn(None, None, [],
761 'revert', '--recursive', wc_dir
)
762 svntest
.actions
.run_and_verify_status(wc_dir
, pristine_status
)
764 # Merge B 2:1 into B2 (B2's mergeinfo should get elided away)
765 expected_status
.tweak('', status
=' ')
766 expected_disk
.remove('')
767 expected_disk
.tweak('E', 'E/alpha', 'E/beta', props
={})
768 svntest
.actions
.run_and_verify_merge(B2_path
, '2', '1', B_url
,
773 None, None, None, None, None, 1)
775 # Merge B 3:4 into B2 now causes a conflict
777 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:4'}),
778 'E/dir_conflicts.prej'
779 : Item("Trying to change property 'foo' from 'foo_val' to 'mod_foo',\n"
780 + "but it has been locally deleted.\n"),
782 : Item("Trying to change property 'foo' from 'foo_val' to 'mod_foo',\n"
783 + "but it has been locally deleted.\n"),
785 : Item("Trying to change property 'foo' from 'foo?\\129val' to"
786 + " 'mod?\\129foo',\n"
787 + "but it has been locally deleted.\n"),
789 expected_disk
.tweak('E', 'E/alpha', props
={'bar' : 'bar_val'})
790 expected_disk
.tweak('E/beta', props
={'bar' : 'bar\201val'})
791 expected_status
.tweak('', status
=' M')
792 expected_status
.tweak('E', 'E/alpha', 'E/beta', status
=' C')
793 expected_output
.tweak('E', 'E/alpha', 'E/beta', status
=' C')
794 svntest
.actions
.run_and_verify_merge(B2_path
, '3', '4', B_url
,
799 None, None, None, None, None, 1)
801 # issue 1109 : single file property merge. This test performs a merge
802 # that should be a no-op (adding properties that are already present).
803 svntest
.actions
.run_and_verify_svn(None, None, [],
804 'revert', '--recursive', wc_dir
)
805 svntest
.actions
.run_and_verify_status(wc_dir
, pristine_status
)
807 # Copy A at rev 4 to A2 to make revision 5.
808 A_url
= sbox
.repo_url
+ '/A'
809 A2_url
= sbox
.repo_url
+ '/A2'
810 svntest
.actions
.run_and_verify_svn(None,
811 ['\n', 'Committed revision 5.\n'], [],
812 'copy', '-m', 'copy A to A2',
815 # Re-root the WC at A2.
816 svntest
.actions
.run_and_verify_svn(None, None, [], 'switch', A2_url
, wc_dir
)
818 # Attempt to re-merge rev 4 of the original A's alpha. Mergeinfo
819 # inherited from A2 (created by its copy from A) allows us to avoid
821 alpha_url
= sbox
.repo_url
+ '/A/B/E/alpha'
822 alpha_path
= os
.path
.join(wc_dir
, 'B', 'E', 'alpha')
824 # Cannot use run_and_verify_merge with a file target
825 svntest
.actions
.run_and_verify_svn(None, [], [], 'merge', '-r', '3:4',
826 alpha_url
, alpha_path
)
828 output
, err
= svntest
.actions
.run_and_verify_svn(None, None, [],
834 if re
.match("\\s*foo\\s*$", line
):
836 if re
.match("\\s*bar\\s*$", line
):
839 if not saw_foo
or not saw_bar
:
840 raise svntest
.Failure("Expected properties not found")
843 #----------------------------------------------------------------------
844 # This is a regression for issue #1176.
846 def merge_catches_nonexistent_target(sbox
):
847 "merge should not die if a target file is absent"
852 # Copy G to a new directory, Q. Create Q/newfile. Commit a change
853 # to Q/newfile. Now merge that change... into G. Merge should not
854 # error, but should do nothing.
856 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
857 Q_path
= os
.path
.join(wc_dir
, 'A', 'D', 'Q')
858 newfile_path
= os
.path
.join(Q_path
, 'newfile')
859 Q_url
= sbox
.repo_url
+ '/A/D/Q'
861 # Copy dir A/D/G to A/D/Q
862 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp', G_path
, Q_path
)
864 svntest
.main
.file_append(newfile_path
, 'This is newfile.\n')
865 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', newfile_path
)
867 # Add newfile to dir G, creating r2.
868 expected_output
= wc
.State(wc_dir
, {
869 'A/D/Q' : Item(verb
='Adding'),
870 'A/D/Q/newfile' : Item(verb
='Adding'),
872 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
873 expected_status
.add({
874 'A/D/Q' : Item(status
=' ', wc_rev
=2),
875 'A/D/Q/pi' : Item(status
=' ', wc_rev
=2),
876 'A/D/Q/rho' : Item(status
=' ', wc_rev
=2),
877 'A/D/Q/tau' : Item(status
=' ', wc_rev
=2),
878 'A/D/Q/newfile' : Item(status
=' ', wc_rev
=2),
880 svntest
.actions
.run_and_verify_commit(wc_dir
,
885 # Change newfile, creating r3.
886 svntest
.main
.file_append(newfile_path
, 'A change to newfile.\n')
887 expected_output
= wc
.State(wc_dir
, {
888 'A/D/Q/newfile' : Item(verb
='Sending'),
890 expected_status
.tweak('A/D/Q/newfile', wc_rev
=3)
891 svntest
.actions
.run_and_verify_commit(wc_dir
,
896 # Merge the change to newfile (from r3) into G, where newfile
899 expected_output
= wc
.State('', { })
900 expected_status
= wc
.State('', {
906 expected_status
.tweak(status
=' ', wc_rev
=1)
907 expected_disk
= wc
.State('', {
908 'pi' : Item("This is the file 'pi'.\n"),
909 'rho' : Item("This is the file 'rho'.\n"),
910 'tau' : Item("This is the file 'tau'.\n"),
912 expected_skip
= wc
.State('', {
915 svntest
.actions
.run_and_verify_merge('', '2', '3', Q_url
,
921 #----------------------------------------------------------------------
923 def merge_tree_deleted_in_target(sbox
):
924 "merge on deleted directory in target"
929 # Copy B to a new directory, I. Modify B/E/alpha, Remove I/E. Now
930 # merge that change... into I. Merge should not error
932 B_path
= os
.path
.join(wc_dir
, 'A', 'B')
933 I_path
= os
.path
.join(wc_dir
, 'A', 'I')
934 alpha_path
= os
.path
.join(B_path
, 'E', 'alpha')
935 B_url
= sbox
.repo_url
+ '/A/B'
936 I_url
= sbox
.repo_url
+ '/A/I'
939 # Copy B to I, creating r1.
940 svntest
.actions
.run_and_verify_svn(None, None, [],
941 'cp', B_url
, I_url
, '-m', 'rev 2')
943 # Change some files, creating r2.
944 svntest
.main
.file_append(alpha_path
, 'A change to alpha.\n')
945 svntest
.main
.file_append(os
.path
.join(B_path
, 'lambda'), 'change lambda.\n')
946 svntest
.actions
.run_and_verify_svn(None, None, [],
947 'ci', '-m', 'rev 3', B_path
)
949 # Remove E, creating r3.
950 E_url
= sbox
.repo_url
+ '/A/I/E'
951 svntest
.actions
.run_and_verify_svn(None, None, [],
952 'rm', E_url
, '-m', 'rev 4')
954 svntest
.actions
.run_and_verify_svn(None, None, [],
955 'up', os
.path
.join(wc_dir
,'A'))
957 expected_output
= wc
.State(I_path
, {
958 'lambda' : Item(status
='U '),
960 expected_disk
= wc
.State('', {
961 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:3'}),
963 'lambda' : Item("This is the file 'lambda'.\nchange lambda.\n"),
965 expected_status
= wc
.State(I_path
, {
966 '' : Item(status
=' M'),
967 'F' : Item(status
=' '),
968 'lambda' : Item(status
='M '),
970 expected_status
.tweak(wc_rev
=4)
971 expected_skip
= wc
.State(I_path
, {
975 svntest
.actions
.run_and_verify_merge(I_path
, '2', '3', B_url
,
980 None, None, None, None, None,
983 #----------------------------------------------------------------------
986 def merge_added_dir_to_deleted_in_target(sbox
):
987 "merge an added dir on a deleted dir in target"
992 # copy B to a new directory, I.
997 B_url
= sbox
.repo_url
+ '/A/B'
998 I_url
= sbox
.repo_url
+ '/A/I'
999 F_url
= sbox
.repo_url
+ '/A/I/F'
1000 J_url
= sbox
.repo_url
+ '/A/B/F/J'
1001 I_path
= os
.path
.join(wc_dir
, 'A', 'I')
1004 svntest
.actions
.run_and_verify_svn(None, None, [],
1005 'cp', B_url
, I_url
, '-m', 'rev 2')
1007 svntest
.actions
.run_and_verify_svn(None, None, [],
1008 'rm', F_url
, '-m', 'rev 3')
1010 svntest
.actions
.run_and_verify_svn(None, None, [],
1011 'mkdir', '-m', 'rev 4', J_url
)
1013 svntest
.actions
.run_and_verify_svn(None, None, [],
1014 'up', os
.path
.join(wc_dir
,'A'))
1016 expected_output
= wc
.State(I_path
, {})
1017 expected_disk
= wc
.State('', {
1019 'E/alpha' : Item("This is the file 'alpha'.\n"),
1020 'E/beta' : Item("This is the file 'beta'.\n"),
1021 'lambda' : Item("This is the file 'lambda'.\n"),
1023 expected_skip
= wc
.State(I_path
, {
1028 svntest
.actions
.run_and_verify_merge(I_path
, '2', '4', B_url
,
1033 None, None, None, None, None,
1036 #----------------------------------------------------------------------
1037 # This is a regression for issue #1176.
1039 def merge_similar_unrelated_trees(sbox
):
1040 "merging similar trees ancestrally unrelated"
1042 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=1249. ##
1045 wc_dir
= sbox
.wc_dir
1047 # Simple test. Make three directories with the same content.
1048 # Modify some stuff in the second one. Now merge
1049 # (firstdir:seconddir->thirddir).
1051 base1_path
= os
.path
.join(wc_dir
, 'base1')
1052 base2_path
= os
.path
.join(wc_dir
, 'base2')
1053 apply_path
= os
.path
.join(wc_dir
, 'apply')
1055 base1_url
= os
.path
.join(sbox
.repo_url
+ '/base1')
1056 base2_url
= os
.path
.join(sbox
.repo_url
+ '/base2')
1058 # Make a tree of stuff ...
1059 os
.mkdir(base1_path
)
1060 svntest
.main
.file_append(os
.path
.join(base1_path
, 'iota'),
1061 "This is the file iota\n")
1062 os
.mkdir(os
.path
.join(base1_path
, 'A'))
1063 svntest
.main
.file_append(os
.path
.join(base1_path
, 'A', 'mu'),
1064 "This is the file mu\n")
1065 os
.mkdir(os
.path
.join(base1_path
, 'A', 'B'))
1066 svntest
.main
.file_append(os
.path
.join(base1_path
, 'A', 'B', 'alpha'),
1067 "This is the file alpha\n")
1068 svntest
.main
.file_append(os
.path
.join(base1_path
, 'A', 'B', 'beta'),
1069 "This is the file beta\n")
1071 # ... Copy it twice ...
1072 shutil
.copytree(base1_path
, base2_path
)
1073 shutil
.copytree(base1_path
, apply_path
)
1075 # ... Gonna see if merge is naughty or nice!
1076 svntest
.main
.file_append(os
.path
.join(base2_path
, 'A', 'mu'),
1077 "A new line in mu.\n")
1078 os
.rename(os
.path
.join(base2_path
, 'A', 'B', 'beta'),
1079 os
.path
.join(base2_path
, 'A', 'B', 'zeta'))
1081 svntest
.actions
.run_and_verify_svn(None, None, [],
1082 'add', base1_path
, base2_path
, apply_path
)
1084 svntest
.actions
.run_and_verify_svn(None, None, [],
1085 'ci', '-m', 'rev 2', wc_dir
)
1087 expected_output
= wc
.State(apply_path
, {
1088 'A/mu' : Item(status
='U '),
1089 'A/B/zeta' : Item(status
='A '),
1090 'A/B/beta' : Item(status
='D '),
1093 # Search for the comment entitled "The Merge Kluge" elsewhere in
1094 # this file, to understand why we shorten and chdir() below.
1095 saved_cwd
= os
.getcwd()
1096 os
.chdir(svntest
.main
.work_dir
)
1097 # run_and_verify_merge doesn't support 'svn merge URL URL path'
1098 svntest
.actions
.run_and_verify_svn(None, None, [],
1100 '--ignore-ancestry',
1101 base1_url
, base2_url
,
1102 shorten_path_kludge(apply_path
))
1105 expected_status
= wc
.State(apply_path
, {
1106 '' : Item(status
=' '),
1107 'A' : Item(status
=' '),
1108 'A/mu' : Item(status
='M '),
1109 'A/B' : Item(status
=' '),
1110 'A/B/zeta' : Item(status
='A ', copied
='+'),
1111 'A/B/alpha' : Item(status
=' '),
1112 'A/B/beta' : Item(status
='D '),
1113 'iota' : Item(status
=' '),
1115 expected_status
.tweak(wc_rev
=2)
1116 expected_status
.tweak('A/B/zeta', wc_rev
='-')
1117 svntest
.actions
.run_and_verify_status(apply_path
, expected_status
)
1119 #----------------------------------------------------------------------
1120 def merge_one_file_helper(sbox
, arg_flav
, record_only
= 0):
1121 "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
1123 if arg_flav
not in ('r', 'c', '*'):
1124 raise svntest
.Failure("Unrecognized flavor of merge argument")
1127 wc_dir
= sbox
.wc_dir
1129 rho_rel_path
= os
.path
.join('A', 'D', 'G', 'rho')
1130 rho_path
= os
.path
.join(wc_dir
, rho_rel_path
)
1131 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
1132 rho_url
= sbox
.repo_url
+ '/A/D/G/rho'
1134 # Change rho for revision 2
1135 svntest
.main
.file_append(rho_path
, 'A new line in rho.\n')
1137 expected_output
= wc
.State(wc_dir
, { rho_rel_path
: Item(verb
='Sending'), })
1138 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1139 expected_status
.tweak('A/D/G/rho', wc_rev
=2)
1140 svntest
.actions
.run_and_verify_commit(wc_dir
,
1146 # Backdate rho to revision 1, so we can merge in the rev 2 changes.
1147 svntest
.actions
.run_and_verify_svn(None, None, [],
1148 'up', '-r', '1', rho_path
)
1150 # Try one merge with an explicit target; it should succeed.
1151 # ### Yes, it would be nice to use run_and_verify_merge(), but it
1152 # appears to be impossible to get the expected_foo trees working
1153 # right. I think something is still assuming a directory target.
1155 svntest
.actions
.run_and_verify_svn(None ,
1156 expected_merge_output([[2]], 'U ' +
1159 'merge', '-r', '1:2',
1161 elif arg_flav
== 'c':
1162 svntest
.actions
.run_and_verify_svn(None ,
1163 expected_merge_output([[2]], 'U ' +
1168 elif arg_flav
== '*':
1169 svntest
.actions
.run_and_verify_svn(None ,
1170 expected_merge_output([[2]], 'U ' +
1173 'merge', rho_url
, rho_path
)
1175 expected_status
.tweak(wc_rev
=1)
1176 expected_status
.tweak('A/D/G/rho', status
='MM')
1177 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1179 # Inspect rho, make sure it's right.
1180 rho_text
= svntest
.tree
.get_text(rho_path
)
1181 if rho_text
!= "This is the file 'rho'.\nA new line in rho.\n":
1182 raise svntest
.Failure("Unexpected text in merged '" + rho_path
+ "'")
1184 # Restore rho to pristine revision 1, for another merge.
1185 svntest
.actions
.run_and_verify_svn(None, None, [], 'revert', rho_path
)
1186 expected_status
.tweak('A/D/G/rho', status
=' ')
1187 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1189 # Cd into the directory and run merge with no targets.
1190 # It should still merge into rho.
1191 saved_cwd
= os
.getcwd()
1194 # Cannot use run_and_verify_merge with a file target
1195 merge_cmd
= ['merge']
1197 merge_cmd
+= ['-r', '1:2']
1198 elif arg_flav
== 'c':
1199 merge_cmd
+= ['-c', '2']
1202 expected_output
= []
1203 merge_cmd
.append('--record-only')
1204 rho_expected_status
= ' M'
1206 expected_output
= expected_merge_output([[2]], 'U rho\n')
1207 rho_expected_status
= 'MM'
1208 merge_cmd
.append(rho_url
)
1210 svntest
.actions
.run_and_verify_svn(None, expected_output
, [], *merge_cmd
)
1212 # Inspect rho, make sure it's right.
1213 rho_text
= svntest
.tree
.get_text('rho')
1215 expected_text
= "This is the file 'rho'.\n"
1217 expected_text
= "This is the file 'rho'.\nA new line in rho.\n"
1218 if rho_text
!= expected_text
:
1220 raise svntest
.Failure("Unexpected text merged to 'rho' in '" +
1224 expected_status
.tweak('A/D/G/rho', status
=rho_expected_status
)
1225 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1227 def merge_one_file_using_r(sbox
):
1228 "merge one file (issue #1150) using the -r option"
1229 merge_one_file_helper(sbox
, 'r')
1231 def merge_one_file_using_c(sbox
):
1232 "merge one file (issue #1150) using the -c option"
1233 merge_one_file_helper(sbox
, 'c')
1235 def merge_one_file_using_implicit_revs(sbox
):
1236 "merge one file without explicit revisions"
1237 merge_one_file_helper(sbox
, '*')
1239 def merge_record_only(sbox
):
1240 "mark a revision range as merged"
1241 merge_one_file_helper(sbox
, 'r', 1)
1243 #----------------------------------------------------------------------
1244 # This is a regression for the enhancement added in issue #785.
1246 def merge_with_implicit_target_helper(sbox
, arg_flav
):
1247 "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
1249 if arg_flav
not in ('r', 'c', '*'):
1250 raise svntest
.Failure("Unrecognized flavor of merge argument")
1253 wc_dir
= sbox
.wc_dir
1255 # Change mu for revision 2
1256 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1257 orig_mu_text
= svntest
.tree
.get_text(mu_path
)
1259 for x
in range(2,11):
1260 added_mu_text
= added_mu_text
+ 'This is line ' + `x`
+ ' in mu\n'
1261 svntest
.main
.file_append(mu_path
, added_mu_text
)
1263 # Create expected output tree for initial commit
1264 expected_output
= wc
.State(wc_dir
, {
1265 'A/mu' : Item(verb
='Sending'),
1268 # Create expected status tree; all local revisions should be at 1,
1269 # but mu should be at revision 2.
1270 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1271 expected_status
.tweak('A/mu', wc_rev
=2)
1274 svntest
.actions
.run_and_verify_commit(wc_dir
,
1280 # Make the "other" working copy, at r1
1281 other_wc
= sbox
.add_wc_path('other')
1282 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
1283 svntest
.main
.run_svn(None, 'up', '-r', 1, other_wc
)
1285 # Try the merge without an explicit target; it should succeed.
1286 # Can't use run_and_verify_merge cuz it expects a directory argument.
1287 mu_url
= sbox
.repo_url
+ '/A/mu'
1289 os
.chdir(os
.path
.join(other_wc
, 'A'))
1291 # merge using filename for sourcepath
1292 # Cannot use run_and_verify_merge with a file target
1294 svntest
.actions
.run_and_verify_svn(None,
1295 expected_merge_output([[2]],
1298 'merge', '-r', '1:2', 'mu')
1299 elif arg_flav
== 'c':
1300 svntest
.actions
.run_and_verify_svn(None,
1301 expected_merge_output([[2]],
1304 'merge', '-c', '2', 'mu')
1306 elif arg_flav
== '*':
1307 svntest
.actions
.run_and_verify_svn(None,
1308 expected_merge_output([[2]],
1313 # sanity-check resulting file
1314 if (svntest
.tree
.get_text('mu') != orig_mu_text
+ added_mu_text
):
1315 raise svntest
.Failure("Unexpected text in 'mu'")
1317 # merge using URL for sourcepath
1319 svntest
.actions
.run_and_verify_svn(None,
1320 expected_merge_output([[-2]],
1323 'merge', '-r', '2:1', mu_url
)
1324 elif arg_flav
== 'c':
1325 svntest
.actions
.run_and_verify_svn(None,
1326 expected_merge_output([[-2]],
1329 'merge', '-c', '-2', mu_url
)
1330 elif arg_flav
== '*':
1331 # Implicit merge source URL and revision range detection is for
1332 # forward merges only (e.g. non-reverts). Undo application of
1333 # r2 to enable continuation of the test case.
1334 svntest
.actions
.run_and_verify_svn(None,
1335 expected_merge_output([[-2]],
1338 'merge', '-c', '-2', mu_url
)
1340 # sanity-check resulting file
1341 if (svntest
.tree
.get_text('mu') != orig_mu_text
):
1342 raise svntest
.Failure("Unexpected text '%s' in 'mu', expected '%s'" %
1343 (svntest
.tree
.get_text('mu'), orig_mu_text
))
1347 def merge_with_implicit_target_using_r(sbox
):
1348 "merging a file w/no explicit target path using -r"
1349 merge_with_implicit_target_helper(sbox
, 'r')
1351 def merge_with_implicit_target_using_c(sbox
):
1352 "merging a file w/no explicit target path using -c"
1353 merge_with_implicit_target_helper(sbox
, 'c')
1355 def merge_with_implicit_target_and_revs(sbox
):
1356 "merging a file w/no explicit target path or revs"
1357 merge_with_implicit_target_helper(sbox
, '*')
1360 #----------------------------------------------------------------------
1362 def merge_with_prev (sbox
):
1363 "merge operations using PREV revision"
1366 wc_dir
= sbox
.wc_dir
1368 # Change mu for revision 2
1369 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
1370 orig_mu_text
= svntest
.tree
.get_text(mu_path
)
1372 for x
in range(2,11):
1373 added_mu_text
= added_mu_text
+ '\nThis is line ' + `x`
+ ' in mu'
1374 added_mu_text
+= "\n"
1375 svntest
.main
.file_append(mu_path
, added_mu_text
)
1377 zot_path
= os
.path
.join(wc_dir
, 'A', 'zot')
1379 svntest
.main
.file_append(zot_path
, "bar")
1380 svntest
.main
.run_svn(None, 'add', zot_path
)
1382 # Create expected output tree for initial commit
1383 expected_output
= wc
.State(wc_dir
, {
1384 'A/mu' : Item(verb
='Sending'),
1385 'A/zot' : Item(verb
='Adding'),
1388 # Create expected status tree; all local revisions should be at 1,
1389 # but mu should be at revision 2.
1390 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1391 expected_status
.tweak('A/mu', wc_rev
=2)
1392 expected_status
.add({'A/zot' : Item(status
=' ', wc_rev
=2)})
1395 svntest
.actions
.run_and_verify_commit(wc_dir
,
1401 # Make some other working copies
1402 other_wc
= sbox
.add_wc_path('other')
1403 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
1405 another_wc
= sbox
.add_wc_path('another')
1406 svntest
.actions
.duplicate_dir(wc_dir
, another_wc
)
1408 was_cwd
= os
.getcwd()
1410 os
.chdir(os
.path
.join(other_wc
, 'A'))
1412 # Try to revert the last change to mu via svn merge
1413 # Cannot use run_and_verify_merge with a file target
1414 svntest
.actions
.run_and_verify_svn(None,
1415 expected_merge_output([[-2]],
1418 'merge', '-r', 'HEAD:PREV', 'mu')
1420 # sanity-check resulting file
1421 if (svntest
.tree
.get_text('mu') != orig_mu_text
):
1422 raise svntest
.Failure("Unexpected text in 'mu'")
1426 other_status
= expected_status
1427 other_status
.wc_dir
= other_wc
1428 other_status
.tweak('A/mu', status
='M ', wc_rev
=2)
1429 other_status
.tweak('A/zot', wc_rev
=2)
1430 svntest
.actions
.run_and_verify_status(other_wc
, other_status
)
1432 os
.chdir(another_wc
)
1434 # ensure 'A' will be at revision 2
1435 svntest
.actions
.run_and_verify_svn(None, None, [], 'up')
1437 # now try a revert on a directory, and verify that it removed the zot
1438 # file we had added previously
1439 svntest
.actions
.run_and_verify_svn(None, None, [],
1440 'merge', '-r', 'COMMITTED:PREV',
1443 if (svntest
.tree
.get_text('A/zot') != None):
1444 raise svntest
.Failure("Unexpected text in 'A/zot'")
1448 another_status
= expected_status
1449 another_status
.wc_dir
= another_wc
1450 another_status
.tweak(wc_rev
=2)
1451 another_status
.tweak('A/mu', status
='M ')
1452 another_status
.tweak('A/zot', status
='D ')
1453 svntest
.actions
.run_and_verify_status(another_wc
, another_status
)
1455 #----------------------------------------------------------------------
1456 # Regression test for issue #1319: 'svn merge' should *not* 'C' when
1457 # merging a change into a binary file, unless it has local mods, or has
1458 # different contents from the left side of the merge.
1460 def merge_binary_file (sbox
):
1461 "merge change into unchanged binary file"
1464 wc_dir
= sbox
.wc_dir
1466 # Add a binary file to the project
1467 theta_contents
= svntest
.main
.file_read(
1468 os
.path
.join(sys
.path
[0], "theta.bin"), 'rb')
1469 # Write PNG file data into 'A/theta'.
1470 theta_path
= os
.path
.join(wc_dir
, 'A', 'theta')
1471 svntest
.main
.file_write(theta_path
, theta_contents
, 'wb')
1473 svntest
.main
.run_svn(None, 'add', theta_path
)
1475 # Commit the new binary file, creating revision 2.
1476 expected_output
= svntest
.wc
.State(wc_dir
, {
1477 'A/theta' : Item(verb
='Adding (bin)'),
1479 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1480 expected_status
.add({
1481 'A/theta' : Item(status
=' ', wc_rev
=2),
1483 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1484 expected_status
, None,
1487 # Make the "other" working copy
1488 other_wc
= sbox
.add_wc_path('other')
1489 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
1491 # Change the binary file in first working copy, commit revision 3.
1492 svntest
.main
.file_append(theta_path
, "some extra junk")
1493 expected_output
= wc
.State(wc_dir
, {
1494 'A/theta' : Item(verb
='Sending'),
1496 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1497 expected_status
.add({
1498 'A/theta' : Item(status
=' ', wc_rev
=3),
1500 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1501 expected_status
, None,
1504 # Search for the comment entitled "The Merge Kluge" elsewhere in
1505 # this file, to understand why we shorten and chdir() below.
1506 short_other_wc
= shorten_path_kludge(other_wc
)
1508 # In second working copy, attempt to 'svn merge -r 2:3'.
1509 # We should *not* see a conflict during the update, but a 'U'.
1510 # And after the merge, the status should be 'M'.
1511 expected_output
= wc
.State(short_other_wc
, {
1512 'A/theta' : Item(status
='U '),
1514 expected_disk
= svntest
.main
.greek_state
.copy()
1516 '' : Item(props
={SVN_PROP_MERGEINFO
: '/:3'}),
1517 'A/theta' : Item(theta_contents
+ "some extra junk",
1518 props
={'svn:mime-type' : 'application/octet-stream'}),
1520 expected_status
= svntest
.actions
.get_virginal_state(short_other_wc
, 1)
1521 expected_status
.add({
1522 '' : Item(status
=' M', wc_rev
=1),
1523 'A/theta' : Item(status
='M ', wc_rev
=2),
1525 expected_skip
= wc
.State('', { })
1527 os
.chdir(svntest
.main
.work_dir
)
1528 svntest
.actions
.run_and_verify_merge(short_other_wc
, '2', '3',
1534 None, None, None, None, None,
1537 #----------------------------------------------------------------------
1538 # Regression test for issue #2403: Incorrect 3-way merge of "added"
1539 # binary file which already exists (unmodified) in the WC
1541 def three_way_merge_add_of_existing_binary_file(sbox
):
1542 "3-way merge of 'file add' into existing binary"
1545 wc_dir
= sbox
.wc_dir
1547 # Create a branch of A, creating revision 2.
1548 A_url
= sbox
.repo_url
+ "/A"
1549 branch_A_url
= sbox
.repo_url
+ "/copy-of-A"
1550 svntest
.actions
.run_and_verify_svn(None, None, [],
1552 A_url
, branch_A_url
,
1553 "-m", "Creating copy-of-A")
1555 # Add a binary file to the WC.
1556 theta_contents
= svntest
.main
.file_read(
1557 os
.path
.join(sys
.path
[0], "theta.bin"), 'rb')
1558 # Write PNG file data into 'A/theta'.
1559 theta_path
= os
.path
.join(wc_dir
, 'A', 'theta')
1560 svntest
.main
.file_write(theta_path
, theta_contents
, 'wb')
1562 svntest
.main
.run_svn(None, "add", theta_path
)
1564 # Commit the new binary file to the repos, creating revision 3.
1565 expected_output
= svntest
.wc
.State(wc_dir
, {
1566 "A/theta" : Item(verb
="Adding (bin)"),
1568 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1569 expected_status
.add({
1570 "A/theta" : Item(status
=" ", wc_rev
=3),
1572 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
1573 expected_status
, None,
1576 # Search for the comment entitled "The Merge Kluge" elsewhere in
1577 # this file, to understand why we shorten and chdir() below.
1578 short_wc
= shorten_path_kludge(wc_dir
)
1580 # In the working copy, attempt to 'svn merge branch_A_url@2 A_url@3 A'.
1581 # We should *not* see a conflict during the merge, but an 'A'.
1582 # And after the merge, the status should not report any differences.
1584 expected_output
= wc
.State(short_wc
, {
1585 "A/theta" : Item(status
="A "),
1588 # As greek_state is rooted at / instead of /A (our merge target), we
1589 # need a sub-tree of it rather than straight copy.
1590 expected_disk
= svntest
.main
.greek_state
.subtree("A")
1592 "" : Item(props
={SVN_PROP_MERGEINFO
: '/A:2-3'}),
1593 "theta" : Item(theta_contents
,
1594 props
={"svn:mime-type" : "application/octet-stream"}),
1596 expected_status
= svntest
.actions
.get_virginal_state(short_wc
, 1)
1597 expected_status
.add({
1598 "A/theta" : Item(status
=" ", wc_rev
=3),
1600 expected_status
.tweak("A", status
=" M")
1601 expected_status
.remove("") # top-level of the WC
1602 expected_status
.remove("iota")
1603 expected_skip
= wc
.State("", { })
1605 os
.chdir(svntest
.main
.work_dir
)
1606 # If we merge into short_wc alone, theta appears at the WC root,
1607 # which is in the wrong location -- append "/A" to stay on target.
1608 svntest
.actions
.run_and_verify_merge2(short_wc
+ "/A", "2", "3",
1609 branch_A_url
, A_url
,
1614 None, None, None, None, None,
1617 #----------------------------------------------------------------------
1618 # Regression test for Issue #1297:
1619 # A merge that creates a new file followed by an immediate diff
1620 # The diff should succeed.
1622 def merge_in_new_file_and_diff(sbox
):
1623 "diff after merge that creates a new file"
1626 wc_dir
= sbox
.wc_dir
1628 trunk_url
= sbox
.repo_url
+ '/A/B/E'
1631 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp',
1633 sbox
.repo_url
+ '/branch',
1634 '-m', "Creating the Branch")
1636 # Update to revision 2.
1637 svntest
.actions
.run_and_verify_svn(None, None, [],
1640 new_file_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'newfile')
1641 svntest
.main
.file_write(new_file_path
, "newfile\n")
1643 # Add the new file, and commit revision 3.
1644 svntest
.actions
.run_and_verify_svn(None, None, [], "add", new_file_path
)
1645 svntest
.actions
.run_and_verify_svn(None, None, [],
1647 "Changing the trunk.", wc_dir
)
1649 # Search for the comment entitled "The Merge Kluge" elsewhere in
1650 # this file, to understand why we shorten and chdir() below.
1651 branch_path
= os
.path
.join(wc_dir
, "branch")
1652 short_branch_path
= shorten_path_kludge(branch_path
)
1654 # Merge our addition into the branch.
1655 expected_output
= svntest
.wc
.State(short_branch_path
, {
1656 'newfile' : Item(status
='A '),
1658 expected_disk
= wc
.State('', {
1659 'alpha' : Item("This is the file 'alpha'.\n"),
1660 'beta' : Item("This is the file 'beta'.\n"),
1661 'newfile' : Item("newfile\n"),
1663 expected_status
= wc
.State(short_branch_path
, {
1664 '' : Item(status
=' M', wc_rev
=2),
1665 'alpha' : Item(status
=' ', wc_rev
=2),
1666 'beta' : Item(status
=' ', wc_rev
=2),
1667 'newfile' : Item(status
='A ', wc_rev
='-', copied
='+')
1669 expected_skip
= wc
.State('', { })
1671 saved_cwd
= os
.getcwd()
1673 os
.chdir(svntest
.main
.work_dir
)
1674 svntest
.actions
.run_and_verify_merge(short_branch_path
,
1675 '1', 'HEAD', trunk_url
,
1683 # Finally, run diff. This diff produces no output!
1686 "Property changes on: " + branch_path
+ "\n",
1687 "___________________________________________________________________\n",
1688 "Added: " + SVN_PROP_MERGEINFO
+ "\n",
1689 " Merged /A/B/E:r2-3\n",
1691 svntest
.actions
.run_and_verify_svn(None, expected_output
, [], 'diff',
1695 #----------------------------------------------------------------------
1697 # Issue #1425: 'svn merge' should skip over any unversioned obstructions.
1699 def merge_skips_obstructions(sbox
):
1700 "merge should skip over unversioned obstructions"
1703 wc_dir
= sbox
.wc_dir
1705 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
1706 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
1707 F_url
= sbox
.repo_url
+ '/A/B/F'
1709 Q_path
= os
.path
.join(F_path
, 'Q')
1710 foo_path
= os
.path
.join(F_path
, 'foo')
1711 bar_path
= os
.path
.join(F_path
, 'Q', 'bar')
1713 svntest
.main
.run_svn(None, 'mkdir', Q_path
)
1714 svntest
.main
.file_append(foo_path
, "foo")
1715 svntest
.main
.file_append(bar_path
, "bar")
1716 svntest
.main
.run_svn(None, 'add', foo_path
, bar_path
)
1718 expected_output
= wc
.State(wc_dir
, {
1719 'A/B/F/Q' : Item(verb
='Adding'),
1720 'A/B/F/Q/bar' : Item(verb
='Adding'),
1721 'A/B/F/foo' : Item(verb
='Adding'),
1723 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
1724 expected_status
.add({
1725 'A/B/F/Q' : Item(status
=' ', wc_rev
=2),
1726 'A/B/F/Q/bar' : Item(status
=' ', wc_rev
=2),
1727 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
1729 svntest
.actions
.run_and_verify_commit(wc_dir
,
1735 pre_merge_status
= expected_status
1737 # Revision 2 now has A/B/F/foo, A/B/F/Q, A/B/F/Q/bar. Let's merge
1738 # those 'F' changes into empty dir 'C'. But first, create an
1739 # unversioned 'foo' within C, and make sure 'svn merge' doesn't
1740 # error when the addition of foo is obstructed.
1742 # Search for the comment entitled "The Merge Kluge" elsewhere in
1743 # this file, to understand why we shorten and chdir() below.
1744 short_C_path
= shorten_path_kludge(C_path
)
1746 expected_output
= wc
.State(short_C_path
, {
1747 'Q' : Item(status
='A '),
1748 'Q/bar' : Item(status
='A '),
1750 expected_disk
= wc
.State('', {
1751 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2'}),
1753 'Q/bar' : Item("bar"),
1754 'foo' : Item("foo"),
1756 expected_status
= wc
.State(short_C_path
, {
1757 '' : Item(status
=' M', wc_rev
=1),
1758 'Q' : Item(status
='A ', wc_rev
='-', copied
='+'),
1759 'Q/bar' : Item(status
='A ', wc_rev
='-', copied
='+'),
1761 expected_skip
= wc
.State(short_C_path
, {
1765 svntest
.main
.file_append(os
.path
.join(C_path
, "foo"), "foo")
1767 saved_cwd
= os
.getcwd()
1769 os
.chdir(svntest
.main
.work_dir
)
1770 svntest
.actions
.run_and_verify_merge(short_C_path
, '1', '2', F_url
,
1775 None, None, None, None, None,
1780 # Revert the local mods, and this time make "Q" obstructed. An
1781 # unversioned file called "Q" will obstruct the adding of the
1782 # directory of the same name.
1784 svntest
.actions
.run_and_verify_svn(None, None, [],
1785 'revert', '-R', wc_dir
)
1786 os
.unlink(os
.path
.join(C_path
, "foo"))
1787 svntest
.main
.safe_rmtree(os
.path
.join(C_path
, "Q"))
1788 svntest
.main
.file_append(os
.path
.join(C_path
, "Q"), "foo") # unversioned
1789 svntest
.actions
.run_and_verify_status(wc_dir
, pre_merge_status
)
1791 # Search for the comment entitled "The Merge Kluge" elsewhere in
1792 # this file, to understand why we use short_C_path and chdir() below.
1793 expected_output
= wc
.State(short_C_path
, {
1794 'foo' : Item(status
='A '),
1796 expected_disk
= wc
.State('', {
1797 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2'}),
1799 'foo' : Item("foo"),
1801 expected_status
= wc
.State(short_C_path
, {
1802 '' : Item(status
=' M', wc_rev
=1),
1803 'foo' : Item(status
='A ', wc_rev
='-', copied
='+'),
1805 expected_skip
= wc
.State(short_C_path
, {
1810 saved_cwd
= os
.getcwd()
1812 os
.chdir(svntest
.main
.work_dir
)
1813 svntest
.actions
.run_and_verify_merge(short_C_path
, '1', '2', F_url
,
1818 None, None, None, None, None,
1823 # Revert the local mods, and commit the deletion of iota and A/D/G. (r3)
1824 os
.unlink(os
.path
.join(C_path
, "foo"))
1825 svntest
.actions
.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir
)
1826 svntest
.actions
.run_and_verify_status(wc_dir
, pre_merge_status
)
1828 iota_path
= os
.path
.join(wc_dir
, 'iota')
1829 G_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G')
1830 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', iota_path
, G_path
)
1832 expected_output
= wc
.State(wc_dir
, {
1833 'A/D/G' : Item(verb
='Deleting'),
1834 'iota' : Item(verb
='Deleting'),
1836 expected_status
= pre_merge_status
1837 expected_status
.remove('iota', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
1838 svntest
.actions
.run_and_verify_commit(wc_dir
,
1843 # Now create unversioned iota and A/D/G, try running a merge -r2:3.
1844 # The merge process should skip over these targets, since they're
1847 # Note: This merge, and all subsequent merges within this test,
1848 # skip *all* targets, so no mergeinfo is set.
1850 # Search for the comment entitled "The Merge Kluge" elsewhere in
1851 # this file, to understand why we shorten and chdir() below.
1852 short_wc_dir
= shorten_path_kludge(wc_dir
)
1854 svntest
.main
.file_append(iota_path
, "foo") # unversioned
1855 os
.mkdir(G_path
) # unversioned
1857 expected_output
= wc
.State(short_wc_dir
, { })
1858 expected_disk
= svntest
.main
.greek_state
.copy()
1859 expected_disk
.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
1862 'A/B/F/Q/bar' : Item("bar"),
1863 'A/B/F/foo' : Item("foo"),
1864 'iota' : Item("foo"),
1865 'A/C/Q' : Item("foo"),
1867 expected_skip
= wc
.State(short_wc_dir
, {
1872 saved_cwd
= os
.getcwd()
1874 os
.chdir(svntest
.main
.work_dir
)
1875 svntest
.actions
.run_and_verify_merge(short_wc_dir
, '2', '3',
1879 expected_status
.copy(short_wc_dir
),
1881 None, None, None, None, None,
1886 # Revert the local mods, and commit a change to A/B/lambda (r4), and then
1887 # commit the deletion of the same file. (r5)
1888 os
.unlink(iota_path
)
1889 svntest
.main
.safe_rmtree(G_path
)
1890 svntest
.actions
.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir
)
1891 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
1893 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
1894 svntest
.main
.file_append(lambda_path
, "more text")
1895 expected_output
= wc
.State(wc_dir
, {
1896 'A/B/lambda' : Item(verb
='Sending'),
1898 expected_status
.tweak('A/B/lambda', wc_rev
=4)
1899 svntest
.actions
.run_and_verify_commit(wc_dir
,
1904 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', lambda_path
)
1906 expected_output
= wc
.State(wc_dir
, {
1907 'A/B/lambda' : Item(verb
='Deleting'),
1909 expected_status
.remove('A/B/lambda')
1910 svntest
.actions
.run_and_verify_commit(wc_dir
,
1915 # lambda is gone, so create an unversioned lambda in its place.
1916 # Then attempt to merge -r3:4, which is a change to lambda. The merge
1917 # should simply skip the unversioned file.
1919 svntest
.main
.file_append(lambda_path
, "foo") # unversioned
1921 # Search for the comment entitled "The Merge Kluge" elsewhere in
1922 # this file, to understand why we use short_wc_dir and chdir() below.
1923 expected_output
= wc
.State(short_wc_dir
, { })
1925 'A/B/lambda' : Item("foo"),
1927 expected_disk
.remove('A/D/G', 'iota')
1928 expected_skip
= wc
.State(short_wc_dir
, {
1929 'A/B/lambda' : Item(),
1932 saved_cwd
= os
.getcwd()
1934 os
.chdir(svntest
.main
.work_dir
)
1935 svntest
.actions
.run_and_verify_merge(short_wc_dir
, '3', '4',
1939 expected_status
.copy(short_wc_dir
),
1941 None, None, None, None, None,
1946 # OK, so let's commit the new lambda (r6), and then delete the
1947 # working file. Then re-run the -r3:4 merge, and see how svn deals
1948 # with a file being under version control, but missing.
1950 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', lambda_path
)
1952 expected_output
= wc
.State(wc_dir
, {
1953 'A/B/lambda' : Item(verb
='Adding'),
1955 expected_status
.add({
1956 'A/B/lambda' : Item(wc_rev
=6, status
=' '),
1958 svntest
.actions
.run_and_verify_commit(wc_dir
,
1963 os
.unlink(lambda_path
)
1965 # Search for the comment entitled "The Merge Kluge" elsewhere in
1966 # this file, to understand why we use short_wc_dir and chdir() below.
1967 expected_output
= wc
.State(short_wc_dir
, { })
1968 expected_disk
.remove('A/B/lambda')
1969 expected_status
.tweak('A/B/lambda', status
='! ')
1971 os
.chdir(svntest
.main
.work_dir
)
1972 svntest
.actions
.run_and_verify_merge(short_wc_dir
, '3', '4',
1976 expected_status
.copy(short_wc_dir
),
1978 None, None, None, None, None,
1981 #----------------------------------------------------------------------
1982 # At one time, a merge that added items with the same name as missing
1983 # items would attempt to add the items and fail, leaving the working
1984 # copy locked and broken.
1986 def merge_into_missing(sbox
):
1987 "merge into missing must not break working copy"
1990 wc_dir
= sbox
.wc_dir
1992 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
1993 F_url
= sbox
.repo_url
+ '/A/B/F'
1994 Q_path
= os
.path
.join(F_path
, 'Q')
1995 foo_path
= os
.path
.join(F_path
, 'foo')
1997 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', Q_path
)
1998 svntest
.main
.file_append(foo_path
, "foo")
1999 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', foo_path
)
2001 expected_output
= wc
.State(wc_dir
, {
2002 'A/B/F/Q' : Item(verb
='Adding'),
2003 'A/B/F/foo' : Item(verb
='Adding'),
2005 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2006 expected_status
.add({
2007 'A/B/F/Q' : Item(status
=' ', wc_rev
=2),
2008 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
2010 svntest
.actions
.run_and_verify_commit(wc_dir
,
2015 R_path
= os
.path
.join(Q_path
, 'R')
2016 bar_path
= os
.path
.join(R_path
, 'bar')
2017 baz_path
= os
.path
.join(Q_path
, 'baz')
2018 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', R_path
)
2019 svntest
.main
.file_append(bar_path
, "bar")
2020 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', bar_path
)
2021 svntest
.main
.file_append(baz_path
, "baz")
2022 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', baz_path
)
2024 expected_output
= wc
.State(wc_dir
, {
2025 'A/B/F/Q/R' : Item(verb
='Adding'),
2026 'A/B/F/Q/R/bar' : Item(verb
='Adding'),
2027 'A/B/F/Q/baz' : Item(verb
='Adding'),
2029 expected_status
.add({
2030 'A/B/F/Q/R' : Item(status
=' ', wc_rev
=3),
2031 'A/B/F/Q/R/bar' : Item(status
=' ', wc_rev
=3),
2032 'A/B/F/Q/baz' : Item(status
=' ', wc_rev
=3),
2034 svntest
.actions
.run_and_verify_commit(wc_dir
,
2040 svntest
.main
.safe_rmtree(Q_path
)
2042 expected_output
= wc
.State(F_path
, {
2044 expected_disk
= wc
.State('', {
2046 expected_status
= wc
.State(F_path
, {
2047 '' : Item(status
=' ', wc_rev
=1),
2048 'foo' : Item(status
='! ', wc_rev
=2),
2049 'Q' : Item(status
='! ', wc_rev
='?'),
2051 expected_skip
= wc
.State(F_path
, {
2056 ### Need to real and dry-run separately since real merge notifies Q
2058 svntest
.actions
.run_and_verify_merge(F_path
, '1', '2', F_url
,
2063 None, None, None, None, None,
2066 svntest
.actions
.run_and_verify_merge(F_path
, '1', '2', F_url
,
2071 None, None, None, None, None,
2074 # This merge fails when it attempts to descend into the missing
2075 # directory. That's OK, there is no real need to support merge into
2076 # an incomplete working copy, so long as when it fails it doesn't
2077 # break the working copy.
2078 svntest
.main
.run_svn('Working copy not locked',
2079 'merge', '-r1:3', '--dry-run', F_url
, F_path
)
2081 svntest
.main
.run_svn('Working copy not locked',
2082 'merge', '-r1:3', F_url
, F_path
)
2084 # Check working copy is not locked.
2085 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2086 expected_status
.add({
2087 'A/B/F/foo' : Item(status
='! ', wc_rev
=2),
2088 'A/B/F/Q' : Item(status
='! ', wc_rev
='?'),
2090 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
2092 #----------------------------------------------------------------------
2093 # A test for issue 1738
2095 def dry_run_adds_file_with_prop(sbox
):
2096 "merge --dry-run adding a new file with props"
2099 wc_dir
= sbox
.wc_dir
2101 # Commit a new file which has a property.
2102 zig_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'zig')
2103 svntest
.main
.file_append(zig_path
, "zig contents")
2104 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', zig_path
)
2105 svntest
.actions
.run_and_verify_svn(None, None, [],
2106 'propset', 'foo', 'foo_val',
2109 expected_output
= wc
.State(wc_dir
, {
2110 'A/B/E/zig' : Item(verb
='Adding'),
2112 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2113 expected_status
.add({
2114 'A/B/E/zig' : Item(status
=' ', wc_rev
=2),
2116 svntest
.actions
.run_and_verify_commit(wc_dir
,
2121 # Do a regular merge of that change into a different dir.
2122 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
2123 E_url
= sbox
.repo_url
+ '/A/B/E'
2125 # Search for the comment entitled "The Merge Kluge" elsewhere in
2126 # this file, to understand why we shorten and chdir() below.
2127 short_F_path
= shorten_path_kludge(F_path
)
2129 expected_output
= wc
.State(short_F_path
, {
2130 'zig' : Item(status
='A '),
2132 expected_disk
= wc
.State('', {
2133 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/E:2'}),
2134 'zig' : Item("zig contents", {'foo':'foo_val'}),
2136 expected_skip
= wc
.State('', { })
2137 expected_status
= None # status is optional
2139 os
.chdir(svntest
.main
.work_dir
)
2140 svntest
.actions
.run_and_verify_merge(short_F_path
, '1', '2', E_url
,
2145 None, None, None, None, None,
2146 1, # please check props
2147 1) # and do a dry-run also)
2149 #----------------------------------------------------------------------
2151 # Regression test for issue #1673
2152 # Merge a binary file from two URL with a common ancestry
2154 def merge_binary_with_common_ancestry(sbox
):
2155 "merge binary files with common ancestry"
2158 wc_dir
= sbox
.wc_dir
2160 # Create the common ancestry path
2161 I_path
= os
.path
.join(wc_dir
, 'I')
2162 svntest
.main
.run_svn(None, 'mkdir', I_path
)
2164 # Add a binary file to the common ancestry path
2165 theta_contents
= svntest
.main
.file_read(
2166 os
.path
.join(sys
.path
[0], "theta.bin"), 'rb')
2167 theta_I_path
= os
.path
.join(I_path
, 'theta')
2168 svntest
.main
.file_write(theta_I_path
, theta_contents
)
2169 svntest
.main
.run_svn(None, 'add', theta_I_path
)
2170 svntest
.main
.run_svn(None, 'propset', 'svn:mime-type',
2171 'application/octet-stream', theta_I_path
)
2173 # Commit the ancestry
2174 expected_output
= wc
.State(wc_dir
, {
2175 'I' : Item(verb
='Adding'),
2176 'I/theta' : Item(verb
='Adding (bin)'),
2179 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2180 expected_status
.add({
2181 'I' : Item(status
=' ', wc_rev
=2),
2182 'I/theta' : Item(status
=' ', wc_rev
=2),
2185 svntest
.actions
.run_and_verify_commit(wc_dir
,
2186 expected_output
, expected_status
,
2190 # Create the first branch
2191 J_path
= os
.path
.join(wc_dir
, 'J')
2192 svntest
.main
.run_svn(None, 'copy', I_path
, J_path
)
2194 # Commit the first branch
2195 expected_output
= wc
.State(wc_dir
, {
2196 'J' : Item(verb
='Adding'),
2199 expected_status
.add({
2200 'J' : Item(status
=' ', wc_rev
=3),
2201 'J/theta' : Item(status
=' ', wc_rev
=3),
2204 svntest
.actions
.run_and_verify_commit(wc_dir
,
2205 expected_output
, expected_status
,
2209 # Create the path where the files will be merged
2210 K_path
= os
.path
.join(wc_dir
, 'K')
2211 svntest
.main
.run_svn(None, 'mkdir', K_path
)
2213 # Commit the new path
2214 expected_output
= wc
.State(wc_dir
, {
2215 'K' : Item(verb
='Adding'),
2218 expected_status
.add({
2219 'K' : Item(status
=' ', wc_rev
=4),
2222 svntest
.actions
.run_and_verify_commit(wc_dir
,
2223 expected_output
, expected_status
,
2227 # Copy 'I/theta' to 'K/'. This file will be merged later.
2228 theta_K_path
= os
.path
.join(K_path
, 'theta')
2229 svntest
.main
.run_svn(None, 'copy', theta_I_path
, theta_K_path
)
2231 # Commit the new file
2232 expected_output
= wc
.State(wc_dir
, {
2233 'K/theta' : Item(verb
='Adding (bin)'),
2236 expected_status
.add({
2237 'K/theta' : Item(status
=' ', wc_rev
=5),
2240 svntest
.actions
.run_and_verify_commit(wc_dir
,
2241 expected_output
, expected_status
,
2245 # Modify the original ancestry 'I/theta'
2246 svntest
.main
.file_append(theta_I_path
, "some extra junk")
2248 # Commit the modification
2249 expected_output
= wc
.State(wc_dir
, {
2250 'I/theta' : Item(verb
='Sending'),
2253 expected_status
.tweak('I/theta', wc_rev
=6)
2255 svntest
.actions
.run_and_verify_commit(wc_dir
,
2256 expected_output
, expected_status
,
2260 # Create the second branch from the modified ancestry
2261 L_path
= os
.path
.join(wc_dir
, 'L')
2262 svntest
.main
.run_svn(None, 'copy', I_path
, L_path
)
2264 # Commit the second branch
2265 expected_output
= wc
.State(wc_dir
, {
2266 'L' : Item(verb
='Adding'),
2267 'L/theta' : Item(verb
='Adding (bin)'),
2270 expected_status
.add({
2271 'L' : Item(status
=' ', wc_rev
=7),
2272 'L/theta' : Item(status
=' ', wc_rev
=7),
2275 svntest
.actions
.run_and_verify_commit(wc_dir
,
2276 expected_output
, expected_status
,
2280 # Now merge first ('J/') and second ('L/') branches into 'K/'
2281 saved_cwd
= os
.getcwd()
2284 theta_J_url
= sbox
.repo_url
+ '/J/theta'
2285 theta_L_url
= sbox
.repo_url
+ '/L/theta'
2286 svntest
.actions
.run_and_verify_svn(None,
2287 expected_merge_output(None,
2290 'merge', theta_J_url
, theta_L_url
)
2293 expected_status
.tweak('K/theta', status
='MM')
2294 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
2296 #----------------------------------------------------------------------
2297 # A test for issue 1905
2298 def merge_funny_chars_on_path(sbox
):
2299 "merge with funny characters (issue #1905)"
2302 wc_dir
= sbox
.wc_dir
2304 # In following lists: 'd' stands for directory, 'f' for file
2305 # targets to be added by recursive add
2307 ('d', 'dir_10', 'F%lename'),
2308 ('d', 'dir%20', 'F lename'),
2309 ('d', 'dir 30', 'Filename'),
2310 ('d', 'dir 40', None),
2311 ('f', 'F lename', None),
2314 # targets to be added by 'svn mkdir' + add
2316 ('d', 'dir_11', 'F%lename'),
2317 ('d', 'dir%21', 'Filename'),
2318 ('d', 'dir 31', 'F lename'),
2319 ('d', 'dir 41', None),
2322 for target
in add_by_add
:
2323 if target
[0] == 'd':
2324 target_dir
= os
.path
.join(wc_dir
, 'A', 'B', 'E', target
[1])
2325 os
.mkdir(target_dir
)
2327 target_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', '%s' % target
[1],
2329 svntest
.main
.file_append(target_path
, "%s/%s" % (target
[1], target
[2]))
2330 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', target_dir
)
2331 elif target
[0] == 'f':
2332 target_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', '%s' % target
[1])
2333 svntest
.main
.file_append(target_path
, "%s" % target
[1])
2334 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', target_path
)
2336 raise svntest
.Failure
2339 for target
in add_by_mkdir
:
2340 if target
[0] == 'd':
2341 target_dir
= os
.path
.join(wc_dir
, 'A', 'B', 'E', target
[1])
2342 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', target_dir
)
2344 target_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', '%s' % target
[1],
2346 svntest
.main
.file_append(target_path
, "%s/%s" % (target
[1], target
[2]))
2347 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', target_path
)
2349 expected_output_dic
= {}
2350 expected_status_dic
= {}
2352 for targets
in add_by_add
,add_by_mkdir
:
2353 for target
in targets
:
2354 key
= 'A/B/E/%s' % target
[1]
2355 expected_output_dic
[key
] = Item(verb
='Adding')
2356 expected_status_dic
[key
] = Item(status
=' ', wc_rev
=2)
2359 key
= 'A/B/E/%s/%s' % (target
[1], target
[2])
2360 expected_output_dic
[key
] = Item(verb
='Adding')
2361 expected_status_dic
[key
] = Item(status
=' ', wc_rev
=2)
2364 expected_output
= wc
.State(wc_dir
, expected_output_dic
)
2366 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2367 expected_status
.add(expected_status_dic
)
2369 svntest
.actions
.run_and_verify_commit(wc_dir
,
2374 # Do a regular merge of that change into a different dir.
2375 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
2376 E_url
= sbox
.repo_url
+ '/A/B/E'
2378 expected_output_dic
= {}
2379 expected_disk_dic
= {}
2381 for targets
in add_by_add
,add_by_mkdir
:
2382 for target
in targets
:
2383 key
= '%s' % target
[1]
2384 expected_output_dic
[key
] = Item(status
='A ')
2385 if target
[0] == 'd':
2386 expected_disk_dic
[key
] = Item(None, {})
2387 elif target
[0] == 'f':
2388 expected_disk_dic
[key
] = Item("%s" % target
[1], {})
2390 raise svntest
.Failure
2392 key
= '%s/%s' % (target
[1], target
[2])
2393 expected_output_dic
[key
] = Item(status
='A ')
2394 expected_disk_dic
[key
] = Item('%s/%s' % (target
[1], target
[2]), {})
2397 # Search for the comment entitled "The Merge Kluge" elsewhere in
2398 # this file, to understand why we shorten and chdir() below.
2399 short_F_path
= shorten_path_kludge(F_path
)
2401 expected_output
= wc
.State(short_F_path
, expected_output_dic
)
2403 expected_disk
= wc
.State('', expected_disk_dic
)
2404 expected_skip
= wc
.State('', { })
2405 expected_status
= None # status is optional
2407 saved_cwd
= os
.getcwd()
2409 os
.chdir(svntest
.main
.work_dir
)
2410 svntest
.actions
.run_and_verify_merge(short_F_path
, '1', '2', E_url
,
2415 None, None, None, None, None,
2416 0, # don't check props
2417 1) # but do a dry-run
2420 expected_output_dic
= {}
2422 for targets
in add_by_add
,add_by_mkdir
:
2423 for target
in targets
:
2424 key
= '%s' % target
[1]
2425 expected_output_dic
[key
] = Item(verb
='Adding')
2427 key
= '%s/%s' % (target
[1], target
[2])
2428 expected_output_dic
[key
] = Item(verb
='Adding')
2430 expected_output
= wc
.State(F_path
, expected_output_dic
)
2431 expected_output
.add({
2432 '' : Item(verb
='Sending'),
2435 svntest
.actions
.run_and_verify_commit(F_path
,
2440 #-----------------------------------------------------------------------
2441 # Regression test for issue #2064
2443 def merge_keyword_expansions(sbox
):
2444 "merge changes to keyword expansion property"
2448 wcpath
= sbox
.wc_dir
2449 tpath
= os
.path
.join(wcpath
, "t")
2450 bpath
= os
.path
.join(wcpath
, "b")
2451 t_fpath
= os
.path
.join(tpath
, 'f')
2452 b_fpath
= os
.path
.join(bpath
, 'f')
2455 svntest
.main
.run_svn(None, "add", tpath
)
2457 svntest
.actions
.run_and_verify_svn(None, None, [],
2458 "ci", "-m", "r2", wcpath
)
2461 svntest
.main
.run_svn(None, "cp", tpath
, bpath
)
2463 svntest
.actions
.run_and_verify_svn(None, None, [],
2464 "ci", "-m", "r3", wcpath
)
2467 svntest
.main
.file_append(t_fpath
, "$Revision$")
2468 svntest
.actions
.run_and_verify_svn(None, None, [],
2470 # Ask for keyword expansion in the file.
2471 svntest
.actions
.run_and_verify_svn(None, None, [],
2472 'propset', 'svn:keywords', 'Revision',
2475 svntest
.actions
.run_and_verify_svn(None, None, [],
2476 'ci', '-m', 'r4', wcpath
)
2478 # Update the wc before the merge.
2479 svntest
.actions
.run_and_verify_svn(None, None, [],
2482 expected_status
= svntest
.actions
.get_virginal_state(wcpath
, 4)
2483 expected_status
.add({
2484 't' : Item(status
=' ', wc_rev
=4),
2485 't/f' : Item(status
=' ', wc_rev
=4),
2486 'b' : Item(status
=' ', wc_rev
=4),
2488 svntest
.actions
.run_and_verify_status(wcpath
, expected_status
)
2492 # Search for the comment entitled "The Merge Kluge" elsewhere in
2493 # this file, to understand why we shorten and chdir() below.
2494 short_bpath
= shorten_path_kludge(bpath
)
2496 expected_output
= wc
.State(short_bpath
, {
2497 'f' : Item(status
='A '),
2499 expected_disk
= wc
.State('', {
2500 'f' : Item("$Revision: 4 $"),
2502 expected_status
= wc
.State(short_bpath
, {
2503 '' : Item(status
=' M', wc_rev
=4),
2504 'f' : Item(status
='A ', wc_rev
='-', copied
='+'),
2506 expected_skip
= wc
.State(short_bpath
, { })
2508 os
.chdir(svntest
.main
.work_dir
)
2509 svntest
.actions
.run_and_verify_merge(short_bpath
, '2', 'HEAD',
2510 sbox
.repo_url
+ '/t',
2516 #----------------------------------------------------------------------
2517 def merge_prop_change_to_deleted_target(sbox
):
2518 "merge prop change into deleted target"
2521 wc_dir
= sbox
.wc_dir
2523 # Add a property to alpha.
2524 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
2525 svntest
.actions
.run_and_verify_svn(None, None, [],
2526 'propset', 'foo', 'foo_val',
2529 # Commit the property add as r2.
2530 expected_output
= svntest
.wc
.State(wc_dir
, {
2531 'A/B/E/alpha' : Item(verb
='Sending'),
2533 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2534 expected_status
.tweak('A/B/E/alpha', wc_rev
=2, status
=' ')
2535 svntest
.actions
.run_and_verify_commit(wc_dir
,
2536 expected_output
, expected_status
,
2538 svntest
.actions
.run_and_verify_svn(None, None, [],
2541 # Remove alpha entirely.
2542 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', alpha_path
)
2543 expected_output
= wc
.State(wc_dir
, {
2544 'A/B/E/alpha' : Item(verb
='Deleting'),
2546 expected_status
.tweak(wc_rev
=2)
2547 expected_status
.remove('A/B/E/alpha')
2548 svntest
.actions
.run_and_verify_commit(wc_dir
,
2553 # Try merging the original propset, which applies to a target that
2554 # no longer exists. The bug would only reproduce when run from
2555 # inside the wc, so we cd in there. We have to use
2556 # --ignore-ancestry here because our merge logic will otherwise
2557 # prevent a merge of changes we already have.
2559 svntest
.actions
.run_and_verify_svn("Merge errored unexpectedly",
2560 svntest
.verify
.AnyOutput
, [], 'merge',
2561 '-r1:2', '--ignore-ancestry', '.')
2564 def set_up_dir_replace(sbox
):
2565 """Set up the working copy for directory replace tests, creating
2566 directory 'A/B/F/foo' with files 'new file' and 'new file2' within
2567 it (r2), and merging 'foo' onto 'C' (r3), then deleting 'A/B/F/foo'
2571 wc_dir
= sbox
.wc_dir
2573 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
2574 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
2575 F_url
= sbox
.repo_url
+ '/A/B/F'
2577 foo_path
= os
.path
.join(F_path
, 'foo')
2578 new_file
= os
.path
.join(foo_path
, "new file")
2579 new_file2
= os
.path
.join(foo_path
, "new file 2")
2581 # Make directory foo in F, and add some files within it.
2582 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', foo_path
)
2583 svntest
.main
.file_append(new_file
, "Initial text in new file.\n")
2584 svntest
.main
.file_append(new_file2
, "Initial text in new file 2.\n")
2585 svntest
.main
.run_svn(None, "add", new_file
)
2586 svntest
.main
.run_svn(None, "add", new_file2
)
2588 # Commit all the new content, creating r2.
2589 expected_output
= wc
.State(wc_dir
, {
2590 'A/B/F/foo' : Item(verb
='Adding'),
2591 'A/B/F/foo/new file' : Item(verb
='Adding'),
2592 'A/B/F/foo/new file 2' : Item(verb
='Adding'),
2594 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2595 expected_status
.add({
2596 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
2597 'A/B/F/foo/new file' : Item(status
=' ', wc_rev
=2),
2598 'A/B/F/foo/new file 2' : Item(status
=' ', wc_rev
=2),
2600 svntest
.actions
.run_and_verify_commit(wc_dir
,
2606 expected_output
= wc
.State(C_path
, {
2607 'foo' : Item(status
='A '),
2608 'foo/new file' : Item(status
='A '),
2609 'foo/new file 2' : Item(status
='A '),
2611 expected_disk
= wc
.State('', {
2612 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2'}),
2614 'foo/new file' : Item("Initial text in new file.\n"),
2615 'foo/new file 2' : Item("Initial text in new file 2.\n"),
2617 expected_status
= wc
.State(C_path
, {
2618 '' : Item(status
=' M', wc_rev
=1),
2619 'foo' : Item(status
='A ', wc_rev
='-', copied
='+'),
2620 'foo/new file' : Item(status
='A ', wc_rev
='-', copied
='+'),
2621 'foo/new file 2' : Item(status
='A ', wc_rev
='-', copied
='+'),
2623 expected_skip
= wc
.State(C_path
, { })
2624 svntest
.actions
.run_and_verify_merge(C_path
, '1', '2', F_url
,
2629 None, None, None, None, None, 1)
2630 # Commit merge of foo onto C, creating r3.
2631 expected_output
= svntest
.wc
.State(wc_dir
, {
2632 'A/C' : Item(verb
='Sending'),
2633 'A/C/foo' : Item(verb
='Adding'),
2634 'A/C/foo/new file' : Item(verb
='Adding'),
2635 'A/C/foo/new file 2' : Item(verb
='Adding'),
2637 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2638 expected_status
.add({
2639 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
2640 'A/C' : Item(status
=' ', wc_rev
=3),
2641 'A/B/F/foo/new file' : Item(status
=' ', wc_rev
=2),
2642 'A/B/F/foo/new file 2' : Item(status
=' ', wc_rev
=2),
2643 'A/C/foo' : Item(status
=' ', wc_rev
=3),
2644 'A/C/foo/new file' : Item(status
=' ', wc_rev
=3),
2645 'A/C/foo/new file 2' : Item(status
=' ', wc_rev
=3),
2648 svntest
.actions
.run_and_verify_commit(wc_dir
,
2653 # Delete foo on F, creating r4.
2654 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', foo_path
)
2655 expected_output
= svntest
.wc
.State(wc_dir
, {
2656 'A/B/F/foo' : Item(verb
='Deleting'),
2658 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2659 expected_status
.add({
2660 'A/C' : Item(status
=' ', wc_rev
=3),
2661 'A/C/foo' : Item(status
=' ', wc_rev
=3),
2662 'A/C/foo/new file' : Item(status
=' ', wc_rev
=3),
2663 'A/C/foo/new file 2' : Item(status
=' ', wc_rev
=3),
2665 svntest
.actions
.run_and_verify_commit(wc_dir
,
2670 #----------------------------------------------------------------------
2671 # A merge that replaces a directory
2672 # Tests for Issue #2144 and Issue #2607
2674 def merge_dir_replace(sbox
):
2675 "merge a replacement of a directory"
2677 set_up_dir_replace(sbox
)
2678 wc_dir
= sbox
.wc_dir
2680 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
2681 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
2682 F_url
= sbox
.repo_url
+ '/A/B/F'
2683 foo_path
= os
.path
.join(F_path
, 'foo')
2684 new_file2
= os
.path
.join(foo_path
, "new file 2")
2686 # Recreate foo in F and add a new folder and two files
2687 bar_path
= os
.path
.join(foo_path
, 'bar')
2688 foo_file
= os
.path
.join(foo_path
, "file foo")
2689 new_file3
= os
.path
.join(bar_path
, "new file 3")
2691 # Make a couple of directories, and add some files within them.
2692 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', foo_path
)
2693 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', bar_path
)
2694 svntest
.main
.file_append(new_file3
, "Initial text in new file 3.\n")
2695 svntest
.main
.run_svn(None, "add", new_file3
)
2696 svntest
.main
.file_append(foo_file
, "Initial text in file foo.\n")
2697 svntest
.main
.run_svn(None, "add", foo_file
)
2699 # Commit the new content, creating r5.
2700 expected_output
= wc
.State(wc_dir
, {
2701 'A/B/F/foo' : Item(verb
='Adding'),
2702 'A/B/F/foo/file foo' : Item(verb
='Adding'),
2703 'A/B/F/foo/bar' : Item(verb
='Adding'),
2704 'A/B/F/foo/bar/new file 3' : Item(verb
='Adding'),
2706 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2707 expected_status
.add({
2708 'A/B/F/foo' : Item(status
=' ', wc_rev
=5),
2709 'A/B/F/foo/file foo' : Item(status
=' ', wc_rev
=5),
2710 'A/B/F/foo/bar' : Item(status
=' ', wc_rev
=5),
2711 'A/B/F/foo/bar/new file 3' : Item(status
=' ', wc_rev
=5),
2712 'A/C' : Item(status
=' ', wc_rev
=3),
2713 'A/C/foo' : Item(status
=' ', wc_rev
=3),
2714 'A/C/foo/new file' : Item(status
=' ', wc_rev
=3),
2715 'A/C/foo/new file 2' : Item(status
=' ', wc_rev
=3),
2717 svntest
.actions
.run_and_verify_commit(wc_dir
,
2721 # Merge replacement of foo onto C
2722 expected_output
= wc
.State(C_path
, {
2723 'foo' : Item(status
='R '),
2724 'foo/file foo' : Item(status
='A '),
2725 'foo/bar' : Item(status
='A '),
2726 'foo/bar/new file 3' : Item(status
='A '),
2728 expected_disk
= wc
.State('', {
2729 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2-5'}),
2731 'foo/file foo' : Item("Initial text in file foo.\n"),
2733 'foo/bar/new file 3' : Item("Initial text in new file 3.\n"),
2735 expected_status
= wc
.State(C_path
, {
2736 '' : Item(status
=' M', wc_rev
=3),
2737 'foo' : Item(status
='R ', wc_rev
='-', copied
='+'),
2738 'foo/new file 2' : Item(status
='D ', wc_rev
='-', copied
='+'),
2739 'foo/file foo' : Item(status
='A ', wc_rev
='-', copied
='+'),
2740 'foo/bar' : Item(status
='A ', wc_rev
='-', copied
='+'),
2741 'foo/bar/new file 3' : Item(status
='A ', wc_rev
='-', copied
='+'),
2742 'foo/new file' : Item(status
='D ', wc_rev
='-', copied
='+'),
2744 expected_skip
= wc
.State(C_path
, { })
2745 svntest
.actions
.run_and_verify_merge(C_path
, '2', '5', F_url
,
2750 None, None, None, None, None,
2752 0) # don't do a dry-run
2753 # the output differs
2755 # Commit merge of foo onto C
2756 expected_output
= svntest
.wc
.State(wc_dir
, {
2757 'A/C' : Item(verb
='Sending'),
2758 'A/C/foo' : Item(verb
='Replacing'),
2759 'A/C/foo/file foo' : Item(verb
='Adding'),
2760 'A/C/foo/bar' : Item(verb
='Adding'),
2761 'A/C/foo/bar/new file 3' : Item(verb
='Adding'),
2762 'A/C/foo/new file' : Item(verb
='Deleting'),
2763 'A/C/foo/new file 2' : Item(verb
='Deleting'),
2765 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2766 expected_status
.add({
2767 'A/B/F/foo' : Item(status
=' ', wc_rev
=5),
2768 'A/B/F/foo/file foo' : Item(status
=' ', wc_rev
=5),
2769 'A/B/F/foo/bar' : Item(status
=' ', wc_rev
=5),
2770 'A/B/F/foo/bar/new file 3' : Item(status
=' ', wc_rev
=5),
2771 'A/C' : Item(status
=' ', wc_rev
=6),
2772 'A/C/foo' : Item(status
=' ', wc_rev
=6),
2773 'A/C/foo/file foo' : Item(status
=' ', wc_rev
=6),
2774 'A/C/foo/bar' : Item(status
=' ', wc_rev
=6),
2775 'A/C/foo/bar/new file 3' : Item(status
=' ', wc_rev
=6),
2777 svntest
.actions
.run_and_verify_commit(wc_dir
,
2782 #----------------------------------------------------------------------
2783 # A merge that replaces a directory and one of its children
2784 # Tests for Issue #2690
2786 def merge_dir_and_file_replace(sbox
):
2787 "replace both dir and one of its children"
2789 set_up_dir_replace(sbox
)
2790 wc_dir
= sbox
.wc_dir
2792 C_path
= os
.path
.join(wc_dir
, 'A', 'C')
2793 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
2794 F_url
= sbox
.repo_url
+ '/A/B/F'
2795 foo_path
= os
.path
.join(F_path
, 'foo')
2796 new_file2
= os
.path
.join(foo_path
, "new file 2")
2798 # Recreate foo and 'new file 2' in F and add a new folder with a file
2799 bar_path
= os
.path
.join(foo_path
, 'bar')
2800 new_file3
= os
.path
.join(bar_path
, "new file 3")
2801 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', foo_path
)
2802 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', bar_path
)
2803 svntest
.main
.file_append(new_file3
, "Initial text in new file 3.\n")
2804 svntest
.main
.run_svn(None, "add", new_file3
)
2805 svntest
.main
.file_append(new_file2
, "New text in new file 2.\n")
2806 svntest
.main
.run_svn(None, "add", new_file2
)
2808 expected_output
= wc
.State(wc_dir
, {
2809 'A/B/F/foo' : Item(verb
='Adding'),
2810 'A/B/F/foo/new file 2' : Item(verb
='Adding'),
2811 'A/B/F/foo/bar' : Item(verb
='Adding'),
2812 'A/B/F/foo/bar/new file 3' : Item(verb
='Adding'),
2814 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2815 expected_status
.add({
2816 'A/B/F/foo' : Item(status
=' ', wc_rev
=5),
2817 'A/B/F/foo/new file 2' : Item(status
=' ', wc_rev
=5),
2818 'A/B/F/foo/bar' : Item(status
=' ', wc_rev
=5),
2819 'A/B/F/foo/bar/new file 3' : Item(status
=' ', wc_rev
=5),
2820 'A/C/foo' : Item(status
=' ', wc_rev
=3),
2821 'A/C/foo/new file' : Item(status
=' ', wc_rev
=3),
2822 'A/C/foo/new file 2' : Item(status
=' ', wc_rev
=3),
2824 svntest
.actions
.run_and_verify_commit(wc_dir
,
2828 # Merge replacement of foo onto C
2829 expected_output
= wc
.State(C_path
, {
2830 'foo' : Item(status
='D '),
2831 'foo' : Item(status
='A '),
2832 'foo/new file 2' : Item(status
='D '),
2833 'foo/new file 2' : Item(status
='A '),
2834 'foo/bar' : Item(status
='A '),
2835 'foo/bar/new file 3' : Item(status
='A '),
2836 'foo/new file' : Item(status
='D '),
2838 expected_disk
= wc
.State('', {
2839 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2-5'}),
2841 'foo/new file 2' : Item("New text in new file 2.\n"),
2843 'foo/bar/new file 3' : Item("Initial text in new file 3.\n"),
2845 expected_status
= wc
.State(C_path
, {
2846 '' : Item(status
=' ', wc_rev
=1),
2847 'foo' : Item(status
='R ', wc_rev
='-', copied
='+'),
2848 'foo/new file 2' : Item(status
='R ', wc_rev
='-', copied
='+'),
2849 'foo/bar' : Item(status
='A ', wc_rev
='-', copied
='+'),
2850 'foo/bar/new file 3' : Item(status
='A ', wc_rev
='-', copied
='+'),
2851 'foo/new file' : Item(status
='D ', wc_rev
='-', copied
='+'),
2853 expected_skip
= wc
.State(C_path
, { })
2854 svntest
.actions
.run_and_verify_merge(C_path
, '2', '5', F_url
,
2859 None, None, None, None, None,
2861 0) # don't do a dry-run
2862 # the output differs
2864 # Commit merge of foo onto C
2865 expected_output
= svntest
.wc
.State(wc_dir
, {
2866 'A/C/foo' : Item(verb
='Replacing'),
2867 'A/C/foo/new file 2' : Item(verb
='Replacing'),
2868 'A/C/foo/new file' : Item(verb
='Deleting'),
2869 'A/C/foo/bar' : Item(verb
='Adding'),
2870 'A/C/foo/bar/new file 3' : Item(verb
='Adding'),
2873 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2874 expected_status
.add({
2875 'A/B/F/foo' : Item(status
=' ', wc_rev
=5),
2876 'A/B/F/foo/new file 2' : Item(status
=' ', wc_rev
=5),
2877 'A/B/F/foo/bar' : Item(status
=' ', wc_rev
=5),
2878 'A/B/F/foo/bar/new file 3' : Item(status
=' ', wc_rev
=5),
2879 'A/C/foo' : Item(status
=' ', wc_rev
=6),
2880 'A/C/foo/new file 2' : Item(status
=' ', wc_rev
=6),
2881 'A/C/foo/bar' : Item(status
=' ', wc_rev
=6),
2882 'A/C/foo/bar/new file 3' : Item(status
=' ', wc_rev
=6),
2884 svntest
.actions
.run_and_verify_commit(wc_dir
,
2889 #----------------------------------------------------------------------
2890 def merge_file_with_space_in_its_name(sbox
):
2891 "merge a file whose name contains a space"
2894 wc_dir
= sbox
.wc_dir
2895 new_file
= os
.path
.join(wc_dir
, "new file")
2898 svntest
.main
.file_append(new_file
, "Initial text in the file.\n")
2899 svntest
.main
.run_svn(None, "add", new_file
)
2900 svntest
.actions
.run_and_verify_svn(None, None, [],
2901 "ci", "-m", "r2", wc_dir
)
2904 svntest
.main
.file_append(new_file
, "Next line of text in the file.\n")
2905 svntest
.actions
.run_and_verify_svn(None, None, [],
2906 "ci", "-m", "r3", wc_dir
)
2908 # Try to reverse merge.
2910 # The reproduction recipe requires that no explicit merge target be
2911 # passed, so we run merge from inside the wc dir where the target
2912 # file (i.e., the URL basename) lives.
2914 target_url
= sbox
.repo_url
+ '/new%20file'
2915 svntest
.actions
.run_and_verify_svn(None, None, [],
2916 "merge", "-r3:2", target_url
)
2918 #----------------------------------------------------------------------
2919 # A merge between two branches using no revision number with the dir being
2920 # created already existing as an unversioned directory.
2921 # Tests for Issue #2222
2923 def merge_dir_branches(sbox
):
2924 "merge between branches (Issue #2222)"
2927 wc_dir
= sbox
.wc_dir
2929 F_path
= os
.path
.join(wc_dir
, 'A', 'B', 'F')
2930 F_url
= sbox
.repo_url
+ '/A/B/F'
2931 C_url
= sbox
.repo_url
+ '/A/C'
2934 foo_path
= os
.path
.join(F_path
, 'foo')
2935 svntest
.actions
.run_and_verify_svn(None, None, [], 'mkdir', foo_path
)
2937 expected_output
= wc
.State(wc_dir
, {
2938 'A/B/F/foo' : Item(verb
='Adding'),
2940 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
2941 expected_status
.add({
2942 'A/B/F/foo' : Item(status
=' ', wc_rev
=2),
2944 svntest
.actions
.run_and_verify_commit(wc_dir
,
2949 # Create an unversioned foo
2950 foo_path
= os
.path
.join(wc_dir
, 'foo')
2953 # Merge from C to F onto the wc_dir
2954 # We can't use run_and_verify_merge because it doesn't support this
2955 # syntax of the merge command.
2956 ### TODO: We can use run_and_verify_merge2() here now.
2957 expected_output
= expected_merge_output(None, "A " + foo_path
+ "\n")
2958 svntest
.actions
.run_and_verify_svn(None, expected_output
, [],
2959 'merge', C_url
, F_url
, wc_dir
)
2961 # Run info to check the copied rev to make sure it's right
2962 expected_output
= ["Path: " + foo_path
+ "\n",
2963 "URL: " + sbox
.repo_url
+ "/foo\n",
2964 "Repository Root: " + sbox
.repo_url
+ "\n",
2966 "Node Kind: directory\n",
2968 "Copied From URL: " + F_url
+ "/foo\n",
2969 "Copied From Rev: 2\n", "\n"]
2970 svntest
.actions
.run_and_verify_svn(None, expected_output
, [],
2974 #----------------------------------------------------------------------
2976 def safe_property_merge(sbox
):
2977 "property merges don't overwrite existing prop-mods"
2980 wc_dir
= sbox
.wc_dir
2982 # Add a property to two files and a directory, commit as r2.
2983 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
2984 beta_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'beta')
2985 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
2987 svntest
.actions
.run_and_verify_svn(None, None, [],
2988 'propset', 'foo', 'foo_val',
2989 alpha_path
, beta_path
)
2990 svntest
.actions
.run_and_verify_svn(None, None, [],
2991 'propset', 'foo', 'foo_val',
2994 expected_output
= svntest
.wc
.State(wc_dir
, {
2995 'A/B/E' : Item(verb
='Sending'),
2996 'A/B/E/alpha' : Item(verb
='Sending'),
2997 'A/B/E/beta' : Item(verb
='Sending'),
2999 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3000 expected_status
.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
3001 wc_rev
=2, status
=' ')
3002 svntest
.actions
.run_and_verify_commit(wc_dir
,
3003 expected_output
, expected_status
,
3005 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3007 # Copy B to B2 as rev 3 (making a branch)
3008 B_url
= sbox
.repo_url
+ '/A/B'
3009 B2_url
= sbox
.repo_url
+ '/A/B2'
3011 svntest
.actions
.run_and_verify_svn(None, None, [],
3012 'copy', '-m', 'copy B to B2',
3014 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3016 # Change the properties underneath B again, and commit as r4
3017 svntest
.actions
.run_and_verify_svn(None, None, [],
3018 'propset', 'foo', 'foo_val2',
3020 svntest
.actions
.run_and_verify_svn(None, None, [],
3023 svntest
.actions
.run_and_verify_svn(None, None, [],
3024 'propset', 'foo', 'foo_val2',
3026 expected_output
= svntest
.wc
.State(wc_dir
, {
3027 'A/B/E' : Item(verb
='Sending'),
3028 'A/B/E/alpha' : Item(verb
='Sending'),
3029 'A/B/E/beta' : Item(verb
='Sending'),
3031 svntest
.actions
.run_and_verify_commit(wc_dir
,
3032 expected_output
, None,
3034 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3036 # Make local propchanges to E, alpha and beta in the branch.
3037 alpha_path2
= os
.path
.join(wc_dir
, 'A', 'B2', 'E', 'alpha')
3038 beta_path2
= os
.path
.join(wc_dir
, 'A', 'B2', 'E', 'beta')
3039 E_path2
= os
.path
.join(wc_dir
, 'A', 'B2', 'E')
3041 svntest
.actions
.run_and_verify_svn(None, None, [],
3042 'propset', 'foo', 'branchval',
3043 alpha_path2
, beta_path2
)
3044 svntest
.actions
.run_and_verify_svn(None, None, [],
3045 'propset', 'foo', 'branchval',
3048 # Now merge the recent B change to the branch. Because we already
3049 # have local propmods, we should get property conflicts.
3050 B2_path
= os
.path
.join(wc_dir
, 'A', 'B2')
3052 expected_output
= wc
.State(B2_path
, {
3053 'E' : Item(status
=' C'),
3054 'E/alpha' : Item(status
=' C'),
3055 'E/beta' : Item(status
=' C'),
3058 expected_disk
= wc
.State('', {
3059 '' : Item(props
={SVN_PROP_MERGEINFO
: "/A/B:4"}),
3061 'E/alpha' : Item("This is the file 'alpha'.\n"),
3062 'E/beta' : Item("This is the file 'beta'.\n"),
3064 'lambda' : Item("This is the file 'lambda'.\n"),
3066 expected_disk
.tweak('E', 'E/alpha', 'E/beta',
3067 props
={'foo' : 'branchval'}) # local mods still present
3069 expected_status
= wc
.State(B2_path
, {
3070 '' : Item(status
=' M'),
3071 'E' : Item(status
=' C'),
3072 'E/alpha' : Item(status
=' C'),
3073 'E/beta' : Item(status
=' C'),
3074 'F' : Item(status
=' '),
3075 'lambda' : Item(status
=' '),
3077 expected_status
.tweak(wc_rev
=4)
3079 expected_skip
= wc
.State('', { })
3081 # should have 3 'prej' files left behind, describing prop conflicts:
3082 extra_files
= ['alpha.*\.prej', 'beta.*\.prej', 'dir_conflicts.*\.prej']
3084 svntest
.actions
.run_and_verify_merge(B2_path
, '3', '4', B_url
,
3089 None, # expected error string
3090 svntest
.tree
.detect_conflict_files
,
3092 None, None, # no B singleton handler
3096 #----------------------------------------------------------------------
3098 # Test for issue 2035, whereby 'svn merge' wouldn't always mark
3099 # property conflicts when it should.
3101 def property_merge_from_branch(sbox
):
3102 "property merge conflict even without local mods"
3105 wc_dir
= sbox
.wc_dir
3107 # Add a property to a file and a directory, commit as r2.
3108 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
3109 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
3111 svntest
.actions
.run_and_verify_svn(None, None, [],
3112 'propset', 'foo', 'foo_val',
3114 svntest
.actions
.run_and_verify_svn(None, None, [],
3115 'propset', 'foo', 'foo_val',
3118 expected_output
= svntest
.wc
.State(wc_dir
, {
3119 'A/B/E' : Item(verb
='Sending'),
3120 'A/B/E/alpha' : Item(verb
='Sending'),
3122 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3123 expected_status
.tweak('A/B/E', 'A/B/E/alpha', wc_rev
=2, status
=' ')
3124 svntest
.actions
.run_and_verify_commit(wc_dir
,
3125 expected_output
, expected_status
,
3127 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3129 # Copy B to B2 as rev 3 (making a branch)
3130 B_url
= sbox
.repo_url
+ '/A/B'
3131 B2_url
= sbox
.repo_url
+ '/A/B2'
3133 svntest
.actions
.run_and_verify_svn(None, None, [],
3134 'copy', '-m', 'copy B to B2',
3136 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3138 # Change the properties underneath B again, and commit as r4
3139 svntest
.actions
.run_and_verify_svn(None, None, [],
3140 'propset', 'foo', 'foo_val2',
3142 svntest
.actions
.run_and_verify_svn(None, None, [],
3143 'propset', 'foo', 'foo_val2',
3145 expected_output
= svntest
.wc
.State(wc_dir
, {
3146 'A/B/E' : Item(verb
='Sending'),
3147 'A/B/E/alpha' : Item(verb
='Sending'),
3149 svntest
.actions
.run_and_verify_commit(wc_dir
,
3150 expected_output
, None,
3152 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3154 # Make different propchanges changes to the B2 branch and commit as r5.
3155 alpha_path2
= os
.path
.join(wc_dir
, 'A', 'B2', 'E', 'alpha')
3156 E_path2
= os
.path
.join(wc_dir
, 'A', 'B2', 'E')
3158 svntest
.actions
.run_and_verify_svn(None, None, [],
3159 'propset', 'foo', 'branchval',
3161 svntest
.actions
.run_and_verify_svn(None, None, [],
3162 'propset', 'foo', 'branchval',
3164 expected_output
= svntest
.wc
.State(wc_dir
, {
3165 'A/B2/E' : Item(verb
='Sending'),
3166 'A/B2/E/alpha' : Item(verb
='Sending'),
3168 svntest
.actions
.run_and_verify_commit(wc_dir
,
3169 expected_output
, None,
3171 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3173 # Now merge the recent B change to the branch. There are no local
3174 # mods anywhere, but we should still get property conflicts anyway!
3175 B2_path
= os
.path
.join(wc_dir
, 'A', 'B2')
3177 expected_output
= wc
.State(B2_path
, {
3178 'E' : Item(status
=' C'),
3179 'E/alpha' : Item(status
=' C'),
3182 expected_disk
= wc
.State('', {
3183 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:4'}),
3185 'E/alpha' : Item("This is the file 'alpha'.\n"),
3186 'E/beta' : Item("This is the file 'beta'.\n"),
3188 'lambda' : Item("This is the file 'lambda'.\n"),
3190 expected_disk
.tweak('E', 'E/alpha',
3191 props
={'foo' : 'branchval'})
3193 expected_status
= wc
.State(B2_path
, {
3194 '' : Item(status
=' M'),
3195 'E' : Item(status
=' C'),
3196 'E/alpha' : Item(status
=' C'),
3197 'E/beta' : Item(status
=' '),
3198 'F' : Item(status
=' '),
3199 'lambda' : Item(status
=' '),
3201 expected_status
.tweak(wc_rev
=5)
3203 expected_skip
= wc
.State('', { })
3205 # should have 2 'prej' files left behind, describing prop conflicts:
3206 extra_files
= ['alpha.*\.prej', 'dir_conflicts.*\.prej']
3208 svntest
.actions
.run_and_verify_merge(B2_path
, '3', '4', B_url
,
3213 None, # expected error string
3214 svntest
.tree
.detect_conflict_files
,
3216 None, None, # no B singleton handler
3220 #----------------------------------------------------------------------
3222 # Another test for issue 2035, whereby sometimes 'svn merge' marked
3223 # property conflicts when it shouldn't!
3225 def property_merge_undo_redo(sbox
):
3226 "undo, then redo a property merge"
3229 wc_dir
= sbox
.wc_dir
3231 # Add a property to a file, commit as r2.
3232 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
3233 svntest
.actions
.run_and_verify_svn(None, None, [],
3234 'propset', 'foo', 'foo_val',
3237 expected_output
= svntest
.wc
.State(wc_dir
, {
3238 'A/B/E/alpha' : Item(verb
='Sending'),
3240 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3241 expected_status
.tweak('A/B/E/alpha', wc_rev
=2, status
=' ')
3242 svntest
.actions
.run_and_verify_commit(wc_dir
,
3243 expected_output
, expected_status
,
3245 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
3247 # Use 'svn merge' to undo the commit. ('svn merge -r2:1')
3248 # Result should be a single local-prop-mod.
3249 expected_output
= wc
.State(wc_dir
, {'A/B/E/alpha' : Item(status
=' U'), })
3251 expected_disk
= svntest
.main
.greek_state
.copy()
3253 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
3254 expected_status
.tweak('A/B/E/alpha', status
=' M')
3256 expected_skip
= wc
.State('', { })
3258 svntest
.actions
.run_and_verify_merge(wc_dir
, '2', '1',
3264 None, # expected error string
3265 None, None, # no A singleton handler
3266 None, None, # no B singleton handler
3270 # Change mind, re-apply the change ('svn merge -r1:2').
3271 # This should merge cleanly into existing prop-mod, status shows nothing.
3272 expected_output
= wc
.State(wc_dir
, {'A/B/E/alpha' : Item(status
=' C'), })
3274 expected_disk
= svntest
.main
.greek_state
.copy()
3275 expected_disk
.add({'' : Item(props
={SVN_PROP_MERGEINFO
: '/:2'}), })
3276 expected_disk
.add({'A/B/E/alpha.prej'
3277 : Item("Trying to create property 'foo' with value 'foo_val',\n"
3278 + "but it has been locally deleted.\n")})
3280 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
3281 expected_status
.tweak('', status
=' M')
3282 expected_status
.tweak('A/B/E/alpha', status
=' C')
3284 expected_skip
= wc
.State('', { })
3286 # Re-merge r1. We have to use --ignore-ancestry here. Otherwise
3287 # the merge logic will claim we already have this change (because it
3288 # was unable to record the previous undoing merge).
3289 svntest
.actions
.run_and_verify_merge(wc_dir
, '1', '2',
3295 None, # expected error string
3296 None, None, # no A singleton handler
3297 None, None, # no B singleton handler
3300 '--ignore-ancestry')
3304 #----------------------------------------------------------------------
3305 def cherry_pick_text_conflict(sbox
):
3306 "cherry-pick a dependent change, get conflict"
3309 wc_dir
= sbox
.wc_dir
3311 A_path
= os
.path
.join(wc_dir
, 'A')
3312 A_url
= sbox
.repo_url
+ '/A'
3313 mu_path
= os
.path
.join(A_path
, 'mu')
3314 branch_A_url
= sbox
.repo_url
+ '/copy-of-A'
3315 branch_mu_path
= os
.path
.join(wc_dir
, 'copy-of-A', 'mu')
3317 # Create a branch of A.
3318 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp',
3319 A_url
, branch_A_url
,
3320 '-m', "Creating copy-of-A")
3322 # Update to get the branch.
3323 svntest
.actions
.run_and_verify_svn(None, None, [],
3326 # Change mu's text on the branch, producing r3 through r6.
3327 for rev
in range(3, 7):
3328 svntest
.main
.file_append(branch_mu_path
, ("r%d\n" % rev
) * 3)
3329 svntest
.actions
.run_and_verify_svn(None, None, [],
3331 'Add lines to mu in r%d.' % rev
, wc_dir
)
3333 # Mark r5 as merged into trunk, to create disparate revision ranges
3334 # which need to be merged.
3335 svntest
.actions
.run_and_verify_svn(None, [], [],
3336 'merge', '-c5', '--record-only',
3337 branch_A_url
, A_path
)
3340 # Try to merge r4:6 into trunk, without r3. It should fail.
3341 expected_output
= wc
.State(A_path
, {
3342 'mu' : Item(status
='C '),
3344 expected_disk
= wc
.State('', {
3345 'mu' : Item("This is the file 'mu'.\n"
3346 + make_conflict_marker_text("r3\n" * 3, "r4\n" * 3, 4)),
3348 'B/lambda' : Item("This is the file 'lambda'.\n"),
3350 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
3351 'B/E/beta' : Item("This is the file 'beta'.\n"),
3355 'D/gamma' : Item("This is the file 'gamma'.\n"),
3357 'D/H/chi' : Item("This is the file 'chi'.\n"),
3358 'D/H/psi' : Item("This is the file 'psi'.\n"),
3359 'D/H/omega' : Item("This is the file 'omega'.\n"),
3361 'D/G/pi' : Item("This is the file 'pi'.\n"),
3362 'D/G/rho' : Item("This is the file 'rho'.\n"),
3363 'D/G/tau' : Item("This is the file 'tau'.\n"),
3365 expected_status
= wc
.State(A_path
, {
3366 '' : Item(status
=' M'),
3367 'mu' : Item(status
='C '),
3368 'B' : Item(status
=' '),
3369 'B/lambda' : Item(status
=' '),
3370 'B/E' : Item(status
=' '),
3371 'B/E/alpha' : Item(status
=' '),
3372 'B/E/beta' : Item(status
=' '),
3373 'B/F' : Item(status
=' '),
3374 'C' : Item(status
=' '),
3375 'D' : Item(status
=' '),
3376 'D/gamma' : Item(status
=' '),
3377 'D/H' : Item(status
=' '),
3378 'D/H/chi' : Item(status
=' '),
3379 'D/H/psi' : Item(status
=' '),
3380 'D/H/omega' : Item(status
=' '),
3381 'D/G' : Item(status
=' '),
3382 'D/G/pi' : Item(status
=' '),
3383 'D/G/rho' : Item(status
=' '),
3384 'D/G/tau' : Item(status
=' '),
3386 expected_status
.tweak(wc_rev
=2)
3387 expected_skip
= wc
.State('', { })
3388 expected_error
= "conflicts were produced while merging r3:4"
3389 svntest
.actions
.run_and_verify_merge(A_path
, '3', '6', branch_A_url
,
3395 svntest
.tree
.detect_conflict_files
,
3397 "mu\.merge-right\.r4",
3398 "mu\.merge-left\.r3"],
3399 None, None, # no singleton handler
3400 0, # don't check props
3405 # Test for issue 2135
3406 def merge_file_replace(sbox
):
3407 "merge a replacement of a file"
3410 wc_dir
= sbox
.wc_dir
3412 # File scheduled for deletion
3413 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
3414 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', rho_path
)
3416 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3417 expected_status
.tweak('A/D/G/rho', status
='D ')
3418 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
3420 expected_output
= svntest
.wc
.State(wc_dir
, {
3421 'A/D/G/rho': Item(verb
='Deleting'),
3424 expected_status
.remove('A/D/G/rho')
3427 svntest
.actions
.run_and_verify_commit(wc_dir
,
3431 # Create and add a new file.
3432 svntest
.main
.file_write(rho_path
, "new rho\n")
3433 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', rho_path
)
3436 expected_status
.add({
3437 'A/D/G/rho' : Item(status
='A ', wc_rev
='0')
3439 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
3440 expected_output
= svntest
.wc
.State(wc_dir
, {
3441 'A/D/G/rho': Item(verb
='Adding'),
3444 svntest
.actions
.run_and_verify_commit(wc_dir
,
3449 # Update working copy
3450 expected_output
= svntest
.wc
.State(wc_dir
, {})
3451 expected_disk
= svntest
.main
.greek_state
.copy()
3452 expected_disk
.tweak('A/D/G/rho', contents
='new rho\n' )
3453 expected_status
.tweak(wc_rev
='3')
3454 expected_status
.tweak('A/D/G/rho', status
=' ')
3456 svntest
.actions
.run_and_verify_update(wc_dir
,
3461 # merge changes from r3:1
3462 expected_output
= svntest
.wc
.State(wc_dir
, {
3463 'A/D/G/rho': Item(status
='R ')
3465 expected_status
.tweak('A/D/G/rho', status
='R ', copied
='+', wc_rev
='-')
3466 expected_skip
= wc
.State(wc_dir
, { })
3467 expected_disk
.tweak('A/D/G/rho', contents
="This is the file 'rho'.\n")
3468 svntest
.actions
.run_and_verify_merge(wc_dir
, '3', '1',
3475 # Now commit merged wc
3476 expected_output
= svntest
.wc
.State(wc_dir
, {
3477 'A/D/G/rho': Item(verb
='Replacing'),
3479 expected_status
.tweak('A/D/G/rho', status
=' ', copied
=None, wc_rev
='4')
3480 svntest
.actions
.run_and_verify_commit(wc_dir
,
3485 # Test for issue 2522
3486 # Same as merge_file_replace, but without update before merge.
3487 def merge_file_replace_to_mixed_rev_wc(sbox
):
3488 "merge a replacement of a file to mixed rev wc"
3491 wc_dir
= sbox
.wc_dir
3493 # File scheduled for deletion
3494 rho_path
= os
.path
.join(wc_dir
, 'A', 'D', 'G', 'rho')
3495 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm', rho_path
)
3497 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3498 expected_status
.tweak('A/D/G/rho', status
='D ')
3499 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
3501 expected_output
= svntest
.wc
.State(wc_dir
, {
3502 'A/D/G/rho': Item(verb
='Deleting'),
3505 expected_status
.remove('A/D/G/rho')
3508 svntest
.actions
.run_and_verify_commit(wc_dir
,
3513 # Update working copy
3514 expected_disk
= svntest
.main
.greek_state
.copy()
3515 expected_disk
.remove('A/D/G/rho' )
3516 expected_output
= svntest
.wc
.State(wc_dir
, {})
3517 expected_status
.tweak(wc_rev
='2')
3519 svntest
.actions
.run_and_verify_update(wc_dir
,
3524 # Create and add a new file.
3525 svntest
.main
.file_write(rho_path
, "new rho\n")
3526 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', rho_path
)
3529 expected_status
.add({
3530 'A/D/G/rho' : Item(status
='A ', wc_rev
='0')
3532 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
3533 expected_output
= svntest
.wc
.State(wc_dir
, {
3534 'A/D/G/rho': Item(verb
='Adding'),
3537 expected_disk
.add({'A/D/G/rho' : Item(contents
='new rho\n')} )
3538 expected_status
.tweak(wc_rev
='2')
3539 expected_status
.tweak('A/D/G/rho', status
=' ', wc_rev
='3')
3541 svntest
.actions
.run_and_verify_commit(wc_dir
,
3547 # merge changes from r3:1
3548 expected_output
= svntest
.wc
.State(wc_dir
, {
3549 'A/D/G/rho': Item(status
='R ')
3551 expected_status
.tweak('A/D/G/rho', status
='R ', copied
='+', wc_rev
='-')
3552 expected_skip
= wc
.State(wc_dir
, { })
3553 expected_disk
.tweak('A/D/G/rho', contents
="This is the file 'rho'.\n")
3554 svntest
.actions
.run_and_verify_merge(wc_dir
, '3', '1',
3561 # At this point WC is broken, because file rho has invalid revision
3563 expected_output
= svntest
.wc
.State(wc_dir
, {})
3564 expected_status
.tweak(wc_rev
='3')
3565 expected_status
.tweak('A/D/G/rho', status
='R ', copied
='+', wc_rev
='-')
3566 svntest
.actions
.run_and_verify_update(wc_dir
,
3571 # Now commit merged wc
3572 expected_output
= svntest
.wc
.State(wc_dir
, {
3573 'A/D/G/rho': Item(verb
='Replacing'),
3575 expected_status
.tweak('A/D/G/rho', status
=' ', copied
=None, wc_rev
='4')
3576 svntest
.actions
.run_and_verify_commit(wc_dir
,
3582 # use -x -w option for ignoring whitespace during merge
3583 def merge_ignore_whitespace(sbox
):
3584 "ignore whitespace when merging"
3587 wc_dir
= sbox
.wc_dir
3589 # commit base version of iota
3591 file_path
= os
.path
.join(wc_dir
, file_name
)
3592 file_url
= sbox
.repo_url
+ '/iota'
3594 svntest
.main
.file_write(file_path
,
3598 expected_output
= svntest
.wc
.State(wc_dir
, {
3599 'iota' : Item(verb
='Sending'),
3601 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3604 # change the file, mostly whitespace changes + an extra line
3605 svntest
.main
.file_write(file_path
, "A a\nBb \n Cc\nNew line in iota\n")
3606 expected_output
= wc
.State(wc_dir
, { file_name
: Item(verb
='Sending'), })
3607 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3608 expected_status
.tweak(file_name
, wc_rev
=3)
3609 svntest
.actions
.run_and_verify_commit(wc_dir
,
3615 # Backdate iota to revision 2, so we can merge in the rev 3 changes.
3616 svntest
.actions
.run_and_verify_svn(None, None, [],
3617 'up', '-r', '2', file_path
)
3618 # Make some local whitespace changes, these should not conflict
3619 # with the remote whitespace changes as both will be ignored.
3620 svntest
.main
.file_write(file_path
, " Aa\nB b\nC c\n")
3622 # Lines changed only by whitespaces - both in local or remote -
3624 expected_output
= wc
.State(sbox
.wc_dir
, { file_name
: Item(status
='G ') })
3625 expected_disk
= svntest
.main
.greek_state
.copy()
3626 expected_disk
.tweak(file_name
,
3630 "New line in iota\n")
3631 expected_status
= svntest
.actions
.get_virginal_state(sbox
.wc_dir
, 1)
3632 expected_status
.tweak('', status
=' M', wc_rev
=1)
3633 expected_status
.tweak(file_name
, status
='M ', wc_rev
=2)
3634 expected_skip
= wc
.State('', { })
3636 svntest
.actions
.run_and_verify_merge(sbox
.wc_dir
, '2', '3',
3642 None, None, None, None, None,
3646 # use -x --ignore-eol-style option for ignoring eolstyle during merge
3647 def merge_ignore_eolstyle(sbox
):
3648 "ignore eolstyle when merging"
3651 wc_dir
= sbox
.wc_dir
3653 # commit base version of iota
3655 file_path
= os
.path
.join(wc_dir
, file_name
)
3656 file_url
= sbox
.repo_url
+ '/iota'
3658 svntest
.main
.file_write(file_path
,
3663 expected_output
= svntest
.wc
.State(wc_dir
, {
3664 'iota' : Item(verb
='Sending'),
3666 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3669 # change the file, mostly eol changes + an extra line
3670 svntest
.main
.file_write(file_path
,
3674 "New line in iota\n",
3676 expected_output
= wc
.State(wc_dir
, { file_name
: Item(verb
='Sending'), })
3677 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3678 expected_status
.tweak(file_name
, wc_rev
=3)
3679 svntest
.actions
.run_and_verify_commit(wc_dir
,
3685 # Backdate iota to revision 2, so we can merge in the rev 3 changes.
3686 svntest
.actions
.run_and_verify_svn(None, None, [],
3687 'up', '-r', '2', file_path
)
3688 # Make some local eol changes, these should not conflict
3689 # with the remote eol changes as both will be ignored.
3690 svntest
.main
.file_write(file_path
,
3696 # Lines changed only by eolstyle - both in local or remote -
3698 expected_output
= wc
.State(sbox
.wc_dir
, { file_name
: Item(status
='G ') })
3699 expected_disk
= svntest
.main
.greek_state
.copy()
3700 expected_disk
.tweak(file_name
,
3704 "New line in iota\n")
3705 expected_status
= svntest
.actions
.get_virginal_state(sbox
.wc_dir
, 1)
3706 expected_status
.tweak('', status
=' M')
3707 expected_status
.tweak(file_name
, status
='M ', wc_rev
=2)
3708 expected_skip
= wc
.State('', { })
3710 svntest
.actions
.run_and_verify_merge(sbox
.wc_dir
, '2', '3',
3716 None, None, None, None, None,
3718 '-x', '--ignore-eol-style')
3720 #----------------------------------------------------------------------
3722 def merge_add_over_versioned_file_conflicts(sbox
):
3723 "conflict from merge of add over versioned file"
3726 wc_dir
= sbox
.wc_dir
3728 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
3729 alpha_path
= os
.path
.join(E_path
, 'alpha')
3730 new_alpha_path
= os
.path
.join(wc_dir
, 'A', 'C', 'alpha')
3732 # Create a new "alpha" file, with enough differences to cause a conflict.
3733 ### TODO: Leverage inject_conflict_into_wc() here.
3734 svntest
.main
.file_write(new_alpha_path
, 'new alpha content\n')
3736 # Add and commit the new "alpha" file, creating revision 2.
3737 svntest
.main
.run_svn(None, "add", new_alpha_path
)
3739 expected_output
= svntest
.wc
.State(wc_dir
, {
3740 'A/C/alpha' : Item(verb
='Adding'),
3742 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
3743 expected_status
.add({
3744 'A/C/alpha' : Item(status
=' ', wc_rev
=2),
3746 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3747 expected_status
, None,
3750 # Search for the comment entitled "The Merge Kluge" elsewhere in
3751 # this file, to understand why we shorten and chdir() below.
3752 short_E_path
= shorten_path_kludge(E_path
)
3754 # Merge changes from r1:2 into our pre-existing "alpha" file,
3755 # causing a conflict.
3756 expected_output
= wc
.State(short_E_path
, {
3757 'alpha' : Item(status
='C '),
3759 expected_disk
= wc
.State('', {
3760 'alpha' : Item(""), # state filled in below
3761 'beta' : Item("This is the file 'beta'.\n"),
3763 expected_status
= wc
.State(short_E_path
, {
3764 '' : Item(status
=' M', wc_rev
=1),
3765 'alpha' : Item(status
='C ', wc_rev
=1),
3766 'beta' : Item(status
=' ', wc_rev
=1),
3769 inject_conflict_into_expected_state('alpha', expected_disk
, expected_status
,
3770 "This is the file 'alpha'.\n",
3771 "new alpha content\n", 2)
3772 expected_skip
= wc
.State(short_E_path
, { })
3774 os
.chdir(svntest
.main
.work_dir
)
3775 svntest
.actions
.run_and_verify_merge(short_E_path
, '1', '2',
3783 svntest
.tree
.detect_conflict_files
,
3785 "alpha\.merge-right\.r2",
3786 "alpha\.merge-left\.r0"])
3788 #----------------------------------------------------------------------
3789 # eol-style handling during merge with conflicts, scenario 1:
3790 # when a merge creates a conflict on a file, make sure the file and files
3791 # r<left>, r<right> and .mine are in the eol-style defined for that file.
3793 # This test for 'svn update' can be found in update_tests.py as
3794 # conflict_markers_matching_eol.
3795 def merge_conflict_markers_matching_eol(sbox
):
3796 "conflict markers should match the file's eol style"
3799 wc_dir
= sbox
.wc_dir
3802 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
3809 # Checkout a second working copy
3810 wc_backup
= sbox
.add_wc_path('backup')
3811 svntest
.actions
.run_and_verify_svn(None, None, [], 'checkout',
3812 sbox
.repo_url
, wc_backup
)
3814 # set starting revision
3817 expected_disk
= svntest
.main
.greek_state
.copy()
3818 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, cur_rev
)
3819 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
,
3822 path_backup
= os
.path
.join(wc_backup
, 'A', 'mu')
3824 # do the test for each eol-style
3825 for eol
, eolchar
in zip(['CRLF', 'CR', 'native', 'LF'],
3826 [crlf
, '\015', '\n', '\012']):
3827 # rewrite file mu and set the eol-style property.
3828 svntest
.main
.file_write(mu_path
, "This is the file 'mu'."+ eolchar
, 'wb')
3829 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', eol
, mu_path
)
3832 'A/mu' : Item("This is the file 'mu'." + eolchar
)
3834 expected_output
= svntest
.wc
.State(wc_dir
, {
3835 'A/mu' : Item(verb
='Sending'),
3837 expected_status
.tweak(wc_rev
= cur_rev
)
3838 expected_status
.add({
3839 'A/mu' : Item(status
=' ', wc_rev
= cur_rev
+ 1),
3842 # Commit the original change and note the 'base' revision number
3843 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
3844 expected_status
, None,
3846 cur_rev
= cur_rev
+ 1
3849 svntest
.main
.run_svn(None, 'update', wc_backup
)
3851 # Make a local mod to mu
3852 svntest
.main
.file_append(mu_path
,
3853 'Original appended text for mu' + eolchar
)
3855 # Commit the original change and note the 'theirs' revision number
3856 svntest
.main
.run_svn(None, 'commit', '-m', 'test log', wc_dir
)
3857 cur_rev
= cur_rev
+ 1
3858 theirs_rev
= cur_rev
3860 # Make a local mod to mu, will conflict with the previous change
3861 svntest
.main
.file_append(path_backup
,
3862 'Conflicting appended text for mu' + eolchar
)
3864 # Create expected output tree for an update of the wc_backup.
3865 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
3866 'A/mu' : Item(status
='C '),
3869 # Create expected disk tree for the update.
3870 expected_backup_disk
= expected_disk
.copy()
3872 # verify content of resulting conflicted file
3873 expected_backup_disk
.add({
3874 'A/mu' : Item(contents
= "This is the file 'mu'." + eolchar
+
3875 "<<<<<<< .working" + eolchar
+
3876 "Conflicting appended text for mu" + eolchar
+
3877 "=======" + eolchar
+
3878 "Original appended text for mu" + eolchar
+
3879 ">>>>>>> .merge-right.r" + str(cur_rev
) + eolchar
),
3881 # verify content of base(left) file
3882 expected_backup_disk
.add({
3883 'A/mu.merge-left.r' + str(base_rev
) :
3884 Item(contents
= "This is the file 'mu'." + eolchar
)
3886 # verify content of theirs(right) file
3887 expected_backup_disk
.add({
3888 'A/mu.merge-right.r' + str(theirs_rev
) :
3889 Item(contents
= "This is the file 'mu'." + eolchar
+
3890 "Original appended text for mu" + eolchar
)
3892 # verify content of mine file
3893 expected_backup_disk
.add({
3894 'A/mu.working' : Item(contents
= "This is the file 'mu'." +
3896 "Conflicting appended text for mu" + eolchar
)
3899 # Create expected status tree for the update.
3900 expected_backup_status
.add({
3901 'A/mu' : Item(status
=' ', wc_rev
=cur_rev
),
3903 expected_backup_status
.tweak('A/mu', status
='C ')
3904 expected_backup_status
.tweak(wc_rev
= cur_rev
- 1)
3905 expected_backup_status
.tweak('', status
= ' M')
3907 expected_backup_skip
= wc
.State('', { })
3909 svntest
.actions
.run_and_verify_merge(wc_backup
, cur_rev
- 1, cur_rev
,
3911 expected_backup_output
,
3912 expected_backup_disk
,
3913 expected_backup_status
,
3914 expected_backup_skip
)
3916 # cleanup for next run
3917 svntest
.main
.run_svn(None, 'revert', '-R', wc_backup
)
3918 svntest
.main
.run_svn(None, 'update', wc_dir
)
3920 # eol-style handling during merge, scenario 2:
3921 # if part of that merge is a propchange (add, change, delete) of
3922 # svn:eol-style, make sure the correct eol-style is applied before
3923 # calculating the merge (and conflicts if any)
3925 # This test for 'svn update' can be found in update_tests.py as
3926 # update_eolstyle_handling.
3927 def merge_eolstyle_handling(sbox
):
3928 "handle eol-style propchange during merge"
3931 wc_dir
= sbox
.wc_dir
3933 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
3940 # Checkout a second working copy
3941 wc_backup
= sbox
.add_wc_path('backup')
3942 svntest
.actions
.run_and_verify_svn(None, None, [], 'checkout',
3943 sbox
.repo_url
, wc_backup
)
3944 path_backup
= os
.path
.join(wc_backup
, 'A', 'mu')
3946 # Test 1: add the eol-style property and commit, change mu in the second
3947 # working copy and merge the last revision; there should be no conflict!
3948 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', "CRLF", mu_path
)
3949 svntest
.main
.run_svn(None,
3950 'commit', '-m', 'set eol-style property', wc_dir
)
3952 svntest
.main
.file_append_binary(path_backup
, 'Added new line of text.\012')
3954 expected_backup_disk
= svntest
.main
.greek_state
.copy()
3955 expected_backup_disk
.tweak(
3956 'A/mu', contents
= "This is the file 'mu'." + crlf
+
3957 "Added new line of text." + crlf
)
3958 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
3959 'A/mu' : Item(status
='GU'),
3961 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
, 1)
3962 expected_backup_status
.tweak('', status
=' M')
3963 expected_backup_status
.tweak('A/mu', status
='MM')
3965 expected_backup_skip
= wc
.State('', { })
3967 svntest
.actions
.run_and_verify_merge(wc_backup
, '1', '2', sbox
.repo_url
,
3968 expected_backup_output
,
3969 expected_backup_disk
,
3970 expected_backup_status
,
3971 expected_backup_skip
)
3973 # Test 2: now change the eol-style property to another value and commit,
3974 # merge this revision in the still changed mu in the second working copy;
3975 # there should be a property conflict! (Since this will overwrite a
3976 # local change to a versioned resource.)
3977 svntest
.main
.run_svn(None, 'propset', 'svn:eol-style', "CR", mu_path
)
3978 svntest
.main
.run_svn(None,
3979 'commit', '-m', 'set eol-style property', wc_dir
)
3981 expected_backup_disk
= svntest
.main
.greek_state
.copy()
3982 expected_backup_disk
.add({
3983 'A/mu' : Item(contents
= "This is the file 'mu'." + crlf
+
3984 "Added new line of text." + crlf
)
3986 expected_backup_disk
.add({
3987 'A/mu.prej' : Item("Trying to change property 'svn:eol-style' from 'CRLF'"
3988 + " to 'CR',\nbut property has been locally added with"
3989 + " value 'CRLF'\n")})
3990 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
3991 'A/mu' : Item(status
='GC'),
3993 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
, 1)
3994 expected_backup_status
.tweak('', status
=' M')
3995 expected_backup_status
.tweak('A/mu', status
='MC')
3996 svntest
.actions
.run_and_verify_merge(wc_backup
, '2', '3', sbox
.repo_url
,
3997 expected_backup_output
,
3998 expected_backup_disk
,
3999 expected_backup_status
,
4000 expected_backup_skip
)
4002 # Test 3: now delete the eol-style property and commit, merge this revision
4003 # in the still changed mu in the second working copy; there should be no
4004 # conflict! (after marking mu resolved from Test 2)
4005 # EOL of mu should be unchanged (=CRLF).
4006 svntest
.main
.run_svn(None, 'propdel', 'svn:eol-style', mu_path
)
4007 svntest
.main
.run_svn(None,
4008 'commit', '-m', 'del eol-style property', wc_dir
)
4010 expected_backup_disk
= svntest
.main
.greek_state
.copy()
4011 expected_backup_disk
.add({
4012 'A/mu' : Item(contents
= "This is the file 'mu'." + crlf
+
4013 "Added new line of text." + crlf
)
4015 expected_backup_output
= svntest
.wc
.State(wc_backup
, {
4016 'A/mu' : Item(status
=' G'),
4018 expected_backup_status
= svntest
.actions
.get_virginal_state(wc_backup
, 1)
4019 expected_backup_status
.tweak('', status
=' M')
4020 expected_backup_status
.tweak('A/mu', status
='M ')
4021 svntest
.main
.run_svn(None, 'resolved', path_backup
)
4022 svntest
.actions
.run_and_verify_merge(wc_backup
, '3', '4', sbox
.repo_url
,
4023 expected_backup_output
,
4024 expected_backup_disk
,
4025 expected_backup_status
,
4026 expected_backup_skip
)
4028 def create_deep_trees(wc_dir
):
4029 """Create A/B/F/E by moving A/B/E to A/B/F/E.
4030 Copy A/B/F/E to A/B/F/E1.
4031 Copy A/B to A/copy-of-B, and return the expected status.
4032 At the end of this function WC would be at r4"""
4034 A_path
= os
.path
.join(wc_dir
, 'A')
4035 A_B_path
= os
.path
.join(A_path
, 'B')
4036 A_B_E_path
= os
.path
.join(A_B_path
, 'E')
4037 A_B_F_path
= os
.path
.join(A_B_path
, 'F')
4038 A_B_F_E_path
= os
.path
.join(A_B_F_path
, 'E')
4039 A_B_F_E1_path
= os
.path
.join(A_B_F_path
, 'E1')
4041 # Deepen the directory structure we're working with by moving E to
4042 # underneath F and committing, creating revision 2.
4043 svntest
.main
.run_svn(None, 'mv', A_B_E_path
, A_B_F_path
)
4045 # A/B/F/E now has empty mergeinfo
4047 expected_output
= wc
.State(wc_dir
, {
4048 'A/B/E' : Item(verb
='Deleting'),
4049 'A/B/F/E' : Item(verb
='Adding')
4051 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
4052 expected_status
.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
4053 expected_status
.add({
4054 'A/B/F/E' : Item(status
=' ', wc_rev
=2),
4055 'A/B/F/E/alpha' : Item(status
=' ', wc_rev
=2),
4056 'A/B/F/E/beta' : Item(status
=' ', wc_rev
=2),
4058 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4059 expected_status
, None,
4062 svntest
.main
.run_svn(None, 'cp', A_B_F_E_path
, A_B_F_E1_path
)
4064 # A/B/F/E1 now has empty mergeinfo
4066 expected_output
= wc
.State(wc_dir
, {
4067 'A/B/F/E1' : Item(verb
='Adding')
4069 expected_status
.add({
4070 'A/B/F/E1' : Item(status
=' ', wc_rev
=3),
4071 'A/B/F/E1/alpha' : Item(status
=' ', wc_rev
=3),
4072 'A/B/F/E1/beta' : Item(status
=' ', wc_rev
=3),
4074 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4075 expected_status
, None,
4078 # Bring the entire WC up to date with rev 3.
4079 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
4080 expected_status
.tweak(wc_rev
=3)
4082 # Copy B and commit, creating revision 4.
4083 copy_of_B_path
= os
.path
.join(A_path
, 'copy-of-B')
4084 svntest
.main
.run_svn(None, "cp", A_B_path
, copy_of_B_path
)
4086 # A/copy-of-B, A/copy-of-B/F/E, and A/copy-of-B/F/E1 now have empty mergeinfo
4088 expected_output
= svntest
.wc
.State(wc_dir
, {
4089 'A/copy-of-B' : Item(verb
='Adding'),
4091 expected_status
.add({
4092 'A/copy-of-B' : Item(status
=' ', wc_rev
=4),
4093 'A/copy-of-B/F' : Item(status
=' ', wc_rev
=4),
4094 'A/copy-of-B/F/E' : Item(status
=' ', wc_rev
=4),
4095 'A/copy-of-B/F/E/alpha' : Item(status
=' ', wc_rev
=4),
4096 'A/copy-of-B/F/E/beta' : Item(status
=' ', wc_rev
=4),
4097 'A/copy-of-B/F/E1' : Item(status
=' ', wc_rev
=4),
4098 'A/copy-of-B/F/E1/alpha' : Item(status
=' ', wc_rev
=4),
4099 'A/copy-of-B/F/E1/beta' : Item(status
=' ', wc_rev
=4),
4100 'A/copy-of-B/lambda' : Item(status
=' ', wc_rev
=4),
4102 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4103 expected_status
, None,
4106 # pre-update, empty mergeinfo can be found on:
4114 expected_disk
= svntest
.main
.greek_state
.copy()
4115 expected_disk
.remove('A/B/E', 'A/B/E/alpha', 'A/B/E/beta')
4117 'A/B/F/E' : Item(props
={SVN_PROP_MERGEINFO
: ''}),
4118 'A/B/F/E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
4119 'A/B/F/E/beta' : Item(contents
="This is the file 'beta'.\n"),
4120 'A/B/F/E1' : Item(props
={SVN_PROP_MERGEINFO
: ''}),
4121 'A/B/F/E1/alpha' : Item(contents
="This is the file 'alpha'.\n"),
4122 'A/B/F/E1/beta' : Item(contents
="This is the file 'beta'.\n"),
4123 'A/copy-of-B' : Item(props
={SVN_PROP_MERGEINFO
: ''}),
4124 'A/copy-of-B/F' : Item(props
={}),
4125 'A/copy-of-B/F/E' : Item(props
={SVN_PROP_MERGEINFO
: ''}),
4126 'A/copy-of-B/F/E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
4127 'A/copy-of-B/F/E/beta' : Item(contents
="This is the file 'beta'.\n"),
4128 'A/copy-of-B/F/E1' : Item(props
={SVN_PROP_MERGEINFO
: ''}),
4129 'A/copy-of-B/F/E1/alpha' : Item(contents
="This is the file 'alpha'.\n"),
4130 'A/copy-of-B/F/E1/beta' : Item(contents
="This is the file 'beta'.\n"),
4131 'A/copy-of-B/lambda' : Item(contents
="This is the file 'lambda'.\n"),
4133 svntest
.actions
.verify_disk(wc_dir
, expected_disk
,
4134 None, None, None, None, 1)
4136 # Bring the entire WC up to date with rev 4.
4137 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
4139 svntest
.actions
.verify_disk(wc_dir
, expected_disk
,
4140 None, None, None, None, 1)
4142 expected_status
.tweak(wc_rev
=4)
4143 expected_disk
.tweak('A/copy-of-B/F/E', 'A/copy-of-B/F/E1', status
=' M')
4144 return expected_status
4146 def avoid_repeated_merge_using_inherited_merge_info(sbox
):
4147 "use inherited mergeinfo to avoid repeated merge"
4150 wc_dir
= sbox
.wc_dir
4152 A_path
= os
.path
.join(wc_dir
, 'A')
4153 A_B_path
= os
.path
.join(A_path
, 'B')
4154 A_B_E_path
= os
.path
.join(A_B_path
, 'E')
4155 A_B_F_path
= os
.path
.join(A_B_path
, 'F')
4156 copy_of_B_path
= os
.path
.join(A_path
, 'copy-of-B')
4158 # Create a deeper directory structure.
4159 expected_status
= create_deep_trees(wc_dir
)
4161 # Edit alpha and commit it, creating revision 5.
4162 alpha_path
= os
.path
.join(A_B_F_path
, 'E', 'alpha')
4163 new_content_for_alpha
= 'new content to alpha\n'
4164 svntest
.main
.file_write(alpha_path
, new_content_for_alpha
)
4165 expected_output
= svntest
.wc
.State(wc_dir
, {
4166 'A/B/F/E/alpha' : Item(verb
='Sending'),
4168 expected_status
.tweak('A/B/F/E/alpha', wc_rev
=5)
4169 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4170 expected_status
, None,
4173 # Search for the comment entitled "The Merge Kluge" elsewhere in
4174 # this file, to understand why we shorten and chdir() below.
4175 short_copy_of_B_path
= shorten_path_kludge(copy_of_B_path
)
4177 # Bring the entire WC up to date with rev 5.
4178 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
4180 # Merge changes from rev 5 of B (to alpha) into copy_of_B.
4181 # A_COPY/copy_of_B/F/E and A_COPY/copy_of_B/F/E1 both exist in the merge
4182 # source at r5, so their empty mergeinfo should be updted with r5, which
4183 # then should elide to A_COPY/copy_of_B leaving no mergeinfo on either.
4184 expected_output
= wc
.State(short_copy_of_B_path
, {
4185 'F/E/alpha' : Item(status
='U '),
4187 expected_status
= wc
.State(short_copy_of_B_path
, {
4188 '' : Item(status
=' M', wc_rev
=5),
4189 'F/E' : Item(status
=' M', wc_rev
=5),
4190 'F/E/alpha' : Item(status
='M ', wc_rev
=5),
4191 'F/E/beta' : Item(status
=' ', wc_rev
=5),
4192 'F/E1' : Item(status
=' M', wc_rev
=5),
4193 'F/E1/alpha' : Item(status
=' ', wc_rev
=5),
4194 'F/E1/beta' : Item(status
=' ', wc_rev
=5),
4195 'lambda' : Item(status
=' ', wc_rev
=5),
4196 'F' : Item(status
=' ', wc_rev
=5),
4198 expected_disk
= wc
.State('', {
4199 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:5'}),
4201 'F/E/alpha' : Item(new_content_for_alpha
),
4202 'F/E/beta' : Item("This is the file 'beta'.\n"),
4204 'F/E1/alpha' : Item("This is the file 'alpha'.\n"),
4205 'F/E1/beta' : Item("This is the file 'beta'.\n"),
4207 'lambda' : Item("This is the file 'lambda'.\n")
4209 expected_skip
= wc
.State(short_copy_of_B_path
, { })
4210 saved_cwd
= os
.getcwd()
4212 os
.chdir(svntest
.main
.work_dir
)
4213 svntest
.actions
.run_and_verify_merge(short_copy_of_B_path
, '4', '5',
4227 # Commit the result of the merge, creating revision 6.
4228 expected_output
= svntest
.wc
.State(copy_of_B_path
, {
4229 '' : Item(verb
='Sending'),
4230 'F/E' : Item(verb
='Sending'),
4231 'F/E/alpha' : Item(verb
='Sending'),
4232 'F/E1' : Item(verb
='Sending'),
4234 svntest
.actions
.run_and_verify_commit(short_copy_of_B_path
, expected_output
,
4237 # Update the WC to bring /A/copy_of_B/F from rev 4 to rev 6.
4238 # Without this update, a subsequent merge will not find any merge
4239 # info for /A/copy_of_B/F -- nor its parent dir in the repos -- at
4240 # rev 4. Mergeinfo wasn't introduced until rev 6.
4241 copy_of_B_F_E_path
= os
.path
.join(copy_of_B_path
, 'F', 'E')
4242 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
4244 # Search for the comment entitled "The Merge Kluge" elsewhere in
4245 # this file, to understand why we shorten and chdir() below.
4246 short_copy_of_B_F_E_path
= shorten_path_kludge(copy_of_B_F_E_path
)
4248 # Attempt to re-merge changes to alpha from rev 4. Use the merge
4249 # info inherited from the grandparent (copy-of-B) of our merge
4250 # target (/A/copy-of-B/F/E) to avoid a repeated merge.
4251 expected_status
= wc
.State(short_copy_of_B_F_E_path
, {
4252 '' : Item(status
=' ', wc_rev
=6),
4253 'alpha' : Item(status
=' ', wc_rev
=6),
4254 'beta' : Item(status
=' ', wc_rev
=6),
4256 os
.chdir(svntest
.main
.work_dir
)
4257 svntest
.actions
.run_and_verify_svn(None, [], [], 'merge', '-r4:5',
4258 sbox
.repo_url
+ '/A/B/F/E',
4259 short_copy_of_B_F_E_path
)
4260 svntest
.actions
.run_and_verify_status(short_copy_of_B_F_E_path
,
4264 def avoid_repeated_merge_on_subtree_with_merge_info(sbox
):
4265 "use subtree's mergeinfo to avoid repeated merge"
4266 # Create deep trees A/B/F/E and A/B/F/E1 and copy A/B to A/copy-of-B
4267 # with the help of 'create_deep_trees'
4268 # As /A/copy-of-B/F/E1 is not a child of /A/copy-of-B/F/E,
4269 # set_path should not be called on /A/copy-of-B/F/E1 while
4270 # doing a implicit subtree merge on /A/copy-of-B/F/E.
4272 wc_dir
= sbox
.wc_dir
4274 A_path
= os
.path
.join(wc_dir
, 'A')
4275 A_B_path
= os
.path
.join(A_path
, 'B')
4276 A_B_E_path
= os
.path
.join(A_B_path
, 'E')
4277 A_B_F_path
= os
.path
.join(A_B_path
, 'F')
4278 A_B_F_E_path
= os
.path
.join(A_B_F_path
, 'E')
4279 copy_of_B_path
= os
.path
.join(A_path
, 'copy-of-B')
4281 # Create a deeper directory structure.
4282 expected_status
= create_deep_trees(wc_dir
)
4284 # Edit alpha and commit it, creating revision 5.
4285 alpha_path
= os
.path
.join(A_B_F_E_path
, 'alpha')
4286 new_content_for_alpha1
= 'new content to alpha\n'
4287 svntest
.main
.file_write(alpha_path
, new_content_for_alpha1
)
4289 expected_output
= svntest
.wc
.State(wc_dir
, {
4290 'A/B/F/E/alpha' : Item(verb
='Sending'),
4292 expected_status
.tweak('A/B/F/E/alpha', wc_rev
=5)
4293 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4294 expected_status
, None, wc_dir
)
4296 for path_and_mergeinfo
in (('E', '/A/B/F/E:5'),
4297 ('E1', '/A/B/F/E:5')):
4298 path_name
= os
.path
.join(copy_of_B_path
, 'F', path_and_mergeinfo
[0])
4299 # Search for the comment entitled "The Merge Kluge" elsewhere in
4300 # this file, to understand why we shorten and chdir() below.
4301 short_path_name
= shorten_path_kludge(path_name
)
4303 # Merge r5 to path_name.
4304 expected_output
= wc
.State(short_path_name
, {
4305 'alpha' : Item(status
='U '),
4307 expected_status
= wc
.State(short_path_name
, {
4308 '' : Item(status
=' M', wc_rev
=4),
4309 'alpha' : Item(status
='M ', wc_rev
=4),
4310 'beta' : Item(status
=' ', wc_rev
=4),
4312 expected_disk
= wc
.State('', {
4313 '' : Item(props
={SVN_PROP_MERGEINFO
: path_and_mergeinfo
[1]}),
4314 'alpha' : Item(new_content_for_alpha1
),
4315 'beta' : Item("This is the file 'beta'.\n"),
4317 expected_skip
= wc
.State(short_path_name
, { })
4318 saved_cwd
= os
.getcwd()
4320 os
.chdir(svntest
.main
.work_dir
)
4321 svntest
.actions
.run_and_verify_merge(short_path_name
, '4', '5',
4322 sbox
.repo_url
+ '/A/B/F/E',
4334 # Commit the result of the merge, creating new revision.
4335 expected_output
= svntest
.wc
.State(path_name
, {
4336 '' : Item(verb
='Sending'),
4337 'alpha' : Item(verb
='Sending'),
4339 svntest
.actions
.run_and_verify_commit(short_path_name
,
4340 expected_output
, None, None, wc_dir
)
4342 # Edit A/B/F/E/alpha and commit it, creating revision 8.
4343 new_content_for_alpha
= 'new content to alpha\none more line\n'
4344 svntest
.main
.file_write(alpha_path
, new_content_for_alpha
)
4346 expected_output
= svntest
.wc
.State(A_B_F_E_path
, {
4347 'alpha' : Item(verb
='Sending'),
4349 expected_status
= wc
.State(A_B_F_E_path
, {
4350 '' : Item(status
=' ', wc_rev
=4),
4351 'alpha' : Item(status
=' ', wc_rev
=8),
4352 'beta' : Item(status
=' ', wc_rev
=4),
4354 svntest
.actions
.run_and_verify_commit(A_B_F_E_path
, expected_output
,
4355 expected_status
, None, wc_dir
)
4357 # Search for the comment entitled "The Merge Kluge" elsewhere in
4358 # this file, to understand why we shorten and chdir() below.
4359 short_copy_of_B_path
= shorten_path_kludge(copy_of_B_path
)
4361 # Update the WC to bring /A/copy_of_B to rev 8.
4362 # Without this update expected_status tree would be cumbersome to
4364 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
4366 # Merge changes from rev 4:8 of A/B into A/copy_of_B. A/copy_of_B/F/E1
4367 # has explicit mergeinfo and exists at r4 in the merge source, so it
4368 # should be treated as a subtree with intersecting mergeinfo and its
4369 # mergeinfo updated.
4370 expected_output
= wc
.State(short_copy_of_B_path
, {
4371 'F/E/alpha' : Item(status
='U ')
4373 expected_status
= wc
.State(short_copy_of_B_path
, {
4374 # When we merge multiple sub-targets, we record mergeinfo on each
4376 '' : Item(status
=' M', wc_rev
=8),
4377 'F/E' : Item(status
=' M', wc_rev
=8),
4378 'F/E/alpha' : Item(status
='M ', wc_rev
=8),
4379 'F/E/beta' : Item(status
=' ', wc_rev
=8),
4380 'F/E1' : Item(status
=' M', wc_rev
=8),
4381 'F/E1/alpha' : Item(status
=' ', wc_rev
=8),
4382 'F/E1/beta' : Item(status
=' ', wc_rev
=8),
4383 'lambda' : Item(status
=' ', wc_rev
=8),
4384 'F' : Item(status
=' ', wc_rev
=8)
4386 expected_disk
= wc
.State('', {
4387 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:5-8'}),
4388 'F/E' : Item(props
={}), # elision!
4389 'F/E/alpha' : Item(new_content_for_alpha
),
4390 'F/E/beta' : Item("This is the file 'beta'.\n"),
4392 'F/E1' : Item(props
={SVN_PROP_MERGEINFO
:
4393 '/A/B/F/E:5\n/A/B/F/E1:5-8\n'}),
4394 'F/E1/alpha' : Item(new_content_for_alpha1
),
4395 'F/E1/beta' : Item("This is the file 'beta'.\n"),
4396 'lambda' : Item("This is the file 'lambda'.\n")
4398 expected_skip
= wc
.State(short_copy_of_B_path
, { })
4399 os
.chdir(svntest
.main
.work_dir
)
4400 svntest
.actions
.run_and_verify_merge(short_copy_of_B_path
, '4', '8',
4401 sbox
.repo_url
+ '/A/B',
4412 def tweak_src_then_merge_to_dest(sbox
, src_path
, dst_path
,
4413 canon_src_path
, contents
, cur_rev
):
4414 """Edit src and commit it. This results in new_rev.
4415 Merge new_rev to dst_path. Return new_rev."""
4417 wc_dir
= sbox
.wc_dir
4418 new_rev
= cur_rev
+ 1
4419 svntest
.main
.file_write(src_path
, contents
)
4421 expected_output
= svntest
.wc
.State(src_path
, {
4422 '': Item(verb
='Sending'),
4425 expected_status
= wc
.State(src_path
,
4426 { '': Item(wc_rev
=new_rev
, status
=' ')})
4428 svntest
.actions
.run_and_verify_commit(src_path
, expected_output
,
4429 expected_status
, None, src_path
)
4431 # Update the WC to new_rev so that it would be easier to expect everyone
4433 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
4435 # Merge new_rev of src_path to dst_path.
4437 # Search for the comment entitled "The Merge Kluge" elsewhere in
4438 # this file, to understand why we shorten and chdir() below.
4439 short_dst_path
= shorten_path_kludge(dst_path
)
4440 expected_status
= wc
.State(dst_path
,
4441 { '': Item(wc_rev
=new_rev
, status
='MM')})
4442 saved_cwd
= os
.getcwd()
4444 os
.chdir(svntest
.main
.work_dir
)
4446 merge_url
= sbox
.repo_url
+ '/' + canon_src_path
4447 if sys
.platform
== 'win32':
4448 merge_url
= merge_url
.replace('\\', '/')
4450 svntest
.actions
.run_and_verify_svn(None,
4451 expected_merge_output([[new_rev
]],
4456 'merge', '-c', str(new_rev
),
4461 svntest
.actions
.run_and_verify_status(dst_path
, expected_status
)
4465 def obey_reporter_api_semantics_while_doing_subtree_merges(sbox
):
4466 "drive reporter api in depth first order"
4468 # Copy /A/D to /A/copy-of-D it results in rONE.
4469 # Create children at different hierarchies having some merge-info
4470 # to test the set_path calls on a reporter in a depth-first order.
4471 # On all 'file' descendants of /A/copy-of-D/ we run merges.
4472 # We create /A/D/umlaut directly over URL it results in rev rTWO.
4473 # When we merge rONE+1:TWO of /A/D on /A/copy-of-D it should merge smoothly.
4476 wc_dir
= sbox
.wc_dir
4478 A_path
= os
.path
.join(wc_dir
, 'A')
4479 A_D_path
= os
.path
.join(wc_dir
, 'A', 'D')
4480 copy_of_A_D_path
= os
.path
.join(wc_dir
, 'A', 'copy-of-D')
4482 svntest
.main
.run_svn(None, "cp", A_D_path
, copy_of_A_D_path
)
4484 expected_output
= svntest
.wc
.State(wc_dir
, {
4485 'A/copy-of-D' : Item(verb
='Adding'),
4487 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
4488 expected_status
.add({
4489 'A/copy-of-D' : Item(status
=' ', wc_rev
=2),
4490 'A/copy-of-D/G' : Item(status
=' ', wc_rev
=2),
4491 'A/copy-of-D/G/pi' : Item(status
=' ', wc_rev
=2),
4492 'A/copy-of-D/G/rho' : Item(status
=' ', wc_rev
=2),
4493 'A/copy-of-D/G/tau' : Item(status
=' ', wc_rev
=2),
4494 'A/copy-of-D/H' : Item(status
=' ', wc_rev
=2),
4495 'A/copy-of-D/H/chi' : Item(status
=' ', wc_rev
=2),
4496 'A/copy-of-D/H/omega' : Item(status
=' ', wc_rev
=2),
4497 'A/copy-of-D/H/psi' : Item(status
=' ', wc_rev
=2),
4498 'A/copy-of-D/gamma' : Item(status
=' ', wc_rev
=2),
4500 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4501 expected_status
, None, wc_dir
)
4505 for path
in (["A", "D", "G", "pi"],
4506 ["A", "D", "G", "rho"],
4507 ["A", "D", "G", "tau"],
4508 ["A", "D", "H", "chi"],
4509 ["A", "D", "H", "omega"],
4510 ["A", "D", "H", "psi"],
4511 ["A", "D", "gamma"]):
4512 path_name
= os
.path
.join(wc_dir
, *path
)
4513 canon_path_name
= os
.path
.join(*path
)
4514 path
[1] = "copy-of-D"
4515 copy_of_path_name
= os
.path
.join(wc_dir
, *path
)
4516 var_name
= 'new_content_for_' + path
[len(path
) - 1]
4517 file_contents
= "new content to " + path
[len(path
) - 1] + "\n"
4518 globals()[var_name
] = file_contents
4519 cur_rev
= tweak_src_then_merge_to_dest(sbox
, path_name
,
4520 copy_of_path_name
, canon_path_name
,
4521 file_contents
, cur_rev
)
4523 copy_of_A_D_wc_rev
= cur_rev
4524 svntest
.actions
.run_and_verify_svn(None,
4526 'Committed revision ' + str(cur_rev
+1) +
4529 'mkdir', sbox
.repo_url
+ '/A/D/umlaut',
4531 rev_to_merge_to_copy_of_D
= cur_rev
+ 1
4533 # Search for the comment entitled "The Merge Kluge" elsewhere in
4534 # this file, to understand why we shorten and chdir() below.
4535 short_copy_of_A_D_path
= shorten_path_kludge(copy_of_A_D_path
)
4537 # All the file descendants of /A/copy-of-D/ have already been merged
4538 # so the only notification we expect is for the added 'umlaut'.
4539 expected_output
= wc
.State(short_copy_of_A_D_path
, {
4540 'umlaut' : Item(status
='A '),
4543 # All the local svn:mergeinfo under A/copy-of-D elides
4545 expected_status
= wc
.State(short_copy_of_A_D_path
, {
4546 '' : Item(status
=' M', wc_rev
=copy_of_A_D_wc_rev
),
4547 'G' : Item(status
=' ', wc_rev
=copy_of_A_D_wc_rev
),
4548 'G/pi' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4549 'G/rho' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4550 'G/tau' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4551 'H' : Item(status
=' ', wc_rev
=copy_of_A_D_wc_rev
),
4552 'H/chi' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4553 'H/omega' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4554 'H/psi' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4555 'gamma' : Item(status
='M ', wc_rev
=copy_of_A_D_wc_rev
),
4556 'umlaut' : Item(status
='A ', copied
='+', wc_rev
='-'),
4559 merged_rangelist
= "3-%d" % rev_to_merge_to_copy_of_D
4562 expected_disk
= wc
.State('', {
4563 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:' + merged_rangelist
}),
4565 'G/pi' : Item(new_content_for_pi
),
4566 'G/rho' : Item(new_content_for_rho
),
4567 'G/tau' : Item(new_content_for_tau
),
4569 'H/chi' : Item(new_content_for_chi
,),
4570 'H/omega' : Item(new_content_for_omega
,),
4571 'H/psi' : Item(new_content_for_psi
,),
4572 'gamma' : Item(new_content_for_gamma
,),
4575 expected_skip
= wc
.State(short_copy_of_A_D_path
, { })
4576 os
.chdir(svntest
.main
.work_dir
)
4577 svntest
.actions
.run_and_verify_merge(short_copy_of_A_D_path
,
4579 str(rev_to_merge_to_copy_of_D
),
4580 sbox
.repo_url
+ '/A/D',
4591 def set_up_branch(sbox
, branch_only
= False, nbr_of_branches
= 1):
4592 '''Starting with standard greek tree, copy 'A' NBR_OF_BRANCHES times
4593 to A_COPY, A_COPY_2, A_COPY_3, and so on. Then make four modifications
4594 (setting file contents to "New content") under A:
4595 r(2 + NBR_OF_BRANCHES) - A/D/H/psi
4596 r(3 + NBR_OF_BRANCHES) - A/D/G/rho
4597 r(4 + NBR_OF_BRANCHES) - A/B/E/beta
4598 r(5 + NBR_OF_BRANCHES) - A/D/H/omega'''
4600 wc_dir
= sbox
.wc_dir
4602 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
4603 expected_disk
= svntest
.main
.greek_state
.copy()
4605 def copy_A(dest_name
, rev
):
4606 expected
= svntest
.verify
.UnorderedOutput(
4607 ["A " + os
.path
.join(wc_dir
, dest_name
, "B") + "\n",
4608 "A " + os
.path
.join(wc_dir
, dest_name
, "B", "lambda") + "\n",
4609 "A " + os
.path
.join(wc_dir
, dest_name
, "B", "E") + "\n",
4610 "A " + os
.path
.join(wc_dir
, dest_name
, "B", "E", "alpha") + "\n",
4611 "A " + os
.path
.join(wc_dir
, dest_name
, "B", "E", "beta") + "\n",
4612 "A " + os
.path
.join(wc_dir
, dest_name
, "B", "F") + "\n",
4613 "A " + os
.path
.join(wc_dir
, dest_name
, "mu") + "\n",
4614 "A " + os
.path
.join(wc_dir
, dest_name
, "C") + "\n",
4615 "A " + os
.path
.join(wc_dir
, dest_name
, "D") + "\n",
4616 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "gamma") + "\n",
4617 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "G") + "\n",
4618 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "G", "pi") + "\n",
4619 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "G", "rho") + "\n",
4620 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "G", "tau") + "\n",
4621 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "H") + "\n",
4622 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "H", "chi") + "\n",
4623 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "H", "omega") + "\n",
4624 "A " + os
.path
.join(wc_dir
, dest_name
, "D", "H", "psi") + "\n",
4625 "Checked out revision " + str(rev
- 1) + ".\n",
4626 "A " + os
.path
.join(wc_dir
, dest_name
) + "\n"])
4627 expected_status
.add({
4628 dest_name
+ "/B" : Item(status
=' ', wc_rev
=rev
),
4629 dest_name
+ "/B/lambda" : Item(status
=' ', wc_rev
=rev
),
4630 dest_name
+ "/B/E" : Item(status
=' ', wc_rev
=rev
),
4631 dest_name
+ "/B/E/alpha" : Item(status
=' ', wc_rev
=rev
),
4632 dest_name
+ "/B/E/beta" : Item(status
=' ', wc_rev
=rev
),
4633 dest_name
+ "/B/F" : Item(status
=' ', wc_rev
=rev
),
4634 dest_name
+ "/mu" : Item(status
=' ', wc_rev
=rev
),
4635 dest_name
+ "/C" : Item(status
=' ', wc_rev
=rev
),
4636 dest_name
+ "/D" : Item(status
=' ', wc_rev
=rev
),
4637 dest_name
+ "/D/gamma" : Item(status
=' ', wc_rev
=rev
),
4638 dest_name
+ "/D/G" : Item(status
=' ', wc_rev
=rev
),
4639 dest_name
+ "/D/G/pi" : Item(status
=' ', wc_rev
=rev
),
4640 dest_name
+ "/D/G/rho" : Item(status
=' ', wc_rev
=rev
),
4641 dest_name
+ "/D/G/tau" : Item(status
=' ', wc_rev
=rev
),
4642 dest_name
+ "/D/H" : Item(status
=' ', wc_rev
=rev
),
4643 dest_name
+ "/D/H/chi" : Item(status
=' ', wc_rev
=rev
),
4644 dest_name
+ "/D/H/omega" : Item(status
=' ', wc_rev
=rev
),
4645 dest_name
+ "/D/H/psi" : Item(status
=' ', wc_rev
=rev
),
4646 dest_name
: Item(status
=' ', wc_rev
=rev
)})
4649 dest_name
+ '/B' : Item(),
4650 dest_name
+ '/B/lambda' : Item("This is the file 'lambda'.\n"),
4651 dest_name
+ '/B/E' : Item(),
4652 dest_name
+ '/B/E/alpha' : Item("This is the file 'alpha'.\n"),
4653 dest_name
+ '/B/E/beta' : Item("This is the file 'beta'.\n"),
4654 dest_name
+ '/B/F' : Item(),
4655 dest_name
+ '/mu' : Item("This is the file 'mu'.\n"),
4656 dest_name
+ '/C' : Item(),
4657 dest_name
+ '/D' : Item(),
4658 dest_name
+ '/D/gamma' : Item("This is the file 'gamma'.\n"),
4659 dest_name
+ '/D/G' : Item(),
4660 dest_name
+ '/D/G/pi' : Item("This is the file 'pi'.\n"),
4661 dest_name
+ '/D/G/rho' : Item("This is the file 'rho'.\n"),
4662 dest_name
+ '/D/G/tau' : Item("This is the file 'tau'.\n"),
4663 dest_name
+ '/D/H' : Item(),
4664 dest_name
+ '/D/H/chi' : Item("This is the file 'chi'.\n"),
4665 dest_name
+ '/D/H/omega' : Item("This is the file 'omega'.\n"),
4666 dest_name
+ '/D/H/psi' : Item("This is the file 'psi'.\n"),
4669 # Make a branch A_COPY to merge into.
4670 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'copy',
4671 sbox
.repo_url
+ "/A",
4672 os
.path
.join(wc_dir
,
4675 expected_output
= wc
.State(wc_dir
, {dest_name
: Item(verb
='Adding')})
4676 svntest
.actions
.run_and_verify_commit(wc_dir
,
4681 for i
in range(nbr_of_branches
):
4683 copy_A('A_COPY', i
+ 2)
4685 copy_A('A_COPY_' + str(i
+ 1), i
+ 2)
4688 return expected_disk
, expected_status
4690 # Make some changes under A which we'll later merge under A_COPY:
4692 # r(nbr_of_branches + 2) - modify and commit A/D/H/psi
4693 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A", "D", "H", "psi"),
4695 expected_output
= wc
.State(wc_dir
, {'A/D/H/psi' : Item(verb
='Sending')})
4696 expected_status
.tweak('A/D/H/psi', wc_rev
=nbr_of_branches
+ 2)
4697 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4698 expected_status
, None, wc_dir
)
4699 expected_disk
.tweak('A/D/H/psi', contents
="New content")
4701 # r(nbr_of_branches + 3) - modify and commit A/D/G/rho
4702 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A", "D", "G", "rho"),
4704 expected_output
= wc
.State(wc_dir
, {'A/D/G/rho' : Item(verb
='Sending')})
4705 expected_status
.tweak('A/D/G/rho', wc_rev
=nbr_of_branches
+ 3)
4706 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4707 expected_status
, None, wc_dir
)
4708 expected_disk
.tweak('A/D/G/rho', contents
="New content")
4710 # r(nbr_of_branches + 4) - modify and commit A/B/E/beta
4711 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A", "B", "E", "beta"),
4713 expected_output
= wc
.State(wc_dir
, {'A/B/E/beta' : Item(verb
='Sending')})
4714 expected_status
.tweak('A/B/E/beta', wc_rev
=nbr_of_branches
+ 4)
4715 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4716 expected_status
, None, wc_dir
)
4717 expected_disk
.tweak('A/B/E/beta', contents
="New content")
4719 # r(nbr_of_branches + 5) - modify and commit A/D/H/omega
4720 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A", "D", "H", "omega"),
4722 expected_output
= wc
.State(wc_dir
, {'A/D/H/omega' : Item(verb
='Sending')})
4723 expected_status
.tweak('A/D/H/omega', wc_rev
=nbr_of_branches
+ 5)
4724 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
4725 expected_status
, None, wc_dir
)
4726 expected_disk
.tweak('A/D/H/omega', contents
="New content")
4728 return expected_disk
, expected_status
4731 def mergeinfo_inheritance(sbox
):
4732 "target inherits mergeinfo from nearest ancestor"
4734 # Test for Issues #2733 and #2734.
4736 # When the target of a merge has no explicit mergeinfo and the merge
4737 # would result in mergeinfo being added to the target which...
4739 # ...is a subset of the *local* mergeinfo on one of the target's
4740 # ancestors (it's nearest ancestor takes precedence), then the merge is
4741 # not repeated and no mergeinfo should be set on the target (Issue #2734).
4745 # ...is not a subset it's nearest ancestor, the target should inherit the
4746 # non-inersecting mergeinfo (local or committed, the former takes
4747 # precedence) from it's nearest ancestor (Issue #2733).
4750 wc_dir
= sbox
.wc_dir
4751 wc_disk
, wc_status
= set_up_branch(sbox
)
4753 # Some paths we'll care about
4754 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
4755 B_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B")
4756 beta_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B", "E", "beta")
4757 E_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B", "E")
4758 omega_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "omega")
4759 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
4760 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
4762 # Now start merging...
4764 # Merge r4 into A_COPY/D/
4765 # Search for the comment entitled "The Merge Kluge" elsewhere in
4766 # this file, to understand why we shorten and chdir() below.
4767 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
4768 expected_output
= wc
.State(short_D_COPY_path
, {
4769 'G/rho' : Item(status
='U '),
4771 expected_status
= wc
.State(short_D_COPY_path
, {
4772 '' : Item(status
=' M', wc_rev
=2),
4773 'G' : Item(status
=' ', wc_rev
=2),
4774 'G/pi' : Item(status
=' ', wc_rev
=2),
4775 'G/rho' : Item(status
='M ', wc_rev
=2),
4776 'G/tau' : Item(status
=' ', wc_rev
=2),
4777 'H' : Item(status
=' ', wc_rev
=2),
4778 'H/chi' : Item(status
=' ', wc_rev
=2),
4779 'H/psi' : Item(status
=' ', wc_rev
=2),
4780 'H/omega' : Item(status
=' ', wc_rev
=2),
4781 'gamma' : Item(status
=' ', wc_rev
=2),
4783 # We test issue #2733 here (with a directory as the merge target).
4784 # r1 should be inherited from 'A_COPY'.
4785 expected_disk
= wc
.State('', {
4786 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:4'}),
4788 'G/pi' : Item("This is the file 'pi'.\n"),
4789 'G/rho' : Item("New content"),
4790 'G/tau' : Item("This is the file 'tau'.\n"),
4792 'H/chi' : Item("This is the file 'chi'.\n"),
4793 'H/psi' : Item("This is the file 'psi'.\n"),
4794 'H/omega' : Item("This is the file 'omega'.\n"),
4795 'gamma' : Item("This is the file 'gamma'.\n")
4797 expected_skip
= wc
.State(short_D_COPY_path
, { })
4798 saved_cwd
= os
.getcwd()
4799 os
.chdir(svntest
.main
.work_dir
)
4800 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '3', '4',
4807 None, None, None, None,
4811 # Merge r4 again, this time into A_COPY/D/G. An ancestor directory
4812 # (A_COPY/D) exists with identical local mergeinfo, so the merge
4813 # should not be repeated. We test issue #2734 here with (with a
4814 # directory as the merge target).
4815 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
4816 expected_output
= wc
.State(short_G_COPY_path
, { })
4817 expected_status
= wc
.State(short_G_COPY_path
, {
4818 '' : Item(status
=' ', wc_rev
=2),
4819 'pi' : Item(status
=' ', wc_rev
=2),
4820 'rho' : Item(status
='M ', wc_rev
=2),
4821 'tau' : Item(status
=' ', wc_rev
=2),
4823 expected_disk
= wc
.State('', {
4824 'pi' : Item("This is the file 'pi'.\n"),
4825 'rho' : Item("New content"),
4826 'tau' : Item("This is the file 'tau'.\n"),
4828 expected_skip
= wc
.State(short_G_COPY_path
, { })
4829 os
.chdir(svntest
.main
.work_dir
)
4830 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '3', '4',
4837 None, None, None, None,
4840 # Merge r5 into A_COPY/B. Again, r1 should be inherited from
4841 # A_COPY (Issue #2733)
4842 short_B_COPY_path
= shorten_path_kludge(B_COPY_path
)
4843 expected_output
= wc
.State(short_B_COPY_path
, {
4844 'E/beta' : Item(status
='U '),
4846 expected_status
= wc
.State(short_B_COPY_path
, {
4847 '' : Item(status
=' M', wc_rev
=2),
4848 'E' : Item(status
=' ', wc_rev
=2),
4849 'E/alpha' : Item(status
=' ', wc_rev
=2),
4850 'E/beta' : Item(status
='M ', wc_rev
=2),
4851 'lambda' : Item(status
=' ', wc_rev
=2),
4852 'F' : Item(status
=' ', wc_rev
=2),
4854 expected_disk
= wc
.State('', {
4855 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:5'}),
4857 'E/alpha' : Item("This is the file 'alpha'.\n"),
4858 'E/beta' : Item("New content"),
4860 'lambda' : Item("This is the file 'lambda'.\n")
4862 expected_skip
= wc
.State(short_B_COPY_path
, { })
4864 os
.chdir(svntest
.main
.work_dir
)
4865 svntest
.actions
.run_and_verify_merge(short_B_COPY_path
, '4', '5',
4872 None, None, None, None,
4876 # Merge r5 again, this time into A_COPY/B/E/beta. An ancestor
4877 # directory (A_COPY/B) exists with identical local mergeinfo, so
4878 # the merge should not be repeated (Issue #2734 with a file as the
4880 short_beta_COPY_path
= shorten_path_kludge(beta_COPY_path
)
4881 expected_skip
= wc
.State(short_beta_COPY_path
, { })
4882 saved_cwd
= os
.getcwd()
4884 os
.chdir(svntest
.main
.work_dir
)
4885 # run_and_verify_merge doesn't support merging to a file WCPATH
4886 # so use run_and_verify_svn.
4887 svntest
.actions
.run_and_verify_svn(None, [], [], 'merge', '-c5',
4888 sbox
.repo_url
+ '/A/B/E/beta',
4889 short_beta_COPY_path
)
4892 # The merge wasn't repeated so beta shouldn't have any mergeinfo.
4893 # We are implicitly testing that without looking at the prop value
4894 # itself, just beta's prop modification status.
4895 expected_status
= wc
.State(beta_COPY_path
, {
4896 '' : Item(status
='M ', wc_rev
=2),
4898 svntest
.actions
.run_and_verify_status(beta_COPY_path
, expected_status
)
4900 # Merge r3 into A_COPY. A_COPY's two descendants with mergeinfo,
4901 # A_COPY/B/E/beta and A_COPY/D/G/rho must have complete mergeinfo
4902 # so they both should pick up r3 too.
4903 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
4904 expected_output
= wc
.State(short_A_COPY_path
, {
4905 'D/H/psi' : Item(status
='U '),
4907 expected_status
= wc
.State(short_A_COPY_path
, {
4908 '' : Item(status
=' M', wc_rev
=2),
4909 'B' : Item(status
=' M', wc_rev
=2),
4910 'mu' : Item(status
=' ', wc_rev
=2),
4911 'B/E' : Item(status
=' ', wc_rev
=2),
4912 'B/E/alpha' : Item(status
=' ', wc_rev
=2),
4913 'B/E/beta' : Item(status
='M ', wc_rev
=2),
4914 'B/lambda' : Item(status
=' ', wc_rev
=2),
4915 'B/F' : Item(status
=' ', wc_rev
=2),
4916 'C' : Item(status
=' ', wc_rev
=2),
4917 'D' : Item(status
=' M', wc_rev
=2),
4918 'D/G' : Item(status
=' ', wc_rev
=2),
4919 'D/G/pi' : Item(status
=' ', wc_rev
=2),
4920 'D/G/rho' : Item(status
='M ', wc_rev
=2),
4921 'D/G/tau' : Item(status
=' ', wc_rev
=2),
4922 'D/gamma' : Item(status
=' ', wc_rev
=2),
4923 'D/H' : Item(status
=' ', wc_rev
=2),
4924 'D/H/chi' : Item(status
=' ', wc_rev
=2),
4925 'D/H/psi' : Item(status
='M ', wc_rev
=2),
4926 'D/H/omega' : Item(status
=' ', wc_rev
=2),
4928 expected_disk
= wc
.State('', {
4929 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:3'}),
4930 'B' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:3,5'}),
4931 'mu' : Item("This is the file 'mu'.\n"),
4933 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
4934 'B/E/beta' : Item("New content"),
4935 'B/lambda' : Item("This is the file 'lambda'.\n"),
4938 'D' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:3-4'}),
4940 'D/G/pi' : Item("This is the file 'pi'.\n"),
4941 'D/G/rho' : Item("New content"),
4942 'D/G/tau' : Item("This is the file 'tau'.\n"),
4943 'D/gamma' : Item("This is the file 'gamma'.\n"),
4945 'D/H/chi' : Item("This is the file 'chi'.\n"),
4946 'D/H/psi' : Item("New content"),
4947 'D/H/omega' : Item("This is the file 'omega'.\n"),
4949 expected_skip
= wc
.State(short_A_COPY_path
, { })
4950 saved_cwd
= os
.getcwd()
4951 os
.chdir(svntest
.main
.work_dir
)
4952 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '2', '3',
4959 None, None, None, None,
4963 # Merge r6 into A_COPY/D/H/omega, it should inherit it's nearest
4964 # ancestor's (A_COPY/D) mergeinfo (Issue #2733 with a file as the
4966 short_omega_COPY_path
= shorten_path_kludge(omega_COPY_path
)
4967 expected_skip
= wc
.State(short_omega_COPY_path
, { })
4968 saved_cwd
= os
.getcwd()
4969 os
.chdir(svntest
.main
.work_dir
)
4970 # run_and_verify_merge doesn't support merging to a file WCPATH
4971 # so use run_and_verify_svn.
4972 svntest
.actions
.run_and_verify_svn(None,
4973 expected_merge_output([[6]],
4974 'U ' + short_omega_COPY_path
+ '\n'),
4976 sbox
.repo_url
+ '/A/D/H/omega',
4977 short_omega_COPY_path
)
4980 # Check that mergeinfo was properly set on A_COPY/D/H/omega
4981 svntest
.actions
.run_and_verify_svn(None,
4982 ["/A/D/H/omega:3-4,6\n"],
4984 'propget', SVN_PROP_MERGEINFO
,
4987 # Given a merge target *without* any of the following:
4989 # 1) Explicit mergeinfo set on itself in the WC
4990 # 2) Any WC ancestor to inherit mergeinfo from
4991 # 3) Any mergeinfo for the target in the repository
4993 # Check that the target still inherits mergeinfo from it's nearest
4994 # repository ancestor.
4996 # Commit all the merges thus far
4997 expected_output
= wc
.State(wc_dir
, {
4998 'A_COPY' : Item(verb
='Sending'),
4999 'A_COPY/B' : Item(verb
='Sending'),
5000 'A_COPY/B/E/beta' : Item(verb
='Sending'),
5001 'A_COPY/D' : Item(verb
='Sending'),
5002 'A_COPY/D/G/rho' : Item(verb
='Sending'),
5003 'A_COPY/D/H/omega' : Item(verb
='Sending'),
5004 'A_COPY/D/H/psi' : Item(verb
='Sending'),
5006 wc_status
.tweak('A_COPY', 'A_COPY/B', 'A_COPY/B/E/beta', 'A_COPY/D',
5007 'A_COPY/D/G/rho', 'A_COPY/D/H/omega', 'A_COPY/D/H/psi',
5009 svntest
.actions
.run_and_verify_commit(wc_dir
,
5015 # Copy the subtree A_COPY/B/E from the working copy, making the
5016 # disconnected WC E_only.
5017 other_wc
= sbox
.add_wc_path('E_only')
5018 svntest
.actions
.duplicate_dir(E_COPY_path
, other_wc
)
5020 # Update the disconnected WC it so it will get the most recent mergeinfo
5021 # from the repos when merging.
5022 svntest
.actions
.run_and_verify_svn(None, ["At revision 7.\n"], [], 'up',
5025 # Merge r5:4 into the root of the disconnected WC.
5026 # E_only has no explicit mergeinfo and since it's the root of the WC
5027 # cannot inherit and mergeinfo from a working copy ancestor path. Nor
5028 # does it have any mergeinfo explicitly set on it in the repository.
5029 # An ancestor path on the repository side, A_COPY/B does have the merge
5030 # info '/A/B:1,3,5' however and E_only should inherit this, resulting in
5031 # mergeinfo of 'A/B/E:1,3' after the removal of r5.
5032 short_other_wc_path
= shorten_path_kludge(other_wc
)
5033 expected_output
= wc
.State(short_other_wc_path
,
5034 {'beta' : Item(status
='U ')})
5035 expected_status
= wc
.State(short_other_wc_path
, {
5036 '' : Item(status
=' M', wc_rev
=7),
5037 'alpha' : Item(status
=' ', wc_rev
=7),
5038 'beta' : Item(status
='M ', wc_rev
=7),
5040 expected_disk
= wc
.State('', {
5041 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/E:3'}),
5042 'alpha' : Item("This is the file 'alpha'.\n"),
5043 'beta' : Item("This is the file 'beta'.\n"),
5045 expected_skip
= wc
.State(short_other_wc_path
, { })
5047 os
.chdir(svntest
.main
.work_dir
)
5048 svntest
.actions
.run_and_verify_merge(short_other_wc_path
, '5', '4',
5055 None, None, None, None,
5058 def mergeinfo_elision(sbox
):
5059 "mergeinfo elides to ancestor with identical info"
5061 # When a merge would result in mergeinfo on a target which is identical
5062 # to mergeinfo (local or committed) on one of the node's ancestors (the
5063 # nearest ancestor takes precedence), then the mergeinfo elides from the
5064 # target to the nearest ancestor (e.g. no mergeinfo is set on the target
5065 # or committed mergeinfo is removed).
5068 wc_dir
= sbox
.wc_dir
5069 wc_disk
, wc_status
= set_up_branch(sbox
)
5071 # Some paths we'll care about
5072 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
5073 beta_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B", "E", "beta")
5074 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
5076 # Now start merging...
5078 # Merge r5 into A_COPY/B/E/beta.
5079 short_beta_COPY_path
= shorten_path_kludge(beta_COPY_path
)
5080 expected_skip
= wc
.State(short_beta_COPY_path
, { })
5081 saved_cwd
= os
.getcwd()
5083 os
.chdir(svntest
.main
.work_dir
)
5084 # run_and_verify_merge doesn't support merging to a file WCPATH
5085 # so use run_and_verify_svn.
5086 svntest
.actions
.run_and_verify_svn(None,
5087 expected_merge_output([[5]],
5088 'U ' + short_beta_COPY_path
+ '\n'),
5090 sbox
.repo_url
+ '/A/B/E/beta',
5091 short_beta_COPY_path
)
5094 # Check beta's status and props.
5095 expected_status
= wc
.State(beta_COPY_path
, {
5096 '' : Item(status
='MM', wc_rev
=2),
5098 svntest
.actions
.run_and_verify_status(beta_COPY_path
, expected_status
)
5100 svntest
.actions
.run_and_verify_svn(None, ["/A/B/E/beta:5\n"], [],
5101 'propget', SVN_PROP_MERGEINFO
,
5105 expected_output
= wc
.State(wc_dir
, {
5106 'A_COPY/B/E/beta' : Item(verb
='Sending'),
5108 wc_status
.tweak('A_COPY/B/E/beta', wc_rev
=7)
5109 svntest
.actions
.run_and_verify_commit(wc_dir
,
5115 # Update A_COPY to get all paths to the same working revision.
5116 svntest
.actions
.run_and_verify_svn(None, ["At revision 7.\n"], [],
5118 wc_status
.tweak(wc_rev
=7)
5120 # Merge r4 into A_COPY/D/G.
5121 # Search for the comment entitled "The Merge Kluge" elsewhere in
5122 # this file, to understand why we shorten and chdir() below.
5123 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
5124 expected_output
= wc
.State(short_G_COPY_path
, {
5125 'rho' : Item(status
='U ')
5127 expected_status
= wc
.State(short_G_COPY_path
, {
5128 '' : Item(status
=' M', wc_rev
=7),
5129 'pi' : Item(status
=' ', wc_rev
=7),
5130 'rho' : Item(status
='M ', wc_rev
=7),
5131 'tau' : Item(status
=' ', wc_rev
=7),
5133 expected_disk
= wc
.State('', {
5134 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:4'}),
5135 'pi' : Item("This is the file 'pi'.\n"),
5136 'rho' : Item("New content"),
5137 'tau' : Item("This is the file 'tau'.\n"),
5139 expected_skip
= wc
.State(short_G_COPY_path
, { })
5141 os
.chdir(svntest
.main
.work_dir
)
5142 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '3', '4',
5149 None, None, None, None,
5153 # Merge r3:6 into A_COPY. This would result in identical mergeinfo
5154 # (r4-6) on A_COPY and two of it's descendants, A_COPY/D/G and
5155 # A_COPY/B/E/beta, so the mergeinfo on the latter two should elide
5156 # to A_COPY. In the case of A_COPY/D/G this means its wholly uncommitted
5157 # mergeinfo is removed leaving no prop mods. In the case of
5158 # A_COPY/B/E/beta its committed mergeinfo prop is removed leaving a prop
5160 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
5161 expected_output
= wc
.State(short_A_COPY_path
, {
5162 'D/H/omega' : Item(status
='U ')
5164 expected_status
= wc
.State(short_A_COPY_path
, {
5165 '' : Item(status
=' M', wc_rev
=7),
5166 'B' : Item(status
=' ', wc_rev
=7),
5167 'mu' : Item(status
=' ', wc_rev
=7),
5168 'B/E' : Item(status
=' ', wc_rev
=7),
5169 'B/E/alpha' : Item(status
=' ', wc_rev
=7),
5170 'B/E/beta' : Item(status
=' M', wc_rev
=7),
5171 'B/lambda' : Item(status
=' ', wc_rev
=7),
5172 'B/F' : Item(status
=' ', wc_rev
=7),
5173 'C' : Item(status
=' ', wc_rev
=7),
5174 'D' : Item(status
=' ', wc_rev
=7),
5175 'D/G' : Item(status
=' ', wc_rev
=7),
5176 'D/G/pi' : Item(status
=' ', wc_rev
=7),
5177 'D/G/rho' : Item(status
='M ', wc_rev
=7),
5178 'D/G/tau' : Item(status
=' ', wc_rev
=7),
5179 'D/gamma' : Item(status
=' ', wc_rev
=7),
5180 'D/H' : Item(status
=' ', wc_rev
=7),
5181 'D/H/chi' : Item(status
=' ', wc_rev
=7),
5182 'D/H/psi' : Item(status
=' ', wc_rev
=7),
5183 'D/H/omega' : Item(status
='M ', wc_rev
=7),
5185 expected_disk
= wc
.State('', {
5186 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:4-6'}),
5188 'mu' : Item("This is the file 'mu'.\n"),
5190 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
5191 'B/E/beta' : Item("New content"),
5192 'B/lambda' : Item("This is the file 'lambda'.\n"),
5197 'D/G/pi' : Item("This is the file 'pi'.\n"),
5198 'D/G/rho' : Item("New content"),
5199 'D/G/tau' : Item("This is the file 'tau'.\n"),
5200 'D/gamma' : Item("This is the file 'gamma'.\n"),
5202 'D/H/chi' : Item("This is the file 'chi'.\n"),
5203 'D/H/psi' : Item("This is the file 'psi'.\n"),
5204 'D/H/omega' : Item("New content"),
5206 expected_skip
= wc
.State(short_A_COPY_path
, { })
5208 os
.chdir(svntest
.main
.work_dir
)
5209 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '3', '6',
5216 None, None, None, None,
5220 # Reverse merge r5 out of A_COPY/B/E/beta. The mergeinfo on
5221 # A_COPY/B/E/beta which previously elided will now return,
5222 # minus r5 of course.
5223 expected_skip
= wc
.State(short_beta_COPY_path
, { })
5225 os
.chdir(svntest
.main
.work_dir
)
5226 # run_and_verify_merge doesn't support merging to a file WCPATH
5227 # so use run_and_verify_svn.
5228 svntest
.actions
.run_and_verify_svn(None,
5229 expected_merge_output([[-5]],
5230 'U ' + short_beta_COPY_path
+ '\n'),
5231 [], 'merge', '-c-5',
5232 sbox
.repo_url
+ '/A/B/E/beta',
5233 short_beta_COPY_path
)
5236 # Check beta's status and props.
5237 expected_status
= wc
.State(beta_COPY_path
, {
5238 '' : Item(status
='MM', wc_rev
=7),
5240 svntest
.actions
.run_and_verify_status(beta_COPY_path
, expected_status
)
5242 svntest
.actions
.run_and_verify_svn(None, ["/A/B/E/beta:4,6\n"], [],
5243 'propget', SVN_PROP_MERGEINFO
,
5246 # Merge r5 back into A_COPY/B/E/beta. Now the mergeinfo on the merge
5247 # target (A_COPY/B/E/beta) is identical to it's nearest ancestor with
5248 # mergeinfo (A_COPY) and so the former should elide.
5249 os
.chdir(svntest
.main
.work_dir
)
5250 # run_and_verify_merge doesn't support merging to a file WCPATH
5251 # so use run_and_verify_svn.
5252 svntest
.actions
.run_and_verify_svn(None,
5253 expected_merge_output([[5]],
5254 'G ' + short_beta_COPY_path
+ '\n'),
5256 sbox
.repo_url
+ '/A/B/E/beta',
5257 short_beta_COPY_path
)
5260 # Check beta's status and props.
5261 expected_status
= wc
.State(beta_COPY_path
, {
5262 '' : Item(status
=' M', wc_rev
=7),
5264 svntest
.actions
.run_and_verify_status(beta_COPY_path
, expected_status
)
5266 # Once again A_COPY/B/E/beta has no mergeinfo.
5267 svntest
.actions
.run_and_verify_svn(None, [], [],
5268 'propget', SVN_PROP_MERGEINFO
,
5271 def mergeinfo_inheritance_and_discontinuous_ranges(sbox
):
5272 "discontinuous merges produce correct mergeinfo"
5274 # When a merge target has no explicit mergeinfo and is subject
5275 # to multiple merges, the resulting mergeinfo on the target
5276 # should reflect the combination of the inherited mergeinfo
5277 # with each merge performed.
5279 # Also tests implied merge source and target when only a revision
5280 # range is specified.
5283 wc_dir
= sbox
.wc_dir
5285 # Some paths we'll care about
5286 A_url
= sbox
.repo_url
+ '/A'
5287 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
5288 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
5289 A_COPY_rho_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "rho")
5291 expected_disk
, expected_status
= set_up_branch(sbox
)
5293 # Merge r4 into A_COPY
5294 saved_cwd
= os
.getcwd()
5296 os
.chdir(A_COPY_path
)
5297 svntest
.actions
.run_and_verify_svn(None,
5298 expected_merge_output([[4]], 'U ' +
5299 os
.path
.join("D", "G", "rho") + '\n'),
5300 [], 'merge', '-c4', A_url
)
5303 # Check the results of the merge.
5304 expected_status
.tweak("A_COPY", status
=' M')
5305 expected_status
.tweak("A_COPY/D/G/rho", status
='M ')
5306 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
5307 svntest
.actions
.run_and_verify_svn(None, ["/A:4\n"], [],
5308 'propget', SVN_PROP_MERGEINFO
,
5311 # Merge r2:6 into A_COPY/D
5313 # Search for the comment entitled "The Merge Kluge" elsewhere in
5314 # this file, to understand why we shorten and chdir() below.
5316 # A_COPY/D should inherit the mergeinfo '/A:4' from A_COPY
5317 # combine it with the discontinous merges performed directly on
5318 # it (A/D/ 2:3 and A/D 4:6) resulting in '/A/D:3-6'.
5319 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
5320 expected_output
= wc
.State(short_D_COPY_path
, {
5321 'H/psi' : Item(status
='U '),
5322 'H/omega' : Item(status
='U '),
5324 expected_status
= wc
.State(short_D_COPY_path
, {
5325 '' : Item(status
=' M', wc_rev
=2),
5326 'G' : Item(status
=' ', wc_rev
=2),
5327 'G/pi' : Item(status
=' ', wc_rev
=2),
5328 'G/rho' : Item(status
='M ', wc_rev
=2),
5329 'G/tau' : Item(status
=' ', wc_rev
=2),
5330 'H' : Item(status
=' ', wc_rev
=2),
5331 'H/chi' : Item(status
=' ', wc_rev
=2),
5332 'H/psi' : Item(status
='M ', wc_rev
=2),
5333 'H/omega' : Item(status
='M ', wc_rev
=2),
5334 'gamma' : Item(status
=' ', wc_rev
=2),
5336 expected_disk
= wc
.State('', {
5337 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:3-6'}),
5339 'G/pi' : Item("This is the file 'pi'.\n"),
5340 'G/rho' : Item("New content"),
5341 'G/tau' : Item("This is the file 'tau'.\n"),
5343 'H/chi' : Item("This is the file 'chi'.\n"),
5344 'H/psi' : Item("New content"),
5345 'H/omega' : Item("New content"),
5346 'gamma' : Item("This is the file 'gamma'.\n")
5348 expected_skip
= wc
.State(short_D_COPY_path
, { })
5350 os
.chdir(svntest
.main
.work_dir
)
5351 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '2', '6',
5352 sbox
.repo_url
+ '/A/D',
5357 None, None, None, None,
5361 # Wipe the memory of a portion of the previous merge...
5362 ### It'd be nice to use 'merge --record-only' here, but we can't (yet)
5363 ### wipe all ranges for a file due to the bug pointed out in r24645.
5364 mu_copy_path
= os
.path
.join(A_COPY_path
, 'mu')
5365 svntest
.actions
.run_and_verify_svn(None,
5366 ["property '" + SVN_PROP_MERGEINFO
5368 mu_copy_path
+ "'\n"], [], 'propset',
5369 SVN_PROP_MERGEINFO
, '', mu_copy_path
)
5370 # ...and confirm that we can commit the wiped mergeinfo...
5371 expected_output
= wc
.State(wc_dir
, {
5372 'A_COPY/mu' : Item(verb
='Sending'),
5374 svntest
.actions
.run_and_verify_commit(wc_dir
,
5379 # ...and that the presence of the property is retained, even when
5380 # the value has been wiped.
5381 svntest
.actions
.run_and_verify_svn(None, ['\n'], [], 'propget',
5382 SVN_PROP_MERGEINFO
, mu_copy_path
)
5384 def merge_to_target_with_copied_children(sbox
):
5385 "merge works when target has copied children"
5387 # Test for Issue #2754 Can't merge to target with copied/moved children
5390 wc_dir
= sbox
.wc_dir
5391 expected_disk
, expected_status
= set_up_branch(sbox
)
5393 # Some paths we'll care about
5394 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
5395 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
5396 rho_COPY_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "rho_copy")
5398 # URL to URL copy A_COPY/D/G/rho to A_COPY/D/G/rho_copy
5399 svntest
.actions
.run_and_verify_svn(None, None, [], 'copy',
5400 sbox
.repo_url
+ '/A_COPY/D/G/rho',
5401 sbox
.repo_url
+ '/A_COPY/D/G/rho_copy',
5405 expected_output
= wc
.State(wc_dir
,
5406 {'A_COPY/D/G/rho_copy' : Item(status
='A ')})
5408 'A_COPY/D/G/rho_copy' : Item("This is the file 'rho'.\n", props
={})
5410 expected_status
.tweak(wc_rev
=7)
5411 expected_status
.add({'A_COPY/D/G/rho_copy' : Item(status
=' ', wc_rev
=7)})
5412 svntest
.actions
.run_and_verify_update(wc_dir
,
5419 # Merge r4 into A_COPY/D/G/rho_copy.
5421 # Search for the comment entitled "The Merge Kluge" elsewhere in
5422 # this file, to understand why we shorten and chdir() below.
5423 os
.chdir(svntest
.main
.work_dir
)
5424 short_rho_COPY_COPY_path
= shorten_path_kludge(rho_COPY_COPY_path
)
5425 svntest
.actions
.run_and_verify_svn(None,
5426 expected_merge_output([[4]],
5427 'U ' + short_rho_COPY_COPY_path
+
5430 sbox
.repo_url
+ '/A/D/G/rho',
5431 short_rho_COPY_COPY_path
)
5433 # Merge r3:5 into A_COPY/D/G.
5434 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
5435 expected_output
= wc
.State(short_G_COPY_path
, {
5436 'rho' : Item(status
='U ')
5438 expected_status
= wc
.State(short_G_COPY_path
, {
5439 '' : Item(status
=' M', wc_rev
=7),
5440 'pi' : Item(status
=' ', wc_rev
=7),
5441 'rho' : Item(status
='M ', wc_rev
=7),
5442 'rho_copy' : Item(status
='MM', wc_rev
=7),
5443 'tau' : Item(status
=' ', wc_rev
=7),
5445 expected_disk
= wc
.State('', {
5446 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:4-5'}),
5447 'pi' : Item("This is the file 'pi'.\n"),
5448 'rho' : Item("New content"),
5449 'rho_copy' : Item("New content",
5450 props
={SVN_PROP_MERGEINFO
: '/A/D/G/rho:4'}),
5451 'tau' : Item("This is the file 'tau'.\n"),
5453 expected_skip
= wc
.State(short_G_COPY_path
, { })
5454 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '3', '5',
5461 None, None, None, None,
5464 def merge_to_switched_path(sbox
):
5465 "merge to switched path does not inherit or elide"
5467 # When the target of a merge is a switched path we don't inherit WC
5468 # mergeinfo from above the target or attempt to elide the mergeinfo
5469 # set on the target as a result of the merge.
5472 wc_dir
= sbox
.wc_dir
5473 wc_disk
, wc_status
= set_up_branch(sbox
)
5475 # Some paths we'll care about
5476 A_COPY_D_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
5477 G_COPY_path
= os
.path
.join(wc_dir
, "A", "D", "G_COPY")
5478 A_COPY_D_G_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
5479 A_COPY_D_G_rho_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "rho")
5481 expected
= svntest
.verify
.UnorderedOutput(
5482 ["A " + os
.path
.join(G_COPY_path
, "pi") + "\n",
5483 "A " + os
.path
.join(G_COPY_path
, "rho") + "\n",
5484 "A " + os
.path
.join(G_COPY_path
, "tau") + "\n",
5485 "Checked out revision 6.\n",
5486 "A " + G_COPY_path
+ "\n"])
5488 # r7 - Copy A/D/G to A/D/G_COPY and commit.
5489 svntest
.actions
.run_and_verify_svn(None, expected
, [], 'copy',
5490 sbox
.repo_url
+ "/A/D/G",
5493 expected_output
= wc
.State(wc_dir
, {'A/D/G_COPY' : Item(verb
='Adding')})
5495 "A/D/G_COPY" : Item(status
=' ', wc_rev
=7),
5496 "A/D/G_COPY/pi" : Item(status
=' ', wc_rev
=7),
5497 "A/D/G_COPY/rho" : Item(status
=' ', wc_rev
=7),
5498 "A/D/G_COPY/tau" : Item(status
=' ', wc_rev
=7),
5501 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
5504 # r8 - modify and commit A/D/G_COPY/rho
5505 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A", "D", "G_COPY", "rho"),
5506 "New *and* improved rho content")
5507 expected_output
= wc
.State(wc_dir
, {'A/D/G_COPY/rho' : Item(verb
='Sending')})
5508 wc_status
.tweak('A/D/G_COPY/rho', wc_rev
=8)
5509 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
5512 # Switch A_COPY/D/G to A/D/G.
5515 "A/D/G_COPY" : Item(),
5516 "A/D/G_COPY/pi" : Item("This is the file 'pi'.\n"),
5517 "A/D/G_COPY/rho" : Item("New *and* improved rho content"),
5518 "A/D/G_COPY/tau" : Item("This is the file 'tau'.\n"),
5520 wc_disk
.tweak('A_COPY/D/G/rho',contents
="New content")
5521 wc_status
.tweak("A_COPY/D/G", wc_rev
=8, switched
='S')
5522 wc_status
.tweak("A_COPY/D/G/pi", wc_rev
=8)
5523 wc_status
.tweak("A_COPY/D/G/rho", wc_rev
=8)
5524 wc_status
.tweak("A_COPY/D/G/tau", wc_rev
=8)
5525 expected_output
= svntest
.wc
.State(sbox
.wc_dir
, {
5526 "A_COPY/D/G/rho" : Item(status
='U '),
5528 svntest
.actions
.run_and_verify_switch(sbox
.wc_dir
, A_COPY_D_G_path
,
5529 sbox
.repo_url
+ "/A/D/G",
5530 expected_output
, wc_disk
, wc_status
,
5531 None, None, None, None, None, 1)
5533 # Merge r8 from A/D/G_COPY into our switched target A_COPY/D/G.
5534 # A_COPY/D/G should get mergeinfo for r8 as a result of the merge,
5535 # but because it's switched should not inherit the mergeinfo from
5536 # its nearest WC ancestor with mergeinfo (A_COPY: svn:mergeinfo : /A:1)
5538 # Search for the comment entitled "The Merge Kluge" elsewhere in
5539 # this file, to understand why we shorten and chdir() below.
5540 short_G_COPY_path
= shorten_path_kludge(A_COPY_D_G_path
)
5541 expected_output
= wc
.State(short_G_COPY_path
, {
5542 'rho' : Item(status
='U ')
5544 # Note: A_COPY/D/G won't show as switched because of the Merge Kluge.
5545 expected_status
= wc
.State(short_G_COPY_path
, {
5546 '' : Item(status
=' M', wc_rev
=8),
5547 'pi' : Item(status
=' ', wc_rev
=8),
5548 'rho' : Item(status
='M ', wc_rev
=8),
5549 'tau' : Item(status
=' ', wc_rev
=8),
5551 expected_disk
= wc
.State('', {
5552 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G_COPY:8'}),
5553 'pi' : Item("This is the file 'pi'.\n"),
5554 'rho' : Item("New *and* improved rho content"),
5555 'tau' : Item("This is the file 'tau'.\n"),
5557 expected_skip
= wc
.State(short_G_COPY_path
, { })
5558 saved_cwd
= os
.getcwd()
5560 os
.chdir(svntest
.main
.work_dir
)
5561 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '7', '8',
5562 sbox
.repo_url
+ '/A/D/G_COPY',
5563 expected_output
, expected_disk
,
5564 expected_status
, expected_skip
,
5565 None, None, None, None, None, 1)
5568 # Check that the mergeinfo set on a target doesn't elide when that
5569 # target is switched.
5571 # Revert the previous merge and manually set 'svn:mergeinfo : '
5572 # on 'merge_tests-1\A_COPY\D'. Now merge -c-4 from /A/D/G into A_COPY/D/G.
5573 # This should still set 'svn:mergeinfo : ' on
5574 # 'merge_tests-1\A_COPY\D\G'. This would normally elide to A_COPY/D,
5575 # but since A_COPY/D/G is switched it should not.
5576 svntest
.actions
.run_and_verify_svn(None,
5577 ["Reverted '" + A_COPY_D_G_path
+ "'\n",
5578 "Reverted '" + A_COPY_D_G_rho_path
+
5580 [], 'revert', '-R', wc_dir
)
5581 svntest
.actions
.run_and_verify_svn(None,
5582 ["property '" + SVN_PROP_MERGEINFO
+
5583 "' set on '" + A_COPY_D_path
+ "'" +
5584 "\n"], [], 'ps', SVN_PROP_MERGEINFO
,
5586 svntest
.actions
.run_and_verify_svn(None,
5587 expected_merge_output([[-4]],
5588 'U ' + A_COPY_D_G_rho_path
+ '\n'),
5589 [], 'merge', '-c-4',
5590 sbox
.repo_url
+ '/A/D/G_COPY',
5592 wc_status
.tweak("A_COPY/D", status
=' M')
5593 wc_status
.tweak("A_COPY/D/G", status
=' M')
5594 wc_status
.tweak("A_COPY/D/G/rho", status
='M ')
5595 svntest
.actions
.run_and_verify_status(wc_dir
, wc_status
)
5596 expected
= svntest
.verify
.UnorderedOutput(
5597 ["A " + os
.path
.join(G_COPY_path
, "pi") + "\n",
5598 "A " + os
.path
.join(G_COPY_path
, "rho") + "\n",
5599 "A " + os
.path
.join(G_COPY_path
, "tau") + "\n",
5600 "Checked out revision 6.\n",
5601 "A " + G_COPY_path
+ "\n"])
5602 expected
= svntest
.verify
.UnorderedOutput(
5603 ["Properties on '" + A_COPY_D_path
+ "':\n",
5604 " " + SVN_PROP_MERGEINFO
+ " : \n",
5605 "Properties on '" + A_COPY_D_G_path
+ "':\n",
5606 " " + SVN_PROP_MERGEINFO
+" : \n"])
5607 svntest
.actions
.run_and_verify_svn(None,
5609 'pl', '-vR', A_COPY_D_path
)
5613 # 2823: Account for mergeinfo differences for switched
5614 # directories when gathering mergeinfo
5616 # 2839: Support non-inheritable mergeinfo revision ranges
5617 def merge_to_path_with_switched_children(sbox
):
5618 "merge to path with switched children"
5620 # Merging to a target with switched children requires special handling
5621 # to keep mergeinfo correct:
5623 # 1) If the target of a merge has switched children without explicit
5624 # mergeinfo, the switched children should get mergeinfo set on
5625 # them as a result of the merge. This mergeinfo includes the
5626 # mergeinfo resulting from the merge *and* any mergeinfo inherited
5627 # from the repos for the switched path.
5629 # 2) Mergeinfo on switched children should never elide.
5631 # 3) The path the switched child overrides cannot be modified by the
5632 # merge (it isn't present in the WC) so should not inherit any
5633 # mergeinfo added as a result of the merge. To prevent this, the
5634 # immediate parent of any switched child should have non-inheritable
5635 # mergeinfo added/modified for the merge performed.
5637 # 4) Because of 3, siblings of switched children will not inherit the
5638 # mergeinfo resulting from the merge, so must get their own, full set
5642 wc_dir
= sbox
.wc_dir
5643 wc_disk
, wc_status
= set_up_branch(sbox
, False, 3)
5645 # Some paths we'll care about
5646 D_path
= os
.path
.join(wc_dir
, "A", "D")
5647 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
5648 A_COPY_beta_path
= os
.path
.join(wc_dir
, "A_COPY", "B", "E", "beta")
5649 A_COPY_chi_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "chi")
5650 A_COPY_omega_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "omega")
5651 A_COPY_psi_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "psi")
5652 A_COPY_G_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
5653 A_COPY_rho_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "rho")
5654 A_COPY_H_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H")
5655 A_COPY_D_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
5656 A_COPY_gamma_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "gamma")
5657 H_COPY_2_path
= os
.path
.join(wc_dir
, "A_COPY_2", "D", "H")
5659 svntest
.actions
.run_and_verify_svn(None, ["At revision 8.\n"], [], 'up',
5661 wc_status
.tweak(wc_rev
=8)
5663 # Switch a file and dir path in the branch:
5665 # Switch A_COPY/D/G to A_COPY_2/D/G.
5666 wc_status
.tweak("A_COPY/D/G", switched
='S')
5667 expected_output
= svntest
.wc
.State(sbox
.wc_dir
, {})
5668 svntest
.actions
.run_and_verify_switch(sbox
.wc_dir
, A_COPY_G_path
,
5669 sbox
.repo_url
+ "/A_COPY_2/D/G",
5670 expected_output
, wc_disk
, wc_status
,
5671 None, None, None, None, None, 1)
5673 # Switch A_COPY/D/G/rho to A_COPY_3/D/G/rho.
5674 wc_status
.tweak("A_COPY/D/G/rho", switched
='S')
5675 expected_output
= svntest
.wc
.State(sbox
.wc_dir
, {})
5676 svntest
.actions
.run_and_verify_switch(sbox
.wc_dir
, A_COPY_rho_path
,
5677 sbox
.repo_url
+ "/A_COPY_3/D/G/rho",
5678 expected_output
, wc_disk
, wc_status
,
5679 None, None, None, None, None, 1)
5681 # Switch A_COPY/D/H/psi to A_COPY_2/D/H/psi.
5682 wc_status
.tweak("A_COPY/D/H/psi", switched
='S')
5683 expected_output
= svntest
.wc
.State(sbox
.wc_dir
, {})
5684 svntest
.actions
.run_and_verify_switch(sbox
.wc_dir
, A_COPY_psi_path
,
5685 sbox
.repo_url
+ "/A_COPY_2/D/H/psi",
5686 expected_output
, wc_disk
, wc_status
,
5687 None, None, None, None, None, 1)
5689 # Target with switched file child:
5691 # Merge r8 from A/D/H into A_COPY/D/H. The switched child of
5692 # A_COPY/D/H, file A_COPY/D/H/psi (which has no mergeinfo prior
5693 # to the merge), should get their own mergeinfo, both r8 from the
5694 # merge itself, and r1-2 inherited from A_COPY_2 in the repository.
5696 # A_COPY/D/H/psi's parent A_COPY/D/H has no pre-exiting explicit
5697 # mergeinfo so should get its own mergeinfo, made up of r1 inherited
5698 # from A_COPY and the non-inheritable r8 resulting from the merge.
5700 # A_COPY/D/H/psi's two unswitched siblings, A_COPY/D/H/chi and
5701 # A_COPY/D/H/omega won't inherit r8 from A_COPY/D/H, so need their
5704 # Search for the comment entitled "The Merge Kluge" elsewhere in
5705 # this file, to understand why we shorten and chdir() below.
5706 short_H_COPY_path
= shorten_path_kludge(A_COPY_H_path
)
5707 expected_output
= wc
.State(short_H_COPY_path
, {
5708 'omega' : Item(status
='U ')
5710 expected_status
= wc
.State(short_H_COPY_path
, {
5711 '' : Item(status
=' M', wc_rev
=8),
5712 'psi' : Item(status
=' M', wc_rev
=8, switched
='S'),
5713 'omega' : Item(status
='MM', wc_rev
=8),
5714 'chi' : Item(status
=' M', wc_rev
=8),
5716 expected_disk
= wc
.State('', {
5717 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:8*'}),
5718 'psi' : Item("This is the file 'psi'.\n",
5719 props
={SVN_PROP_MERGEINFO
: '/A/D/H/psi:8'}),
5720 'omega' : Item("New content",
5721 props
={SVN_PROP_MERGEINFO
: '/A/D/H/omega:8'}),
5722 'chi' : Item("This is the file 'chi'.\n",
5723 props
={SVN_PROP_MERGEINFO
: '/A/D/H/chi:8'}),
5725 expected_skip
= wc
.State(short_H_COPY_path
, { })
5726 saved_cwd
= os
.getcwd()
5728 os
.chdir(svntest
.main
.work_dir
)
5730 svntest
.actions
.run_and_verify_merge(short_H_COPY_path
, '7', '8',
5731 sbox
.repo_url
+ '/A/D/H',
5732 expected_output
, expected_disk
,
5733 expected_status
, expected_skip
,
5734 None, None, None, None, None, 1)
5737 # Target with switched dir child:
5739 # Merge r6 from A/D into A_COPY/D. The switched child of A_COPY/D,
5740 # directory A_COPY/D/G (which has no mergeinfo prior to the merge),
5741 # should get its own mergeinfo, both for r6 from the merge itself and
5742 # r1-2 from the repository.
5744 # A_COPY/D/G's parent A_COPY/D has no pre-exiting explicit
5745 # mergeinfo so should get its own mergeinfo, made up of r1 inherited
5746 # from A_COPY and the non-inheritable r5 resulting from the merge.
5748 # A_COPY/D/G's two unswitched siblings, A_COPY/D/gamma and A_COPY/D/H
5749 # won't inherit r5 from A_COPY/D, so need their own mergeinfo
5750 # added/updated respectively. A_COPY/D/H itself has a switched child
5751 # so r5 is set as non-inheritable on it. All of A_COPY/D/H's children,
5752 # which have explict mergeinfo from the previous merge, get r5 in their
5754 short_D_COPY_path
= shorten_path_kludge(A_COPY_D_path
)
5755 expected_output
= wc
.State(short_D_COPY_path
, {
5756 'G/rho' : Item(status
='U ')
5758 expected_status_D
= wc
.State(short_D_COPY_path
, {
5759 '' : Item(status
=' M', wc_rev
=8),
5760 'H' : Item(status
=' M', wc_rev
=8),
5761 'H/chi' : Item(status
=' M', wc_rev
=8),
5762 'H/omega' : Item(status
='MM', wc_rev
=8),
5763 'H/psi' : Item(status
=' M', wc_rev
=8, switched
='S'),
5764 'G' : Item(status
=' M', wc_rev
=8, switched
='S'),
5765 'G/pi' : Item(status
=' M', wc_rev
=8),
5766 'G/rho' : Item(status
='MM', wc_rev
=8, switched
='S'),
5767 'G/tau' : Item(status
=' M', wc_rev
=8),
5768 'gamma' : Item(status
=' M', wc_rev
=8),
5770 expected_disk_D
= wc
.State('', {
5771 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:6*'}),
5772 'H' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:6*,8*'}),
5773 'H/chi' : Item("This is the file 'chi'.\n",
5774 props
={SVN_PROP_MERGEINFO
: '/A/D/H/chi:6,8'}),
5775 'H/omega' : Item("New content",
5776 props
={SVN_PROP_MERGEINFO
: '/A/D/H/omega:6,8'}),
5777 'H/psi' : Item("This is the file 'psi'.\n",
5778 props
={SVN_PROP_MERGEINFO
: '/A/D/H/psi:6,8'}),
5779 'G' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:6*'}),
5780 'G/pi' : Item("This is the file 'pi'.\n",
5781 props
={SVN_PROP_MERGEINFO
: '/A/D/G/pi:6'}),
5782 'G/rho' : Item("New content",
5783 props
={SVN_PROP_MERGEINFO
: '/A/D/G/rho:6'}),
5784 'G/tau' : Item("This is the file 'tau'.\n",
5785 props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:6'}),
5786 'gamma' : Item("This is the file 'gamma'.\n",
5787 props
={SVN_PROP_MERGEINFO
: '/A/D/gamma:6'}),
5789 expected_skip_D
= wc
.State(short_D_COPY_path
, { })
5790 os
.chdir(svntest
.main
.work_dir
)
5791 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '5', '6',
5792 sbox
.repo_url
+ '/A/D',
5793 expected_output
, expected_disk_D
,
5794 expected_status_D
, expected_skip_D
,
5795 None, None, None, None, None, 1)
5797 # Merge r5 from A/D into A_COPY/D. A_COPY/D's switched child A_COPY/D/G
5798 # gets r5 as does A_COPY/D/G's unswitched sibling A_COPY/D/gamma. Since
5799 # A_COPY/D has a switched child, it gets an uninheritable r5. Every other
5800 # path with existing mergeinfo already has r8 so are unchanged.
5802 # A_COPY/D/H/chi and A_COPY/D/H/omega both have mergeinfo for r1,6,8 but
5803 # won't elide to A_COPY/D/H becuase the latter's mergeinfo, while
5804 # encompassing the same ranges, r1,6*,8*, has some non-inheritable ranges.
5805 # The same is true of A_COPY/D/gamma and A_COPY/D.
5806 expected_output
= wc
.State(short_D_COPY_path
, {
5807 'H/psi' : Item(status
='U ')})
5808 expected_disk_D
.tweak('', props
={SVN_PROP_MERGEINFO
: '/A/D:5-6*'})
5809 expected_disk_D
.tweak('G', props
={SVN_PROP_MERGEINFO
: '/A/D/G:5-6*'})
5810 expected_disk_D
.tweak('G/pi',
5811 props
={SVN_PROP_MERGEINFO
: '/A/D/G/pi:5-6'})
5812 expected_disk_D
.tweak('G/rho',
5813 props
={SVN_PROP_MERGEINFO
: '/A/D/G/rho:5-6'})
5814 expected_disk_D
.tweak('G/tau',
5815 props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:5-6'})
5816 expected_disk_D
.tweak('H', props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-6*,8*'})
5817 expected_disk_D
.tweak('gamma',
5818 props
={SVN_PROP_MERGEINFO
: '/A/D/gamma:5-6'})
5819 expected_disk_D
.tweak('H/chi',
5820 props
={SVN_PROP_MERGEINFO
:'/A/D/H/chi:5-6,8'})
5821 expected_disk_D
.tweak('H/psi', contents
="New content",
5822 props
={SVN_PROP_MERGEINFO
:'/A/D/H/psi:5-6,8'})
5823 expected_disk_D
.tweak('H/omega',
5824 props
={SVN_PROP_MERGEINFO
:'/A/D/H/omega:5-6,8'})
5825 expected_status_D
.tweak('H/psi', status
='MM')
5826 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '4', '5',
5827 sbox
.repo_url
+ '/A/D',
5828 expected_output
, expected_disk_D
,
5829 expected_status_D
, expected_skip_D
,
5830 None, None, None, None, None, 1)
5833 # Finally, merge r4:8 into A_COPY. A_COPY gets r5-8 added and every path
5834 # under it with with explicit mergeinfo gets r5,7 added (they all have r6,8
5835 # already). Again there is no elision, since the only possibilities, e.g.
5836 # A_COPY/D/H's '/A/D/H:1,5-8*' to A_COPY/D's '/A/D:1,5-8*', involve
5837 # non-inheritable mergeinfo one ond side or the other.
5838 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
5839 expected_output
= wc
.State(short_A_COPY_path
, {
5840 'B/E/beta' : Item(status
='U ')
5842 expected_status
= wc
.State(short_A_COPY_path
, {
5843 '' : Item(status
=' M', wc_rev
=8),
5844 'B' : Item(status
=' ', wc_rev
=8),
5845 'mu' : Item(status
=' ', wc_rev
=8),
5846 'B/E' : Item(status
=' ', wc_rev
=8),
5847 'B/E/alpha' : Item(status
=' ', wc_rev
=8),
5848 'B/E/beta' : Item(status
='M ', wc_rev
=8),
5849 'B/lambda' : Item(status
=' ', wc_rev
=8),
5850 'B/F' : Item(status
=' ', wc_rev
=8),
5851 'C' : Item(status
=' ', wc_rev
=8),
5852 'D' : Item(status
=' M', wc_rev
=8),
5853 'D/G' : Item(status
=' M', wc_rev
=8, switched
='S'),
5854 'D/G/pi' : Item(status
=' M', wc_rev
=8),
5855 'D/G/rho' : Item(status
='MM', wc_rev
=8, switched
='S'),
5856 'D/G/tau' : Item(status
=' M', wc_rev
=8),
5857 'D/gamma' : Item(status
=' M', wc_rev
=8),
5858 'D/H' : Item(status
=' M', wc_rev
=8),
5859 'D/H/chi' : Item(status
=' M', wc_rev
=8),
5860 'D/H/psi' : Item(status
='MM', wc_rev
=8, switched
='S'),
5861 'D/H/omega' : Item(status
='MM', wc_rev
=8),
5863 expected_disk
= wc
.State('', {
5864 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5-8'}),
5866 'mu' : Item("This is the file 'mu'.\n"),
5868 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
5869 'B/E/beta' : Item("New content"),
5870 'B/lambda' : Item("This is the file 'lambda'.\n"),
5873 'D' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:5-8*'}),
5874 'D/G' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:5-8*'}),
5875 'D/G/pi' : Item("This is the file 'pi'.\n",
5876 props
={SVN_PROP_MERGEINFO
: '/A/D/G/pi:5-8'}),
5877 'D/G/rho' : Item("New content",
5878 props
={SVN_PROP_MERGEINFO
: '/A/D/G/rho:5-8'}),
5879 'D/G/tau' : Item("This is the file 'tau'.\n",
5880 props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:5-8'}),
5881 'D/gamma' : Item("This is the file 'gamma'.\n",
5882 props
={SVN_PROP_MERGEINFO
: '/A/D/gamma:5-8'}),
5883 'D/H' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-8*'}),
5884 'D/H/chi' : Item("This is the file 'chi'.\n",
5885 props
={SVN_PROP_MERGEINFO
: '/A/D/H/chi:5-8'}),
5886 'D/H/psi' : Item("New content",
5887 props
={SVN_PROP_MERGEINFO
: '/A/D/H/psi:5-8'}),
5888 'D/H/omega' : Item("New content",
5889 props
={SVN_PROP_MERGEINFO
: '/A/D/H/omega:5-8'}),
5891 expected_skip
= wc
.State(short_A_COPY_path
, { })
5892 os
.chdir(svntest
.main
.work_dir
)
5893 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '4', '8',
5894 sbox
.repo_url
+ '/A',
5895 expected_output
, expected_disk
,
5896 expected_status
, expected_skip
,
5897 None, None, None, None, None, 1)
5901 # Commit changes thus far.
5902 expected_output
= svntest
.wc
.State(wc_dir
, {
5903 'A_COPY' : Item(verb
='Sending'),
5904 'A_COPY/B/E/beta' : Item(verb
='Sending'),
5905 'A_COPY/D' : Item(verb
='Sending'),
5906 'A_COPY/D/gamma' : Item(verb
='Sending'),
5907 'A_COPY/D/G' : Item(verb
='Sending'),
5908 'A_COPY/D/G/pi' : Item(verb
='Sending'),
5909 'A_COPY/D/G/rho' : Item(verb
='Sending'),
5910 'A_COPY/D/G/tau' : Item(verb
='Sending'),
5911 'A_COPY/D/H' : Item(verb
='Sending'),
5912 'A_COPY/D/H/chi' : Item(verb
='Sending'),
5913 'A_COPY/D/H/omega' : Item(verb
='Sending'),
5914 'A_COPY/D/H/psi' : Item(verb
='Sending'),
5916 wc_status
.tweak('A_COPY', 'A_COPY/B/E/beta', 'A_COPY/D', 'A_COPY/D/gamma',
5917 'A_COPY/D/G', 'A_COPY/D/G/pi', 'A_COPY/D/G/rho',
5918 'A_COPY/D/G/tau','A_COPY/D/H', 'A_COPY/D/H/chi',
5919 'A_COPY/D/H/omega', 'A_COPY/D/H/psi',
5921 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
5924 # Unswitch A_COPY/D/H/psi.
5925 expected_output
= svntest
.wc
.State(wc_dir
, {
5926 'A_COPY/D/H/psi' : Item(status
='UU')})
5927 wc_status
.tweak("A_COPY/D/H/psi", switched
=None, wc_rev
=9)
5928 wc_disk
.tweak("A_COPY",
5929 props
={SVN_PROP_MERGEINFO
: '/A:5-8'})
5930 wc_disk
.tweak("A_COPY/B/E/beta",
5931 contents
="New content")
5932 wc_disk
.tweak("A_COPY/D",
5933 props
={SVN_PROP_MERGEINFO
: '/A/D:5-8*'})
5934 wc_disk
.tweak("A_COPY/D/gamma",
5935 props
={SVN_PROP_MERGEINFO
: '/A/D/gamma:5-8'})
5936 wc_disk
.tweak("A_COPY/D/G",
5937 props
={SVN_PROP_MERGEINFO
: '/A/D/G:5-8*'})
5938 wc_disk
.tweak("A_COPY/D/G/pi",
5939 props
={SVN_PROP_MERGEINFO
: '/A/D/G/pi:5-8'})
5940 wc_disk
.tweak("A_COPY/D/G/rho",
5941 contents
="New content",
5942 props
={SVN_PROP_MERGEINFO
: '/A/D/G/rho:5-8'})
5943 wc_disk
.tweak("A_COPY/D/G/tau",
5944 props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:5-8'})
5945 wc_disk
.tweak("A_COPY/D/H",
5946 props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-8*'})
5947 wc_disk
.tweak("A_COPY/D/H/chi",
5948 props
={SVN_PROP_MERGEINFO
: '/A/D/H/chi:5-8'})
5949 wc_disk
.tweak("A_COPY/D/H/omega",
5950 contents
="New content",
5951 props
={SVN_PROP_MERGEINFO
: '/A/D/H/omega:5-8'})
5952 wc_disk
.tweak("A_COPY_2", props
={})
5953 svntest
.actions
.run_and_verify_switch(sbox
.wc_dir
, A_COPY_psi_path
,
5954 sbox
.repo_url
+ "/A_COPY/D/H/psi",
5955 expected_output
, wc_disk
, wc_status
,
5956 None, None, None, None, None, 1)
5958 # Non-inheritable mergeinfo ranges on a target don't prevent repeat
5959 # merges of that range on the target's children.
5961 # Non-inheritable mergeinfo ranges on a target are removed if the target
5962 # no longer has any switched children and a repeat merge is performed.
5964 # Merge r4:8 from A/D/H into A_COPY/D/H. A_COPY/D/H already has mergeinfo
5965 # for r4:8 but it is marked as uninheritable so the repeat merge is
5966 # allowed on its children, notably the now unswitched A_COPY/D/H/psi.
5967 # Since A_COPY/D/H no longer has any switched children and the merge of
5968 # r4:8 has been repeated the previously uninheritable ranges 5-8* on
5969 # A_COPY/D/H are made inheritable. This also means that the mergeinfo on
5970 # A_COPY/D/H's children will elide to it.
5971 short_H_COPY_path
= shorten_path_kludge(A_COPY_H_path
)
5972 expected_output
= wc
.State(short_H_COPY_path
, {
5973 'psi' : Item(status
='U ')
5975 expected_status
= wc
.State(short_H_COPY_path
, {
5976 '' : Item(status
=' M', wc_rev
=9),
5977 'psi' : Item(status
='M ', wc_rev
=9),
5978 'omega' : Item(status
=' M', wc_rev
=9),
5979 'chi' : Item(status
=' M', wc_rev
=9),
5981 expected_disk
= wc
.State('', {
5982 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-8'}),
5983 'psi' : Item("New content"),
5984 'omega' : Item("New content"),
5985 'chi' : Item("This is the file 'chi'.\n"),
5987 expected_skip
= wc
.State(short_H_COPY_path
, { })
5988 os
.chdir(svntest
.main
.work_dir
)
5989 svntest
.actions
.run_and_verify_merge(short_H_COPY_path
, '4', '8',
5990 sbox
.repo_url
+ '/A/D/H',
5991 expected_output
, expected_disk
,
5992 expected_status
, expected_skip
,
5993 None, None, None, None, None, 1)
5996 # Non-inheritable mergeinfo ranges on a target do prevent repeat
5997 # merges on the target itself.
5999 # Add a prop A/D and commit it as r10. Merge r10 into A_COPY/D. Since
6000 # A_COPY/D has a switched child it gets r10 added as a non-inheritable
6001 # range. Repeat the same merge checking that no repeat merge is
6002 # attempted on A_COPY/D.
6003 svntest
.actions
.run_and_verify_svn(None,
6004 ["property 'prop:name' set on '" +
6005 D_path
+ "'\n"], [], 'ps',
6006 'prop:name', 'propval', D_path
)
6007 expected_output
= svntest
.wc
.State(wc_dir
, {
6008 'A/D' : Item(verb
='Sending'),
6009 'A_COPY/D/H' : Item(verb
='Sending'),
6010 'A_COPY/D/H/chi' : Item(verb
='Sending'),
6011 'A_COPY/D/H/psi' : Item(verb
='Sending'),
6012 'A_COPY/D/H/omega' : Item(verb
='Sending'),
6014 wc_status
.tweak('A_COPY/D', wc_rev
=9)
6015 wc_status
.tweak('A/D', 'A_COPY/D/H', 'A_COPY/D/H/chi', 'A_COPY/D/H/psi',
6016 'A_COPY/D/H/omega', wc_rev
=10)
6017 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
6019 expected_output
= wc
.State(short_D_COPY_path
, {
6020 '' : Item(status
=' U')
6022 # Reuse expected status and disk from last merge to A_COPY/D
6023 expected_status_D
.tweak('', 'gamma', status
=' M', wc_rev
=9)
6024 expected_status_D
.tweak('H', status
=' M', wc_rev
=10)
6025 expected_status_D
.tweak('H/psi', 'H/chi', 'H/omega', status
=' ', wc_rev
=10,
6027 expected_status_D
.tweak('G', switched
='S', status
=' M', wc_rev
=9)
6028 expected_status_D
.tweak('G/tau', 'G/pi', 'G/rho', status
=' M', wc_rev
=9)
6029 expected_disk_D
.tweak('', props
={SVN_PROP_MERGEINFO
: '/A/D:5-8*,10*',
6030 "prop:name" : "propval"})
6031 expected_disk_D
.tweak('G',
6032 props
={SVN_PROP_MERGEINFO
: '/A/D/G:5-8*,10*'})
6033 expected_disk_D
.tweak('G/pi',
6034 props
={SVN_PROP_MERGEINFO
: '/A/D/G/pi:5-8,10'})
6035 expected_disk_D
.tweak('G/rho',
6036 props
={SVN_PROP_MERGEINFO
: '/A/D/G/rho:5-8,10'})
6037 expected_disk_D
.tweak('G/tau',
6038 props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:5-8,10'})
6039 expected_disk_D
.tweak('H', props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-8,10'})
6040 expected_disk_D
.tweak('gamma',
6041 props
={SVN_PROP_MERGEINFO
: '/A/D/gamma:5-8,10'})
6042 expected_disk_D
.tweak('H/chi', 'H/omega', props
={})
6043 expected_disk_D
.tweak('H/psi', contents
="New content", props
={})
6044 os
.chdir(svntest
.main
.work_dir
)
6045 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '9', '10',
6046 sbox
.repo_url
+ '/A/D',
6047 expected_output
, expected_disk_D
,
6048 expected_status_D
, expected_skip_D
,
6049 None, None, None, None, None, 1)
6050 # Repeated merge is a no-op.
6051 expected_output
= wc
.State(short_D_COPY_path
, {})
6052 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '9', '10',
6053 sbox
.repo_url
+ '/A/D',
6054 expected_output
, expected_disk_D
,
6055 expected_status_D
, expected_skip_D
,
6056 None, None, None, None, None, 1)
6060 # Test for issue 2047: Merge from parent dir fails while it succeeds from
6062 def merge_with_implicit_target_file(sbox
):
6063 "merge a change to a file, using relative path"
6066 wc_dir
= sbox
.wc_dir
6068 # Make a change to A/mu, then revert it using 'svn merge -r 2:1 A/mu'
6070 # change A/mu and commit
6071 A_path
= os
.path
.join(wc_dir
, 'A')
6072 mu_path
= os
.path
.join(A_path
, 'mu')
6074 svntest
.main
.file_append(mu_path
, "A whole new line.\n")
6076 expected_output
= svntest
.wc
.State(wc_dir
, {
6077 'A/mu' : Item(verb
='Sending'),
6079 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
6080 expected_status
.tweak('A/mu', wc_rev
=2)
6081 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6082 expected_status
, None, wc_dir
)
6084 # Update to revision 2.
6085 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
6087 # Revert the change committed in r2
6090 # run_and_verify_merge doesn't accept file paths.
6091 svntest
.actions
.run_and_verify_svn(None, None, [], 'merge', '-r', '2:1',
6094 # Test practical application of issue #2769 fix, empty rev range elision,
6095 # and elision to the repos.
6096 def empty_mergeinfo(sbox
):
6097 "mergeinfo can explicitly be empty"
6099 # A bit o' history: The fix for issue #2769 originally permitted mergeinfo
6100 # with empty range lists and as a result we permitted partial elision and
6101 # had a whole slew of tests here for that. But the fix of issue #3029 now
6102 # prevents svn ps or svn merge from creating mergeinfo with paths mapped to
6103 # empty ranges, only empty mergeinfo is allowed. As a result this test now
6104 # covers the following areas:
6106 # A) Merging a set of revisions into a path, then reverse merging the
6107 # same set out of a subtree of path results in empty mergeinfo
6108 # (i.e. "") on the subtree.
6110 # B) Empty mergeinfo elides to empty mergeinfo.
6112 # C) If a merge sets empty mergeinfo on its target and that target has
6113 # no ancestor in either the WC or the repository with explict
6114 # mergeinfo, then the target's mergeinfo is removed (a.k.a. elides
6117 wc_dir
= sbox
.wc_dir
6118 wc_disk
, wc_status
= set_up_branch(sbox
)
6120 # Some paths we'll care about
6121 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
6122 H_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H")
6123 psi_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "psi")
6124 rho_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "rho")
6126 # Test area A -- Merge r2:4 into A_COPY then reverse merge 4:2 to
6127 # A_COPY/D/G. A_COPY/D/G should end up with empty mergeinfo to
6128 # override that of A_COPY.
6130 # Search for the comment entitled "The Merge Kluge" elsewhere in
6131 # this file, to understand why we shorten and chdir() below.
6132 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
6133 expected_output
= wc
.State(short_A_COPY_path
, {
6134 'D/H/psi' : Item(status
='U '),
6135 'D/G/rho' : Item(status
='U '),
6137 expected_status
= wc
.State(short_A_COPY_path
, {
6138 '' : Item(status
=' M', wc_rev
=2),
6139 'B' : Item(status
=' ', wc_rev
=2),
6140 'mu' : Item(status
=' ', wc_rev
=2),
6141 'B/E' : Item(status
=' ', wc_rev
=2),
6142 'B/E/alpha' : Item(status
=' ', wc_rev
=2),
6143 'B/E/beta' : Item(status
=' ', wc_rev
=2),
6144 'B/lambda' : Item(status
=' ', wc_rev
=2),
6145 'B/F' : Item(status
=' ', wc_rev
=2),
6146 'C' : Item(status
=' ', wc_rev
=2),
6147 'D' : Item(status
=' ', wc_rev
=2),
6148 'D/G' : Item(status
=' ', wc_rev
=2),
6149 'D/G/pi' : Item(status
=' ', wc_rev
=2),
6150 'D/G/rho' : Item(status
='M ', wc_rev
=2),
6151 'D/G/tau' : Item(status
=' ', wc_rev
=2),
6152 'D/gamma' : Item(status
=' ', wc_rev
=2),
6153 'D/H' : Item(status
=' ', wc_rev
=2),
6154 'D/H/chi' : Item(status
=' ', wc_rev
=2),
6155 'D/H/psi' : Item(status
='M ', wc_rev
=2),
6156 'D/H/omega' : Item(status
=' ', wc_rev
=2),
6158 expected_disk
= wc
.State('', {
6159 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:3-4'}),
6161 'mu' : Item("This is the file 'mu'.\n"),
6163 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
6164 'B/E/beta' : Item("This is the file 'beta'.\n"),
6165 'B/lambda' : Item("This is the file 'lambda'.\n"),
6170 'D/G/pi' : Item("This is the file 'pi'.\n"),
6171 'D/G/rho' : Item("New content"),
6172 'D/G/tau' : Item("This is the file 'tau'.\n"),
6173 'D/gamma' : Item("This is the file 'gamma'.\n"),
6175 'D/H/chi' : Item("This is the file 'chi'.\n"),
6176 'D/H/psi' : Item("New content"),
6177 'D/H/omega' : Item("This is the file 'omega'.\n"),
6179 expected_skip
= wc
.State(short_A_COPY_path
, { })
6180 saved_cwd
= os
.getcwd()
6181 os
.chdir(svntest
.main
.work_dir
)
6182 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '2', '4',
6189 None, None, None, None,
6191 # Now do the reverse merge into the subtree.
6192 short_H_COPY_path
= shorten_path_kludge(H_COPY_path
)
6193 expected_output
= wc
.State(short_H_COPY_path
, {
6194 'psi' : Item(status
='G '),
6196 expected_status
= wc
.State(short_H_COPY_path
, {
6197 '' : Item(status
=' M', wc_rev
=2),
6198 'chi' : Item(status
=' ', wc_rev
=2),
6199 'psi' : Item(status
=' ', wc_rev
=2),
6200 'omega' : Item(status
=' ', wc_rev
=2),
6202 expected_disk
= wc
.State('', {
6203 '' : Item(props
={SVN_PROP_MERGEINFO
: ''}),
6204 'chi' : Item("This is the file 'chi'.\n"),
6205 'psi' : Item("This is the file 'psi'.\n"),
6206 'omega' : Item("This is the file 'omega'.\n"),
6208 expected_skip
= wc
.State(short_H_COPY_path
, { })
6209 svntest
.actions
.run_and_verify_merge(short_H_COPY_path
, '4', '2',
6216 None, None, None, None,
6219 # Test areas B and C -- Reverse merge r3 into A_COPY, this would result in
6220 # empty mergeinfo on A_COPY and A_COPY/D/H, but the empty mergeinfo on the
6221 # latter elides to the former. And then the empty mergeinfo on A_COPY,
6222 # which has no parent with explicit mergeinfo to override (in either the WC
6223 # or the repos) itself elides. This leaves the WC in the same unmodified
6224 # state as after the call to set_up_branch().
6225 short_rho_COPY_path
= shorten_path_kludge(rho_COPY_path
)
6226 expected_output
= expected_merge_output(
6227 [[4,3]], 'G ' + short_rho_COPY_path
+ '\n')
6228 svntest
.actions
.run_and_verify_svn(None, expected_output
,
6229 [], 'merge', '-r4:2',
6230 sbox
.repo_url
+ '/A',
6233 svntest
.actions
.run_and_verify_status(wc_dir
, wc_status
)
6234 # Check that A_COPY's mergeinfo is gone.
6235 svntest
.actions
.run_and_verify_svn(None, [], [], 'pg', 'svn:mergeinfo',
6238 def prop_add_to_child_with_mergeinfo(sbox
):
6239 "merge adding prop to child of merge target works"
6241 # Test for Issue #2781 Prop add to child of merge target corrupts WC if
6242 # child has mergeinfo.
6245 wc_dir
= sbox
.wc_dir
6246 expected_disk
, expected_status
= set_up_branch(sbox
)
6248 # Some paths we'll care about
6249 beta_path
= os
.path
.join(wc_dir
, "A", "B", "E", "beta")
6250 beta_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B", "E", "beta")
6251 B_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B")
6253 # Set a non-mergeinfo prop on a file.
6254 svntest
.actions
.run_and_verify_svn(None,
6255 ["property 'prop:name' set on '" +
6256 beta_path
+ "'\n"], [], 'ps',
6257 'prop:name', 'propval', beta_path
)
6258 expected_disk
.tweak('A/B/E/beta', props
={'prop:name' : 'propval'})
6259 expected_status
.tweak('A/B/E/beta', wc_rev
=7)
6260 expected_output
= wc
.State(wc_dir
,
6261 {'A/B/E/beta' : Item(verb
='Sending')})
6262 svntest
.actions
.run_and_verify_commit(wc_dir
,
6268 # Merge r4:5 from A/B/E/beta into A_COPY/B/E/beta.
6269 short_beta_COPY_path
= shorten_path_kludge(beta_COPY_path
)
6270 saved_cwd
= os
.getcwd()
6271 os
.chdir(svntest
.main
.work_dir
)
6272 svntest
.actions
.run_and_verify_svn(None,
6273 expected_merge_output([[5]],
6274 'U ' + short_beta_COPY_path
+'\n'),
6276 sbox
.repo_url
+ '/A/B/E/beta',
6277 short_beta_COPY_path
)
6280 # Merge r6:7 into A_COPY/B. In issue #2781 this adds a bogus
6281 # and incomplete entry in A_COPY/B/.svn/entries for 'beta'.
6282 short_B_COPY_path
= shorten_path_kludge(B_COPY_path
)
6283 expected_output
= wc
.State(short_B_COPY_path
, {
6284 'E/beta' : Item(status
=' U'),
6286 expected_status
= wc
.State(short_B_COPY_path
, {
6287 '' : Item(status
=' M', wc_rev
=2),
6288 'E' : Item(status
=' ', wc_rev
=2),
6289 'E/alpha' : Item(status
=' ', wc_rev
=2),
6290 'E/beta' : Item(status
='MM', wc_rev
=2),
6291 'lambda' : Item(status
=' ', wc_rev
=2),
6292 'F' : Item(status
=' ', wc_rev
=2),
6294 expected_disk
= wc
.State('', {
6295 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:7'}),
6297 'E/alpha' : Item("This is the file 'alpha'.\n"),
6298 'E/beta' : Item(contents
="New content",
6299 props
={SVN_PROP_MERGEINFO
: '/A/B/E/beta:5,7',
6300 'prop:name' : 'propval'}),
6302 'lambda' : Item("This is the file 'lambda'.\n")
6304 expected_skip
= wc
.State(short_B_COPY_path
, { })
6305 os
.chdir(svntest
.main
.work_dir
)
6306 svntest
.actions
.run_and_verify_merge(short_B_COPY_path
, '6', '7',
6313 None, None, None, None,
6316 def diff_repos_does_not_update_mergeinfo(sbox
):
6317 "don't set mergeinfo when merging from another repo"
6319 # Test for issue #2788.
6322 wc_dir
= sbox
.wc_dir
6323 expected_disk
, expected_status
= set_up_branch(sbox
)
6325 # Create a second repository with the same greek tree
6326 repo_dir
= sbox
.repo_dir
6327 other_repo_dir
, other_repo_url
= sbox
.add_repo_path("other")
6328 svntest
.main
.copy_repos(repo_dir
, other_repo_dir
, 6, 1)
6330 # Merge r3:4 (using implied peg revisions) from 'other' repos into
6331 # A_COPY/D/G. Merge should succeed, but no mergeinfo should be set.
6333 # Search for the comment entitled "The Merge Kluge" elsewhere in
6334 # this file, to understand why we shorten and chdir() below.
6335 short_G_COPY_path
= shorten_path_kludge(os
.path
.join(wc_dir
,
6336 "A_COPY", "D", "G"))
6337 saved_cwd
= os
.getcwd()
6339 os
.chdir(svntest
.main
.work_dir
)
6340 svntest
.actions
.run_and_verify_svn(None,
6341 expected_merge_output([[4]],
6343 os
.path
.join(short_G_COPY_path
,
6346 other_repo_url
+ '/A/D/G',
6350 # Merge r4:5 (using explicit peg revisions) from 'other' repos into
6351 # A_COPY/B/E. Merge should succeed, but no mergeinfo should be set.
6352 short_E_COPY_path
= shorten_path_kludge(os
.path
.join(wc_dir
,
6353 "A_COPY", "B", "E"))
6355 os
.chdir(svntest
.main
.work_dir
)
6356 svntest
.actions
.run_and_verify_svn(None,
6357 expected_merge_output([[5]],
6359 os
.path
.join(short_E_COPY_path
,
6362 other_repo_url
+ '/A/B/E@4',
6363 other_repo_url
+ '/A/B/E@5',
6367 expected_status
.tweak('A_COPY/D/G/rho', 'A_COPY/B/E/beta', status
='M ')
6368 svntest
.actions
.run_and_verify_status(wc_dir
, expected_status
)
6370 def avoid_reflected_revs(sbox
):
6371 "avoid repeated merges for cyclic merging"
6373 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2897. ##
6375 # Create a WC with a single branch
6377 wc_dir
= sbox
.wc_dir
6378 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
6380 # Some paths we'll care about
6381 A_path
= os
.path
.join(wc_dir
, 'A')
6382 A_COPY_path
= os
.path
.join(wc_dir
, 'A_COPY')
6383 tfile1_path
= os
.path
.join(wc_dir
, 'A', 'tfile1')
6384 tfile2_path
= os
.path
.join(wc_dir
, 'A', 'tfile2')
6385 bfile1_path
= os
.path
.join(A_COPY_path
, 'bfile1')
6386 bfile2_path
= os
.path
.join(A_COPY_path
, 'bfile2')
6388 # Contents to be added to files
6389 tfile1_content
= "This is tfile1\n"
6390 tfile2_content
= "This is tfile2\n"
6391 bfile1_content
= "This is bfile1\n"
6392 bfile2_content
= "This is bfile2\n"
6394 # We'll consider A as the trunk and A_COPY as the feature branch
6395 # Create a tfile1 in A
6396 svntest
.main
.file_write(tfile1_path
, tfile1_content
)
6397 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', tfile1_path
)
6398 expected_output
= wc
.State(wc_dir
, {'A/tfile1' : Item(verb
='Adding')})
6399 wc_status
.add({'A/tfile1' : Item(status
=' ', wc_rev
=3)})
6400 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6401 wc_status
, None, wc_dir
)
6403 # Create a bfile1 in A_COPY
6404 svntest
.main
.file_write(bfile1_path
, bfile1_content
)
6405 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', bfile1_path
)
6406 expected_output
= wc
.State(wc_dir
, {'A_COPY/bfile1' : Item(verb
='Adding')})
6407 wc_status
.add({'A_COPY/bfile1' : Item(status
=' ', wc_rev
=4)})
6408 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6409 wc_status
, None, wc_dir
)
6411 # Create one more file in A
6412 svntest
.main
.file_write(tfile2_path
, tfile2_content
)
6413 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', tfile2_path
)
6414 expected_output
= wc
.State(wc_dir
, {'A/tfile2' : Item(verb
='Adding')})
6415 wc_status
.add({'A/tfile2' : Item(status
=' ', wc_rev
=5)})
6416 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6417 wc_status
, None, wc_dir
)
6419 short_A_COPY
= shorten_path_kludge(A_COPY_path
)
6420 saved_cwd
= os
.getcwd()
6421 os
.chdir(svntest
.main
.work_dir
)
6423 # Merge r5 from /A to /A_COPY, creating r6
6424 expected_output
= wc
.State(short_A_COPY
, {
6425 'tfile2' : Item(status
='A '),
6427 expected_status
= wc
.State(short_A_COPY
, {
6428 '' : Item(status
=' M', wc_rev
=2),
6429 'tfile2' : Item(status
='A ', wc_rev
='-', copied
='+'),
6430 'bfile1' : Item(status
=' ', wc_rev
=4),
6431 'mu' : Item(status
=' ', wc_rev
=2),
6432 'C' : Item(status
=' ', wc_rev
=2),
6433 'D' : Item(status
=' ', wc_rev
=2),
6434 'B' : Item(status
=' ', wc_rev
=2),
6435 'B/lambda' : Item(status
=' ', wc_rev
=2),
6436 'B/E' : Item(status
=' ', wc_rev
=2),
6437 'B/E/alpha': Item(status
=' ', wc_rev
=2),
6438 'B/E/beta' : Item(status
=' ', wc_rev
=2),
6439 'B/F' : Item(status
=' ', wc_rev
=2),
6440 'D/gamma' : Item(status
=' ', wc_rev
=2),
6441 'D/G' : Item(status
=' ', wc_rev
=2),
6442 'D/G/pi' : Item(status
=' ', wc_rev
=2),
6443 'D/G/rho' : Item(status
=' ', wc_rev
=2),
6444 'D/G/tau' : Item(status
=' ', wc_rev
=2),
6445 'D/H' : Item(status
=' ', wc_rev
=2),
6446 'D/H/chi' : Item(status
=' ', wc_rev
=2),
6447 'D/H/omega': Item(status
=' ', wc_rev
=2),
6448 'D/H/psi' : Item(status
=' ', wc_rev
=2),
6450 expected_disk
= wc
.State('', {
6451 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5'}),
6452 'tfile2' : Item(tfile2_content
),
6453 'bfile1' : Item(bfile1_content
),
6454 'mu' : Item("This is the file 'mu'.\n"),
6458 'B/lambda' : Item("This is the file 'lambda'.\n"),
6460 'B/E/alpha': Item("This is the file 'alpha'.\n"),
6461 'B/E/beta' : Item("This is the file 'beta'.\n"),
6463 'D/gamma' : Item("This is the file 'gamma'.\n"),
6465 'D/G/pi' : Item("This is the file 'pi'.\n"),
6466 'D/G/rho' : Item("This is the file 'rho'.\n"),
6467 'D/G/tau' : Item("This is the file 'tau'.\n"),
6469 'D/H/chi' : Item("This is the file 'chi'.\n"),
6470 'D/H/omega': Item("This is the file 'omega'.\n"),
6471 'D/H/psi' : Item("This is the file 'psi'.\n"),
6473 expected_skip
= wc
.State(short_A_COPY
, {})
6475 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '4', '5',
6476 sbox
.repo_url
+ '/A',
6481 None, None, None, None, None, 1)
6484 # Sync up with the trunk ie., A
6485 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
6486 expected_output
= wc
.State(wc_dir
, {
6487 'A_COPY' : Item(verb
='Sending'),
6488 'A_COPY/tfile2' : Item(verb
='Adding'),
6490 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6492 os
.chdir(svntest
.main
.work_dir
)
6494 # Merge r3 from /A to /A_COPY, creating r7
6495 expected_output
= wc
.State(short_A_COPY
, {
6496 'tfile1' : Item(status
='A '),
6498 expected_status
.tweak(wc_rev
=5)
6499 expected_status
.tweak('', wc_rev
=6)
6500 expected_status
.tweak('tfile2', status
=' ', copied
=None, wc_rev
=6)
6501 expected_status
.add({
6502 'tfile1' : Item(status
='A ', wc_rev
='-', copied
='+'),
6504 expected_disk
.tweak('', props
={SVN_PROP_MERGEINFO
: '/A:3,5'})
6506 'tfile1' : Item(tfile1_content
),
6509 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '2', '3',
6510 sbox
.repo_url
+ '/A',
6515 None, None, None, None, None, 1)
6519 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
6520 expected_output
= wc
.State(wc_dir
, {
6521 'A_COPY' : Item(verb
='Sending'),
6522 'A_COPY/tfile1' : Item(verb
='Adding'),
6524 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6527 # Add bfile2 to A_COPY
6528 svntest
.main
.file_write(bfile2_path
, bfile2_content
)
6529 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', bfile2_path
)
6530 expected_output
= wc
.State(wc_dir
, {'A_COPY/bfile2' : Item(verb
='Adding')})
6531 wc_status
.tweak(wc_rev
=6)
6533 'A_COPY/bfile2' : Item(status
=' ', wc_rev
=8),
6534 'A_COPY' : Item(status
=' ', wc_rev
=7),
6535 'A_COPY/tfile2' : Item(status
=' ', wc_rev
=6),
6536 'A_COPY/tfile1' : Item(status
=' ', wc_rev
=7),
6538 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
6539 wc_status
, None, wc_dir
)
6541 # Merge 2:8 from A_COPY(feature branch) to A(trunk).
6542 short_A_path
= shorten_path_kludge(A_path
)
6543 expected_output
= wc
.State(short_A_path
, {
6544 'bfile2' : Item(status
='A '),
6545 'bfile1' : Item(status
='A '),
6547 expected_status
= wc
.State(short_A_path
, {
6548 '' : Item(status
=' M', wc_rev
=6),
6549 'bfile2' : Item(status
='A ', wc_rev
='-', copied
='+'),
6550 'bfile1' : Item(status
='A ', wc_rev
='-', copied
='+'),
6551 'tfile2' : Item(status
=' ', wc_rev
=6),
6552 'tfile1' : Item(status
=' ', wc_rev
=6),
6553 'mu' : Item(status
=' ', wc_rev
=6),
6554 'C' : Item(status
=' ', wc_rev
=6),
6555 'D' : Item(status
=' ', wc_rev
=6),
6556 'B' : Item(status
=' ', wc_rev
=6),
6557 'B/lambda' : Item(status
=' ', wc_rev
=6),
6558 'B/E' : Item(status
=' ', wc_rev
=6),
6559 'B/E/alpha' : Item(status
=' ', wc_rev
=6),
6560 'B/E/beta' : Item(status
=' ', wc_rev
=6),
6561 'B/F' : Item(status
=' ', wc_rev
=6),
6562 'D/gamma' : Item(status
=' ', wc_rev
=6),
6563 'D/G' : Item(status
=' ', wc_rev
=6),
6564 'D/G/pi' : Item(status
=' ', wc_rev
=6),
6565 'D/G/rho' : Item(status
=' ', wc_rev
=6),
6566 'D/G/tau' : Item(status
=' ', wc_rev
=6),
6567 'D/H' : Item(status
=' ', wc_rev
=6),
6568 'D/H/chi' : Item(status
=' ', wc_rev
=6),
6569 'D/H/omega' : Item(status
=' ', wc_rev
=6),
6570 'D/H/psi' : Item(status
=' ', wc_rev
=6),
6572 expected_disk
= wc
.State('', {
6573 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A_COPY:3-8'}),
6574 'bfile2' : Item(bfile2_content
),
6575 'bfile1' : Item(bfile1_content
),
6576 'tfile2' : Item(tfile2_content
),
6577 'tfile1' : Item(tfile1_content
),
6578 'mu' : Item("This is the file 'mu'.\n"),
6582 'B/lambda' : Item("This is the file 'lambda'.\n"),
6584 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
6585 'B/E/beta' : Item("This is the file 'beta'.\n"),
6587 'D/gamma' : Item("This is the file 'gamma'.\n"),
6589 'D/G/pi' : Item("This is the file 'pi'.\n"),
6590 'D/G/rho' : Item("This is the file 'rho'.\n"),
6591 'D/G/tau' : Item("This is the file 'tau'.\n"),
6593 'D/H/chi' : Item("This is the file 'chi'.\n"),
6594 'D/H/omega' : Item("This is the file 'omega'.\n"),
6595 'D/H/psi' : Item("This is the file 'psi'.\n"),
6598 expected_skip
= wc
.State(short_A_path
, {})
6599 saved_cwd
= os
.getcwd()
6600 os
.chdir(svntest
.main
.work_dir
)
6602 svntest
.actions
.run_and_verify_merge(short_A_path
, '2', '8',
6603 sbox
.repo_url
+ '/A_COPY',
6608 None, None, None, None, None, 1)
6612 def update_loses_mergeinfo(sbox
):
6613 "update does not merge mergeinfo"
6616 When a working copy receives a fresh svn:mergeinfo property due to update,
6617 and working copy has some local mergeinfo(yet to be added), local mergeinfo
6622 wc_dir
= sbox
.wc_dir
6623 A_C_wc_dir
= wc_dir
+ '/A/C'
6624 A_B_url
= sbox
.repo_url
+ '/A/B'
6625 A_B_J_url
= sbox
.repo_url
+ '/A/B/J'
6626 A_B_K_url
= sbox
.repo_url
+ '/A/B/K'
6627 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 2.\n'],
6629 'mkdir', '-m', 'rev 2', A_B_J_url
)
6630 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 3.\n'],
6632 'mkdir', '-m', 'rev 3', A_B_K_url
)
6634 other_wc
= sbox
.add_wc_path('other')
6635 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
6637 short_A_C_wc_dir
= shorten_path_kludge(A_C_wc_dir
)
6638 expected_output
= wc
.State(short_A_C_wc_dir
, {'J' : Item(status
='A ')})
6639 expected_disk
= wc
.State('', {
6641 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2'}),
6643 expected_status
= wc
.State(short_A_C_wc_dir
,
6644 { '' : Item(wc_rev
=1, status
=' M'),
6645 'J' : Item(status
='A ',
6646 wc_rev
='-', copied
='+')
6649 expected_skip
= wc
.State('', { })
6650 saved_cwd
= os
.getcwd()
6651 os
.chdir(svntest
.main
.work_dir
)
6652 svntest
.actions
.run_and_verify_merge(short_A_C_wc_dir
, '1', '2',
6660 expected_output
= wc
.State(A_C_wc_dir
, {
6661 '' : Item(verb
='Sending'),
6662 'J' : Item(verb
='Adding')
6664 expected_status
= wc
.State(A_C_wc_dir
,
6665 { '' : Item(status
=' ', wc_rev
=4),
6666 'J' : Item(status
=' ', wc_rev
=4)
6669 svntest
.actions
.run_and_verify_commit(A_C_wc_dir
,
6675 other_A_C_wc_dir
= other_wc
+ '/A/C'
6676 short_other_A_C_wc_dir
= shorten_path_kludge(other_A_C_wc_dir
)
6677 expected_output
= wc
.State(short_other_A_C_wc_dir
, {'K' : Item(status
='A ')})
6678 expected_disk
= wc
.State('', {
6680 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:3'}),
6682 expected_status
= wc
.State(short_other_A_C_wc_dir
,
6683 { '' : Item(wc_rev
=1, status
=' M'),
6684 'K' : Item(status
='A ',
6685 wc_rev
='-', copied
='+')
6688 expected_skip
= wc
.State('', { })
6689 saved_cwd
= os
.getcwd()
6690 os
.chdir(svntest
.main
.work_dir
)
6691 svntest
.actions
.run_and_verify_merge(short_other_A_C_wc_dir
, '2', '3',
6699 expected_output
= wc
.State(other_A_C_wc_dir
,
6700 {'J' : Item(status
='A '),
6701 '' : Item(status
=' G')
6704 expected_disk
= wc
.State('', {
6705 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2-3'}),
6709 expected_status
= wc
.State(other_A_C_wc_dir
,
6710 { '' : Item(wc_rev
=4, status
=' M'),
6711 'J' : Item(status
=' ', wc_rev
='4'),
6712 'K' : Item(status
='A ',
6713 wc_rev
='-', copied
='+')
6716 svntest
.actions
.run_and_verify_update(other_A_C_wc_dir
,
6722 # Tests part of issue# 2829, marked as XFail until that issue is fixed.
6723 def merge_loses_mergeinfo(sbox
):
6724 "merge should merge mergeinfo"
6727 When a working copy has no mergeinfo(due to local full revert of all merges),
6728 and merge is attempted for someother revision rX, The new mergeinfo should be
6729 /merge/src: rX not all the reverted ones reappearing along with rX.
6733 wc_dir
= sbox
.wc_dir
6734 A_C_wc_dir
= wc_dir
+ '/A/C'
6735 A_B_url
= sbox
.repo_url
+ '/A/B'
6736 A_B_J_url
= sbox
.repo_url
+ '/A/B/J'
6737 A_B_K_url
= sbox
.repo_url
+ '/A/B/K'
6738 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 2.\n'],
6740 'mkdir', '-m', 'rev 2', A_B_J_url
)
6741 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 3.\n'],
6743 'mkdir', '-m', 'rev 3', A_B_K_url
)
6745 short_A_C_wc_dir
= shorten_path_kludge(A_C_wc_dir
)
6746 expected_output
= wc
.State(short_A_C_wc_dir
, {'J' : Item(status
='A ')})
6747 expected_disk
= wc
.State('', {
6749 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2'}),
6751 expected_status
= wc
.State(short_A_C_wc_dir
,
6752 { '' : Item(wc_rev
=1, status
=' M'),
6753 'J' : Item(status
='A ',
6754 wc_rev
='-', copied
='+')
6757 expected_skip
= wc
.State('', { })
6758 saved_cwd
= os
.getcwd()
6759 os
.chdir(svntest
.main
.work_dir
)
6760 svntest
.actions
.run_and_verify_merge(short_A_C_wc_dir
, '1', '2',
6768 expected_output
= wc
.State(A_C_wc_dir
, {
6769 '' : Item(verb
='Sending'),
6770 'J' : Item(verb
='Adding')
6772 expected_status
= wc
.State(A_C_wc_dir
,
6773 { '' : Item(status
=' ', wc_rev
=4),
6774 'J' : Item(status
=' ', wc_rev
=4)
6777 svntest
.actions
.run_and_verify_commit(A_C_wc_dir
,
6782 expected_output
= wc
.State(short_A_C_wc_dir
, {'J' : Item(status
='D ')})
6783 expected_disk
= wc
.State('', {'J': Item()})
6784 expected_status
= wc
.State(short_A_C_wc_dir
,
6785 { '' : Item(wc_rev
=4, status
=' M'),
6786 'J' : Item(wc_rev
=4, status
='D ')
6789 saved_cwd
= os
.getcwd()
6790 os
.chdir(svntest
.main
.work_dir
)
6791 svntest
.actions
.run_and_verify_merge(short_A_C_wc_dir
, '2', '1',
6800 expected_output
= wc
.State(short_A_C_wc_dir
, {'K' : Item(status
='A ')})
6801 expected_disk
= wc
.State('', {
6804 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:3'}),
6806 expected_status
= wc
.State(short_A_C_wc_dir
,
6807 { '' : Item(wc_rev
=4, status
=' M'),
6808 'K' : Item(status
='A ',
6809 wc_rev
='-', copied
='+'),
6810 'J' : Item(wc_rev
=4, status
='D ')
6813 saved_cwd
= os
.getcwd()
6814 os
.chdir(svntest
.main
.work_dir
)
6815 svntest
.actions
.run_and_verify_merge(short_A_C_wc_dir
, '2', '3',
6823 def single_file_replace_style_merge_capability(sbox
):
6824 "replace-style merge capability for a single file"
6826 # Test for issue #2853, do_single_file_merge() lacks "Replace-style
6830 wc_dir
= sbox
.wc_dir
6831 iota_path
= os
.path
.join(wc_dir
, 'iota')
6832 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
6834 # delete mu and replace it with a copy of iota
6835 svntest
.main
.run_svn(None, 'rm', mu_path
)
6836 svntest
.main
.run_svn(None, 'mv', iota_path
, mu_path
)
6838 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
6839 expected_status
.tweak('A/mu', status
=' ', wc_rev
=2)
6840 expected_status
.remove('iota')
6841 expected_output
= svntest
.wc
.State(wc_dir
, {
6842 'iota': Item(verb
='Deleting'),
6843 'A/mu': Item(verb
='Replacing'),
6845 svntest
.actions
.run_and_verify_commit(wc_dir
,
6850 # Merge the file mu alone to rev1
6851 svntest
.actions
.run_and_verify_svn(None,
6852 expected_merge_output(None,
6853 ['D ' + mu_path
+ '\n',
6854 'A ' + mu_path
+ '\n']),
6861 # Test for issue 2786 fix.
6862 def merge_to_out_of_date_target(sbox
):
6863 "merge to ood path can lead to inaccurate mergeinfo"
6865 # Create a WC with a branch.
6867 wc_dir
= sbox
.wc_dir
6868 wc_disk
, wc_status
= set_up_branch(sbox
, False, 1)
6870 # Make second working copy
6871 other_wc
= sbox
.add_wc_path('other')
6872 svntest
.actions
.duplicate_dir(wc_dir
, other_wc
)
6874 # Some paths we'll care about
6875 A_COPY_H_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H")
6876 other_A_COPY_H_path
= os
.path
.join(other_wc
, "A_COPY", "D", "H")
6878 # Merge -c3 into A_COPY/D/H of first WC.
6880 # Search for the comment entitled "The Merge Kluge" elsewhere in
6881 # this file, to understand why we shorten and chdir() below.
6882 short_H_COPY_path
= shorten_path_kludge(A_COPY_H_path
)
6883 expected_output
= wc
.State(short_H_COPY_path
, {
6884 'psi' : Item(status
='U ')
6886 expected_status
= wc
.State(short_H_COPY_path
, {
6887 '' : Item(status
=' M', wc_rev
=2),
6888 'psi' : Item(status
='M ', wc_rev
=2),
6889 'omega' : Item(status
=' ', wc_rev
=2),
6890 'chi' : Item(status
=' ', wc_rev
=2),
6892 expected_disk
= wc
.State('', {
6893 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:3'}),
6894 'psi' : Item("New content"),
6895 'omega' : Item("This is the file 'omega'.\n"),
6896 'chi' : Item("This is the file 'chi'.\n"),
6898 expected_skip
= wc
.State(short_H_COPY_path
, { })
6899 saved_cwd
= os
.getcwd()
6900 os
.chdir(svntest
.main
.work_dir
)
6901 svntest
.actions
.run_and_verify_merge(short_H_COPY_path
, '2', '3',
6902 sbox
.repo_url
+ '/A/D/H',
6903 expected_output
, expected_disk
,
6904 expected_status
, expected_skip
,
6905 None, None, None, None, None, 1)
6908 # Commit merge to first WC.
6909 wc_status
.tweak('A_COPY/D/H/psi', 'A_COPY/D/H', wc_rev
=7)
6910 expected_output
= svntest
.wc
.State(wc_dir
, {
6911 'A_COPY/D/H' : Item(verb
='Sending'),
6912 'A_COPY/D/H/psi': Item(verb
='Sending'),
6914 svntest
.actions
.run_and_verify_commit(wc_dir
,
6919 # Merge -c6 into A_COPY/D/H of other WC.
6920 short_H_COPY_path
= shorten_path_kludge(other_A_COPY_H_path
)
6921 expected_output
= wc
.State(short_H_COPY_path
, {
6922 'omega' : Item(status
='U ')
6924 expected_status
= wc
.State(short_H_COPY_path
, {
6925 '' : Item(status
=' M', wc_rev
=2),
6926 'psi' : Item(status
=' ', wc_rev
=2),
6927 'omega' : Item(status
='M ', wc_rev
=2),
6928 'chi' : Item(status
=' ', wc_rev
=2),
6930 expected_disk
= wc
.State('', {
6931 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:6'}),
6932 'psi' : Item("This is the file 'psi'.\n"),
6933 'omega' : Item("New content"),
6934 'chi' : Item("This is the file 'chi'.\n"),
6936 expected_skip
= wc
.State(short_H_COPY_path
, { })
6937 os
.chdir(svntest
.main
.work_dir
)
6938 svntest
.actions
.run_and_verify_merge(short_H_COPY_path
, '5', '6',
6939 sbox
.repo_url
+ '/A/D/H',
6940 expected_output
, expected_disk
,
6941 expected_status
, expected_skip
,
6942 None, None, None, None, None, 1)
6945 # Update A_COPY/D/H in other WC. Local mergeinfo for r6 on A_COPY/D/H
6946 # should be *merged* with r3 from first WC.
6947 expected_output
= svntest
.wc
.State(other_A_COPY_H_path
, {
6948 '' : Item(status
=' G'),
6949 'psi' : Item(status
='U ')
6951 other_disk
= wc
.State('', {
6952 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:3,6'}),
6953 'psi' : Item(contents
="New content"),
6954 'chi' : Item("This is the file 'chi'.\n"),
6955 'omega' : Item(contents
="New content"),
6957 other_status
= wc
.State(other_A_COPY_H_path
,{
6958 '' : Item(wc_rev
=7, status
=' M'),
6959 'chi' : Item(wc_rev
=7, status
=' '),
6960 'psi' : Item(wc_rev
=7, status
=' '),
6961 'omega' : Item(wc_rev
=7, status
='M ')
6963 svntest
.actions
.run_and_verify_update(other_A_COPY_H_path
,
6969 def merge_with_depth_files(sbox
):
6970 "merge test for --depth files"
6973 wc_dir
= sbox
.wc_dir
6975 # Some paths we'll care about
6976 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
6977 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
6978 Acopy_path
= os
.path
.join(wc_dir
, 'A_copy')
6979 Acopy_mu_path
= os
.path
.join(wc_dir
, 'A_copy', 'mu')
6980 A_url
= sbox
.repo_url
+ '/A'
6981 Acopy_url
= sbox
.repo_url
+ '/A_copy'
6983 # Copy A_url to A_copy_url
6984 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp',
6986 '-m', 'create a new copy of A')
6988 svntest
.main
.file_write(mu_path
, "this is file 'mu' modified.\n")
6989 svntest
.main
.file_write(gamma_path
, "this is file 'gamma' modified.\n")
6991 # Create expected output tree for commit
6992 expected_output
= wc
.State(wc_dir
, {
6993 'A/mu' : Item(verb
='Sending'),
6994 'A/D/gamma' : Item(verb
='Sending'),
6997 # Create expected status tree for commit
6998 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
6999 expected_status
.add({
7000 'A/mu' : Item(status
=' ', wc_rev
=3),
7001 'A/D/gamma' : Item(status
=' ', wc_rev
=3),
7004 # Commit the modified contents
7005 svntest
.actions
.run_and_verify_commit(wc_dir
,
7011 # Update working copy
7012 svntest
.actions
.run_and_verify_svn(None, None, [],
7015 # Merge r1:3 into A_copy with --depth files. The merge only affects
7016 # 'A_copy' and its one file child 'mu', so 'A_copy' gets non-inheritable
7017 # mergeinfo for -r1:3 and 'mu' gets its own complete set of mergeinfo:
7018 # r1 from its parent, and r1:3 from the merge itself.
7020 # Search for the comment entitled "The Merge Kluge" elsewhere in
7021 # this file, to understand why we shorten and chdir() below.
7022 short_A_COPY_path
= shorten_path_kludge(Acopy_path
)
7023 expected_output
= wc
.State(short_A_COPY_path
, {
7024 'mu' : Item(status
='U '),
7026 expected_status
= wc
.State(short_A_COPY_path
, {
7027 '' : Item(status
=' M'),
7028 'B' : Item(status
=' '),
7029 'mu' : Item(status
='MM'),
7030 'B/E' : Item(status
=' '),
7031 'B/E/alpha' : Item(status
=' '),
7032 'B/E/beta' : Item(status
=' '),
7033 'B/lambda' : Item(status
=' '),
7034 'B/F' : Item(status
=' '),
7035 'C' : Item(status
=' '),
7036 'D' : Item(status
=' '),
7037 'D/G' : Item(status
=' '),
7038 'D/G/pi' : Item(status
=' '),
7039 'D/G/rho' : Item(status
=' '),
7040 'D/G/tau' : Item(status
=' '),
7041 'D/gamma' : Item(status
=' '),
7042 'D/H' : Item(status
=' '),
7043 'D/H/chi' : Item(status
=' '),
7044 'D/H/psi' : Item(status
=' '),
7045 'D/H/omega' : Item(status
=' '),
7047 expected_status
.tweak(wc_rev
=3)
7048 expected_disk
= wc
.State('', {
7049 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:2-3*'}),
7051 'mu' : Item("this is file 'mu' modified.\n",
7052 props
={SVN_PROP_MERGEINFO
: '/A/mu:2-3'}),
7054 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
7055 'B/E/beta' : Item("This is the file 'beta'.\n"),
7056 'B/lambda' : Item("This is the file 'lambda'.\n"),
7061 'D/G/pi' : Item("This is the file 'pi'.\n"),
7062 'D/G/rho' : Item("This is the file 'rho'.\n"),
7063 'D/G/tau' : Item("This is the file 'tau'.\n"),
7064 'D/gamma' : Item("This is the file 'gamma'.\n"),
7066 'D/H/chi' : Item("This is the file 'chi'.\n"),
7067 'D/H/psi' : Item("This is the file 'psi'.\n"),
7068 'D/H/omega' : Item("This is the file 'omega'.\n"),
7070 expected_skip
= wc
.State(short_A_COPY_path
, { })
7071 saved_cwd
= os
.getcwd()
7072 os
.chdir(svntest
.main
.work_dir
)
7073 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '1', '3',
7074 sbox
.repo_url
+ '/A',
7075 expected_output
, expected_disk
,
7076 expected_status
, expected_skip
,
7077 None, None, None, None, None, 1, 1,
7081 def merge_fails_if_subtree_is_deleted_on_src(sbox
):
7082 "merge fails if subtree is deleted on src"
7084 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2876. ##
7088 wc_dir
= sbox
.wc_dir
7090 # Some paths we'll care about
7091 Acopy_path
= os
.path
.join(wc_dir
, 'A_copy')
7092 gamma_path
= os
.path
.join(wc_dir
, 'A', 'D', 'gamma')
7093 Acopy_gamma_path
= os
.path
.join(wc_dir
, 'A_copy', 'D', 'gamma')
7094 A_url
= sbox
.repo_url
+ '/A'
7095 Acopy_url
= sbox
.repo_url
+ '/A_copy'
7097 # Contents to be added to 'gamma'
7098 new_content
= "line1\nline2\nline3\nline4\nline5\n"
7100 svntest
.main
.file_write(gamma_path
, new_content
)
7102 # Create expected output tree for commit
7103 expected_output
= wc
.State(wc_dir
, {
7104 'A/D/gamma' : Item(verb
='Sending'),
7107 # Create expected status tree for commit
7108 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
7109 expected_status
.tweak('A/D/gamma', wc_rev
=2)
7111 # Commit the new content
7112 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7113 expected_status
, None, wc_dir
)
7115 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp', A_url
, Acopy_url
,
7116 '-m', 'create a new copy of A')
7118 # Update working copy
7119 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
7121 svntest
.main
.file_substitute(gamma_path
, "line1", "this is line1")
7122 # Create expected output tree for commit
7123 expected_output
= wc
.State(wc_dir
, {
7124 'A/D/gamma' : Item(verb
='Sending'),
7127 # Create expected status tree for commit
7128 expected_status
.tweak(wc_rev
=3)
7129 expected_status
.tweak('A/D/gamma', wc_rev
=4)
7130 expected_status
.add({
7131 'A_copy' : Item(status
=' ', wc_rev
=3),
7132 'A_copy/B' : Item(status
=' ', wc_rev
=3),
7133 'A_copy/B/lambda' : Item(status
=' ', wc_rev
=3),
7134 'A_copy/B/E' : Item(status
=' ', wc_rev
=3),
7135 'A_copy/B/E/alpha': Item(status
=' ', wc_rev
=3),
7136 'A_copy/B/E/beta' : Item(status
=' ', wc_rev
=3),
7137 'A_copy/B/F' : Item(status
=' ', wc_rev
=3),
7138 'A_copy/mu' : Item(status
=' ', wc_rev
=3),
7139 'A_copy/C' : Item(status
=' ', wc_rev
=3),
7140 'A_copy/D' : Item(status
=' ', wc_rev
=3),
7141 'A_copy/D/gamma' : Item(status
=' ', wc_rev
=3),
7142 'A_copy/D/G' : Item(status
=' ', wc_rev
=3),
7143 'A_copy/D/G/pi' : Item(status
=' ', wc_rev
=3),
7144 'A_copy/D/G/rho' : Item(status
=' ', wc_rev
=3),
7145 'A_copy/D/G/tau' : Item(status
=' ', wc_rev
=3),
7146 'A_copy/D/H' : Item(status
=' ', wc_rev
=3),
7147 'A_copy/D/H/chi' : Item(status
=' ', wc_rev
=3),
7148 'A_copy/D/H/omega': Item(status
=' ', wc_rev
=3),
7149 'A_copy/D/H/psi' : Item(status
=' ', wc_rev
=3),
7152 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7153 expected_status
, None, wc_dir
)
7155 # Delete A/D/gamma from working copy
7156 svntest
.actions
.run_and_verify_svn(None, None, [], 'delete', gamma_path
)
7157 # Create expected output tree for commit
7158 expected_output
= wc
.State(wc_dir
, {
7159 'A/D/gamma' : Item(verb
='Deleting'),
7162 expected_status
.remove('A/D/gamma')
7164 svntest
.actions
.run_and_verify_commit(wc_dir
,
7170 svntest
.actions
.run_and_verify_svn(None, expected_merge_output([[3,4]],
7171 'U ' + Acopy_gamma_path
+ '\n'),
7172 [], 'merge', '-r1:4',
7173 A_url
+ '/D/gamma' + '@4',
7176 svntest
.actions
.run_and_verify_svn(None, expected_merge_output([[5]],
7177 'D ' + Acopy_gamma_path
+ '\n'),
7178 [], 'merge', '-r1:5', '--force',
7183 # 2883: No-op merge (without skip) should not change mergeinfo.
7184 # 2976: Subtrees can lose non-inhertiable ranges
7185 def no_mergeinfo_from_no_op_merge(sbox
):
7186 "no-op merge without skips doesn't change mergeinfo"
7189 wc_dir
= sbox
.wc_dir
7190 wc_disk
, wc_status
= set_up_branch(sbox
)
7192 # Some paths we'll care about
7193 H_path
= os
.path
.join(wc_dir
, "A", "D", "H")
7194 beta_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "B", "E", "beta")
7195 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
7196 tau_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "tau")
7197 C_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "C")
7198 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
7200 # Part 1: Test for issue #2883
7202 # Merge r5 into A_COPY/B/E/beta and commit it.
7203 # Search for the comment entitled "The Merge Kluge" elsewhere in
7204 # this file, to understand why we shorten and chdir() below.
7205 short_beta_COPY_path
= shorten_path_kludge(beta_COPY_path
)
7206 expected_skip
= wc
.State(short_beta_COPY_path
, { })
7207 saved_cwd
= os
.getcwd()
7208 os
.chdir(svntest
.main
.work_dir
)
7209 # run_and_verify_merge doesn't support merging to a file WCPATH
7210 # so use run_and_verify_svn.
7211 svntest
.actions
.run_and_verify_svn(None,
7212 expected_merge_output([[5]],
7213 'U ' + short_beta_COPY_path
+
7214 '\n'), [], 'merge', '-c5',
7215 sbox
.repo_url
+ '/A/B/E/beta',
7216 short_beta_COPY_path
)
7219 expected_output
= wc
.State(wc_dir
,
7220 {'A_COPY/B/E/beta' : Item(verb
='Sending')})
7221 wc_status
.tweak('A_COPY/B/E/beta', wc_rev
=7)
7222 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
7225 # Update A_COPY to get all paths to the same working revision.
7226 svntest
.actions
.run_and_verify_svn(None, ["At revision 7.\n"], [],
7228 wc_status
.tweak(wc_rev
=7)
7230 # Merge r4 into A_COPY/D/G.
7231 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
7232 expected_output
= wc
.State(short_G_COPY_path
, {
7233 'rho' : Item(status
='U ')
7235 expected_status
= wc
.State(short_G_COPY_path
, {
7236 '' : Item(status
=' M', wc_rev
=7),
7237 'pi' : Item(status
=' ', wc_rev
=7),
7238 'rho' : Item(status
='M ', wc_rev
=7),
7239 'tau' : Item(status
=' ', wc_rev
=7),
7241 expected_disk
= wc
.State('', {
7242 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:4'}),
7243 'pi' : Item("This is the file 'pi'.\n"),
7244 'rho' : Item("New content"),
7245 'tau' : Item("This is the file 'tau'.\n"),
7247 expected_skip
= wc
.State(short_G_COPY_path
, { })
7248 os
.chdir(svntest
.main
.work_dir
)
7249 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '3', '4',
7250 sbox
.repo_url
+ '/A/D/G',
7251 expected_output
, expected_disk
,
7252 expected_status
, expected_skip
,
7253 None, None, None, None, None, 1)
7254 wc_status
.tweak('A_COPY/D/G', status
=' M')
7255 wc_status
.tweak('A_COPY/D/G/rho', status
='M ')
7257 # Now try a few no-op variants, in every case no mergeinfo should
7258 # change from the above state.
7260 # Do a no-op merge to a file with committed mergeinfo:
7261 # -r2:4 into A_COPY/B/E/beta.
7262 svntest
.actions
.run_and_verify_svn(None,
7263 expected_merge_output([[3,4]], None),
7264 [], 'merge', '-r2:4',
7265 sbox
.repo_url
+ '/A/B/E/beta',
7266 short_beta_COPY_path
)
7268 # Do a no-op merge to a file with inherited mergeinfo:
7269 # -c3 into A_COPY/D/G/tau.
7270 short_tau_COPY_path
= shorten_path_kludge(tau_COPY_path
)
7271 svntest
.actions
.run_and_verify_svn(None,
7272 expected_merge_output([[3]]),
7274 sbox
.repo_url
+ '/A/D/G/tau',
7275 short_tau_COPY_path
)
7277 # Do a no-op merge to a dir with local mergeinfo:
7278 # -r4:6 into A_COPY/D/G.
7279 short_tau_COPY_path
= shorten_path_kludge(tau_COPY_path
)
7280 svntest
.actions
.run_and_verify_svn(None,
7281 expected_merge_output([[5,6]], None),
7282 [], 'merge', '-r4:6',
7283 sbox
.repo_url
+ '/A/D/G',
7286 svntest
.actions
.run_and_verify_svn(None, ["/A/D/G:4\n"], [],
7287 'propget', SVN_PROP_MERGEINFO
,
7290 # Do a no-op merge to a dir with inherited mergeinfo:
7291 # All available revs into A_COPY/C.
7292 os
.chdir(svntest
.main
.work_dir
)
7293 short_C_COPY_path
= shorten_path_kludge(C_COPY_path
)
7294 svntest
.actions
.run_and_verify_svn(None,
7295 expected_merge_output([[2,7]], None),
7297 sbox
.repo_url
+ '/A/C',
7301 # A final check of the WC's status to ensure nothing unexpected occurred
7302 # (that the above merge's stdout/stderr didn't already reveal).
7303 svntest
.actions
.run_and_verify_status(wc_dir
, wc_status
)
7305 # Reopened Issue #2883 as the following sequence failed:
7306 # Commit what we have so far as r8.
7307 expected_output
= svntest
.wc
.State(wc_dir
, {
7308 'A_COPY/D/G' : Item(verb
='Sending'),
7309 'A_COPY/D/G/rho' : Item(verb
='Sending'),
7311 wc_status
.tweak(status
=' ')
7312 wc_status
.tweak('A_COPY/D/G', 'A_COPY/D/G/rho', wc_rev
=8)
7313 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
7315 wc_status
.tweak(wc_rev
=8)
7316 # Update the WC and add a prop to A/D/H and commit that as r9.
7317 svntest
.actions
.run_and_verify_svn(None, ['At revision 8.\n'], [],
7320 svntest
.actions
.run_and_verify_svn(
7321 None, ["property 'prop:name' set on '" + H_path
+ "'\n"], [],
7322 'ps', 'prop:name', 'propval', H_path
)
7323 expected_output
= svntest
.wc
.State(wc_dir
, {
7324 'A/D/H' : Item(verb
='Sending'),})
7325 wc_status
.tweak(status
=' ')
7326 wc_status
.tweak('A/D/H', wc_rev
=9)
7327 wc_status
.tweak('A_COPY/D/G', 'A_COPY/D/G/rho', wc_rev
=8)
7328 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
7331 # Update A_COPY to get all paths to the same working revision.
7332 svntest
.actions
.run_and_verify_svn(None, ["At revision 9.\n"], [],
7334 wc_status
.tweak(wc_rev
=9)
7336 # Merge r5:9 --depth immediates to A_COPY/D
7337 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
7338 expected_output
= wc
.State(short_D_COPY_path
, {
7339 'H' : Item(status
=' U'),
7341 expected_status
= wc
.State(short_D_COPY_path
, {
7342 '' : Item(status
=' M', wc_rev
=9),
7343 'H' : Item(status
=' M', wc_rev
=9),
7344 'H/chi' : Item(status
=' ', wc_rev
=9),
7345 'H/omega' : Item(status
=' ', wc_rev
=9),
7346 'H/psi' : Item(status
=' ', wc_rev
=9),
7347 'G' : Item(status
=' M', wc_rev
=9),
7348 'G/pi' : Item(status
=' ', wc_rev
=9),
7349 'G/rho' : Item(status
=' ', wc_rev
=9),
7350 'G/tau' : Item(status
=' ', wc_rev
=9),
7351 'gamma' : Item(status
=' ', wc_rev
=9),
7353 expected_disk
= wc
.State('', {
7354 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:6-9'}),
7355 'H' : Item(props
={'prop:name' : 'propval',
7356 SVN_PROP_MERGEINFO
: '/A/D/H:6-9*'}),
7357 'H/chi' : Item("This is the file 'chi'.\n"),
7358 'H/omega' : Item("This is the file 'omega'.\n"),
7359 'H/psi' : Item("This is the file 'psi'.\n"),
7360 'G' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:4,6-9*'}),
7361 'G/pi' : Item("This is the file 'pi'.\n"),
7362 'G/rho' : Item("New content"),
7363 'G/tau' : Item("This is the file 'tau'.\n"),
7364 'gamma' : Item("This is the file 'gamma'.\n"),
7366 expected_skip
= wc
.State(short_D_COPY_path
, { })
7367 os
.chdir(svntest
.main
.work_dir
)
7368 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '5', '9',
7369 sbox
.repo_url
+ '/A/D',
7370 expected_output
, expected_disk
,
7371 expected_status
, expected_skip
,
7372 None, None, None, None, None, 1, 1,
7373 '--depth', 'immediates')
7376 # Commit everything so far.
7377 expected_output
= svntest
.wc
.State(wc_dir
, {
7378 'A_COPY/D' : Item(verb
='Sending'),
7379 'A_COPY/D/G' : Item(verb
='Sending'),
7380 'A_COPY/D/H' : Item(verb
='Sending'),
7382 wc_status
.tweak('A_COPY/D', 'A_COPY/D/G', 'A_COPY/D/H',
7383 wc_rev
=10, status
=' ')
7384 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
7387 # Do a no-op merge of -c9 to A_COPY/D. In issue #2883 this
7388 # looked like a no-op but modified subtree mergeinfo.
7389 expected_output
= wc
.State(short_D_COPY_path
, {})
7390 expected_status
.tweak('', 'G', 'H', wc_rev
=10, status
=' ')
7391 os
.chdir(svntest
.main
.work_dir
)
7392 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '8', '9',
7393 sbox
.repo_url
+ '/A/D',
7394 expected_output
, expected_disk
,
7395 expected_status
, expected_skip
,
7396 None, None, None, None, None, 1, 1)
7400 # Part 2: Test for issue #2976
7402 # Merge r3:8 A_COPY/D/H and A_COPY/D/G should
7403 # both retain mergeinfo for r9*
7405 # Update A_COPY to get all paths to the same working revision.
7406 svntest
.actions
.run_and_verify_svn(None, ["At revision 10.\n"], [],
7408 expected_status
.tweak(wc_rev
=10)
7410 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
7411 expected_output
= wc
.State(short_D_COPY_path
, {
7412 'H/omega' : Item(status
='U '),
7414 expected_status
.tweak('', 'G', 'H', status
=' M')
7415 expected_status
.tweak('H/omega', status
='M ')
7416 expected_disk
= wc
.State('', {
7417 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:4-9'}),
7418 'H' : Item(props
={'prop:name' : 'propval',
7419 SVN_PROP_MERGEINFO
: '/A/D/H:4-8,9*'}),
7420 'H/chi' : Item("This is the file 'chi'.\n"),
7421 'H/omega' : Item("New content"),
7422 'H/psi' : Item("This is the file 'psi'.\n"),
7423 'G' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:4-8,9*'}),
7424 'G/pi' : Item("This is the file 'pi'.\n"),
7425 'G/rho' : Item("New content"),
7426 'G/tau' : Item("This is the file 'tau'.\n"),
7427 'gamma' : Item("This is the file 'gamma'.\n"),
7429 expected_skip
= wc
.State(short_D_COPY_path
, { })
7430 os
.chdir(svntest
.main
.work_dir
)
7431 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '3', '8',
7432 sbox
.repo_url
+ '/A/D',
7433 expected_output
, expected_disk
,
7434 expected_status
, expected_skip
,
7435 None, None, None, None, None, 1, 1)
7438 # Test for issue #2827
7439 # Handle merge info for sparsely-populated directories
7440 def merge_to_sparse_directories(sbox
):
7441 "merge to sparse directories"
7443 # Merges into sparse working copies should set non-inheritable mergeinfo
7444 # on the deepest directories present in the WC.
7447 wc_dir
= sbox
.wc_dir
7448 wc_disk
, wc_status
= set_up_branch(sbox
, False, 1)
7450 # Some paths we'll care about
7451 A_path
= os
.path
.join(wc_dir
, "A")
7452 D_path
= os
.path
.join(wc_dir
, "A", "D")
7453 I_path
= os
.path
.join(wc_dir
, "A", "C", "I")
7454 G_path
= os
.path
.join(wc_dir
, "A", "D", "G")
7455 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
7457 # Make a few more changes to the merge source...
7459 # r7 - modify and commit A/mu
7460 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A", "mu"),
7462 expected_output
= wc
.State(wc_dir
, {'A/mu' : Item(verb
='Sending')})
7463 wc_status
.tweak('A/mu', wc_rev
=7)
7464 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7465 wc_status
, None, wc_dir
)
7466 wc_disk
.tweak('A/mu', contents
="New content")
7468 # r8 - Add a prop to A/D and commit.
7469 svntest
.actions
.run_and_verify_svn(None, ["At revision 7.\n"], [],
7471 svntest
.actions
.run_and_verify_svn(None,
7472 ["property 'prop:name' set on '" +
7473 D_path
+ "'\n"], [], 'ps',
7474 'prop:name', 'propval', D_path
)
7475 expected_output
= svntest
.wc
.State(wc_dir
, {
7476 'A/D' : Item(verb
='Sending'),
7478 wc_status
.tweak(wc_rev
=7)
7479 wc_status
.tweak('A/D', wc_rev
=8)
7480 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
7483 # r9 - Add a prop to A and commit.
7484 svntest
.actions
.run_and_verify_svn(None, ["At revision 8.\n"], [],
7486 svntest
.actions
.run_and_verify_svn(None,
7487 ["property 'prop:name' set on '" +
7488 A_path
+ "'\n"], [], 'ps',
7489 'prop:name', 'propval', A_path
)
7490 expected_output
= svntest
.wc
.State(wc_dir
, {
7491 'A' : Item(verb
='Sending'),
7493 wc_status
.tweak(wc_rev
=8)
7494 wc_status
.tweak('A', wc_rev
=9)
7495 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
7498 # Do an --immediates checkout of A_COPY
7499 immediates_dir
= sbox
.add_wc_path('immediates')
7500 expected_output
= wc
.State(immediates_dir
, {
7501 'B' : Item(status
='A '),
7502 'mu' : Item(status
='A '),
7503 'C' : Item(status
='A '),
7504 'D' : Item(status
='A '),
7506 expected_disk
= wc
.State('', {
7508 'mu' : Item("This is the file 'mu'.\n"),
7512 svntest
.actions
.run_and_verify_checkout(sbox
.repo_url
+ "/A_COPY",
7514 expected_output
, expected_disk
,
7515 None, None, None, None,
7516 "--depth", "immediates")
7518 # Merge r4:9 into the immediates WC.
7519 # The root of the immediates WC should get inheritable r4:9 as should
7520 # the one file present 'mu'. The three directory children present, 'B',
7521 # 'C', and 'D' are checked out at depth empty, so get non-inheritable
7522 # mergeinfo for r4:9. The root and 'D' do should also get the changes
7523 # that affect them directly (the prop adds from r8 and r9). Any changes
7524 # deeper than the immediates should be skipped.
7526 # Search for the comment entitled "The Merge Kluge" elsewhere in
7527 # this file, to understand why we shorten and chdir() below.
7528 short_immediates_dir
= shorten_path_kludge(immediates_dir
)
7529 expected_output
= wc
.State(short_immediates_dir
, {
7530 'D' : Item(status
=' U'),
7531 'mu' : Item(status
='U '),
7532 '' : Item(status
=' U'),
7534 expected_status
= wc
.State(short_immediates_dir
, {
7535 '' : Item(status
=' M', wc_rev
=9),
7536 'B' : Item(status
=' M', wc_rev
=9),
7537 'mu' : Item(status
='M ', wc_rev
=9),
7538 'C' : Item(status
=' M', wc_rev
=9),
7539 'D' : Item(status
=' M', wc_rev
=9),
7541 expected_disk
= wc
.State('', {
7542 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5-9',
7543 "prop:name" : "propval"}),
7544 'B' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:5-9*'}),
7545 'mu' : Item("New content"),
7546 'C' : Item(props
={SVN_PROP_MERGEINFO
: '/A/C:5-9*'}),
7547 'D' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:5-9*',
7548 "prop:name" : "propval"}),
7550 expected_skip
= wc
.State(short_immediates_dir
, {})
7551 saved_cwd
= os
.getcwd()
7552 os
.chdir(svntest
.main
.work_dir
)
7553 svntest
.actions
.run_and_verify_merge(short_immediates_dir
, '4', '9',
7560 None, None, None, None,
7564 # Do a --files checkout of A_COPY
7565 files_dir
= sbox
.add_wc_path('files')
7566 expected_output
= wc
.State(files_dir
, {
7567 'mu' : Item(status
='A '),
7569 expected_disk
= wc
.State('', {
7570 'mu' : Item("This is the file 'mu'.\n"),
7572 svntest
.actions
.run_and_verify_checkout(sbox
.repo_url
+ "/A_COPY",
7574 expected_output
, expected_disk
,
7575 None, None, None, None,
7578 # Merge r4:9 into the files WC.
7579 # The root of the files WC should get non-inheritable r4:9 and its one
7580 # present child 'mu' should get the same but inheritable. The root
7581 # should also get the change that affects it directly (the prop add
7583 short_files_dir
= shorten_path_kludge(files_dir
)
7584 expected_output
= wc
.State(short_files_dir
, {
7585 'mu' : Item(status
='U '),
7586 '' : Item(status
=' U'),
7588 expected_status
= wc
.State(short_files_dir
, {
7589 '' : Item(status
=' M', wc_rev
=9),
7590 'mu' : Item(status
='MM', wc_rev
=9),
7592 expected_disk
= wc
.State('', {
7593 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5-9*',
7594 "prop:name" : "propval"}),
7595 'mu' : Item("New content",
7596 props
={SVN_PROP_MERGEINFO
: '/A/mu:5-9'}),
7598 expected_skip
= wc
.State(short_files_dir
, {})
7599 os
.chdir(svntest
.main
.work_dir
)
7600 svntest
.actions
.run_and_verify_merge(short_files_dir
, '4', '9',
7607 None, None, None, None,
7611 # Do an --empty checkout of A_COPY
7612 empty_dir
= sbox
.add_wc_path('empty')
7613 expected_output
= wc
.State(empty_dir
, {})
7614 expected_disk
= wc
.State('', {})
7615 svntest
.actions
.run_and_verify_checkout(sbox
.repo_url
+ "/A_COPY",
7617 expected_output
, expected_disk
,
7618 None, None, None, None,
7621 # Merge r4:9 into the empty WC.
7622 # The root of the files WC should get non-inheritable r4:9 and also get
7623 # the one change that affects it directly (the prop add from r9).
7624 short_empty_dir
= shorten_path_kludge(empty_dir
)
7625 expected_output
= wc
.State(short_empty_dir
, {
7626 '' : Item(status
=' U'),
7628 expected_status
= wc
.State(short_empty_dir
, {
7629 '' : Item(status
=' M', wc_rev
=9),
7631 expected_disk
= wc
.State('', {
7632 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5-9*',
7633 "prop:name" : "propval"}),
7635 expected_skip
= wc
.State(short_empty_dir
, {})
7636 os
.chdir(svntest
.main
.work_dir
)
7637 svntest
.actions
.run_and_verify_merge(short_empty_dir
, '4', '9',
7644 None, None, None, None,
7648 def merge_old_and_new_revs_from_renamed_dir(sbox
):
7649 "merge -rold(before rename):head renamed dir"
7651 ## See http://svn.haxx.se/dev/archive-2007-09/0706.shtml ##
7653 # Create a WC with a single branch
7655 wc_dir
= sbox
.wc_dir
7656 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
7658 # Some paths we'll care about
7659 A_url
= sbox
.repo_url
+ '/A'
7660 A_MOVED_url
= sbox
.repo_url
+ '/A_MOVED'
7661 A_COPY_path
= os
.path
.join(wc_dir
, 'A_COPY')
7662 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
7663 A_MOVED_mu_path
= os
.path
.join(wc_dir
, 'A_MOVED', 'mu')
7665 # Make a modification to A/mu
7666 svntest
.main
.file_write(mu_path
, "This is the file 'mu' modified.\n")
7667 expected_output
= wc
.State(wc_dir
, {'A/mu' : Item(verb
='Sending')})
7668 wc_status
.add({'A/mu' : Item(status
=' ', wc_rev
=3)})
7669 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7670 wc_status
, None, wc_dir
)
7673 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 4.\n'],
7674 [], 'mv', '-m', 'mv A to A_MOVED',
7677 # Update the working copy to get A_MOVED
7678 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
7680 # Make a modification to A_MOVED/mu
7681 svntest
.main
.file_write(A_MOVED_mu_path
, "This is 'mu' in A_MOVED.\n")
7682 expected_output
= wc
.State(wc_dir
, {'A_MOVED/mu' : Item(verb
='Sending')})
7683 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 4)
7684 expected_status
.remove('A', 'A/mu', 'A/C', 'A/D', 'A/B', 'A/B/lambda',
7685 'A/B/E', 'A/B/E/alpha', 'A/B/E/beta', 'A/B/F',
7686 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho',
7687 'A/D/G/tau', 'A/D/H', 'A/D/H/chi', 'A/D/H/omega',
7689 expected_status
.add({
7690 '' : Item(status
=' ', wc_rev
=4),
7691 'iota' : Item(status
=' ', wc_rev
=4),
7692 'A_MOVED' : Item(status
=' ', wc_rev
=4),
7693 'A_MOVED/mu' : Item(status
=' ', wc_rev
=5),
7694 'A_MOVED/C' : Item(status
=' ', wc_rev
=4),
7695 'A_MOVED/D' : Item(status
=' ', wc_rev
=4),
7696 'A_MOVED/B' : Item(status
=' ', wc_rev
=4),
7697 'A_MOVED/B/lambda' : Item(status
=' ', wc_rev
=4),
7698 'A_MOVED/B/E' : Item(status
=' ', wc_rev
=4),
7699 'A_MOVED/B/E/alpha': Item(status
=' ', wc_rev
=4),
7700 'A_MOVED/B/E/beta' : Item(status
=' ', wc_rev
=4),
7701 'A_MOVED/B/F' : Item(status
=' ', wc_rev
=4),
7702 'A_MOVED/D/gamma' : Item(status
=' ', wc_rev
=4),
7703 'A_MOVED/D/G' : Item(status
=' ', wc_rev
=4),
7704 'A_MOVED/D/G/pi' : Item(status
=' ', wc_rev
=4),
7705 'A_MOVED/D/G/rho' : Item(status
=' ', wc_rev
=4),
7706 'A_MOVED/D/G/tau' : Item(status
=' ', wc_rev
=4),
7707 'A_MOVED/D/H' : Item(status
=' ', wc_rev
=4),
7708 'A_MOVED/D/H/chi' : Item(status
=' ', wc_rev
=4),
7709 'A_MOVED/D/H/omega': Item(status
=' ', wc_rev
=4),
7710 'A_MOVED/D/H/psi' : Item(status
=' ', wc_rev
=4),
7711 'A_COPY' : Item(status
=' ', wc_rev
=4),
7712 'A_COPY/mu' : Item(status
=' ', wc_rev
=4),
7713 'A_COPY/C' : Item(status
=' ', wc_rev
=4),
7714 'A_COPY/D' : Item(status
=' ', wc_rev
=4),
7715 'A_COPY/B' : Item(status
=' ', wc_rev
=4),
7716 'A_COPY/B/lambda' : Item(status
=' ', wc_rev
=4),
7717 'A_COPY/B/E' : Item(status
=' ', wc_rev
=4),
7718 'A_COPY/B/E/alpha' : Item(status
=' ', wc_rev
=4),
7719 'A_COPY/B/E/beta' : Item(status
=' ', wc_rev
=4),
7720 'A_COPY/B/F' : Item(status
=' ', wc_rev
=4),
7721 'A_COPY/D/gamma' : Item(status
=' ', wc_rev
=4),
7722 'A_COPY/D/G' : Item(status
=' ', wc_rev
=4),
7723 'A_COPY/D/G/pi' : Item(status
=' ', wc_rev
=4),
7724 'A_COPY/D/G/rho' : Item(status
=' ', wc_rev
=4),
7725 'A_COPY/D/G/tau' : Item(status
=' ', wc_rev
=4),
7726 'A_COPY/D/H' : Item(status
=' ', wc_rev
=4),
7727 'A_COPY/D/H/chi' : Item(status
=' ', wc_rev
=4),
7728 'A_COPY/D/H/omega' : Item(status
=' ', wc_rev
=4),
7729 'A_COPY/D/H/psi' : Item(status
=' ', wc_rev
=4),
7731 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7732 expected_status
, None, wc_dir
)
7734 short_A_COPY
= shorten_path_kludge(A_COPY_path
)
7735 saved_cwd
= os
.getcwd()
7736 os
.chdir(svntest
.main
.work_dir
)
7738 # Merge /A_MOVED to /A_COPY - this happens in multiple passes
7739 # because /A_MOVED has renames in its history between the boundaries
7740 # of the requested merge range.
7741 expected_output
= wc
.State(short_A_COPY
, {
7742 'mu' : Item(status
='G '), # mu gets touched twice
7744 expected_status
= wc
.State(short_A_COPY
, {
7745 '' : Item(status
=' M', wc_rev
=4),
7746 'mu' : Item(status
='M ', wc_rev
=4),
7747 'C' : Item(status
=' ', wc_rev
=4),
7748 'D' : Item(status
=' ', wc_rev
=4),
7749 'B' : Item(status
=' ', wc_rev
=4),
7750 'B/lambda' : Item(status
=' ', wc_rev
=4),
7751 'B/E' : Item(status
=' ', wc_rev
=4),
7752 'B/E/alpha': Item(status
=' ', wc_rev
=4),
7753 'B/E/beta' : Item(status
=' ', wc_rev
=4),
7754 'B/F' : Item(status
=' ', wc_rev
=4),
7755 'D/gamma' : Item(status
=' ', wc_rev
=4),
7756 'D/G' : Item(status
=' ', wc_rev
=4),
7757 'D/G/pi' : Item(status
=' ', wc_rev
=4),
7758 'D/G/rho' : Item(status
=' ', wc_rev
=4),
7759 'D/G/tau' : Item(status
=' ', wc_rev
=4),
7760 'D/H' : Item(status
=' ', wc_rev
=4),
7761 'D/H/chi' : Item(status
=' ', wc_rev
=4),
7762 'D/H/omega': Item(status
=' ', wc_rev
=4),
7763 'D/H/psi' : Item(status
=' ', wc_rev
=4),
7765 expected_disk
= wc
.State('', {
7766 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:3\n/A_MOVED:4-5\n'}),
7767 'mu' : Item("This is 'mu' in A_MOVED.\n"),
7771 'B/lambda' : Item("This is the file 'lambda'.\n"),
7773 'B/E/alpha': Item("This is the file 'alpha'.\n"),
7774 'B/E/beta' : Item("This is the file 'beta'.\n"),
7776 'D/gamma' : Item("This is the file 'gamma'.\n"),
7778 'D/G/pi' : Item("This is the file 'pi'.\n"),
7779 'D/G/rho' : Item("This is the file 'rho'.\n"),
7780 'D/G/tau' : Item("This is the file 'tau'.\n"),
7782 'D/H/chi' : Item("This is the file 'chi'.\n"),
7783 'D/H/omega': Item("This is the file 'omega'.\n"),
7784 'D/H/psi' : Item("This is the file 'psi'.\n"),
7786 expected_skip
= wc
.State(short_A_COPY
, {})
7788 ### Disabling dry_run mode because currently it can't handle the way
7789 ### 'mu' gets textually modified in multiple passes.
7790 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '2', '5',
7796 None, None, None, None, None,
7800 def merge_with_child_having_different_rev_ranges_to_merge(sbox
):
7801 "child having different rev ranges to merge"
7802 #Modify A/mu to 30 lines with a content 'line1'...'line30' commit it at r2.
7803 #Create a branch A_COPY from A, commit it at r3.
7804 #Modify A/mu line number 7 to 'LINE7' modify and commit at r4.
7805 #Modify A/mu line number 17 to 'LINE17' modify, set prop 'prop1' on 'A'
7806 #with a value 'val1' and commit at r5.
7807 #Modify A/mu line number 27 to 'LINE27' modify and commit at r6.
7808 #Merge r5 to 'A/mu' as a single file merge explicitly to 'A_COPY/mu'.
7809 #Merge r3:6 from 'A' to 'A_COPY
7810 #This should merge r4 and then r5 through r6.
7811 #Revert r5 and r6 via single file merge on A_COPY/mu.
7812 #Revert r6 through r4 on A_COPY this should get back us the pristine copy.
7813 #Merge r3:6 from 'A' to 'A_COPY
7814 #Revert r5 on A_COPY/mu
7815 #Modify line number 17 with 'some other line17' of A_COPY/mu
7816 #Merge r6:3 from 'A' to 'A_COPY, This should leave line number 17
7817 #undisturbed in A_COPY/mu, rest should be reverted.
7821 wc_dir
= sbox
.wc_dir
7822 A_path
= os
.path
.join(wc_dir
, 'A')
7823 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
7824 A_url
= sbox
.repo_url
+ '/A'
7825 A_mu_url
= sbox
.repo_url
+ '/A/mu'
7826 A_COPY_url
= sbox
.repo_url
+ '/A_COPY'
7827 A_COPY_path
= os
.path
.join(wc_dir
, 'A_COPY')
7828 A_COPY_mu_path
= os
.path
.join(wc_dir
, 'A_COPY', 'mu')
7829 thirty_line_dummy_text
= 'line1\n'
7830 for i
in range(2, 31):
7831 thirty_line_dummy_text
+= 'line' + str(i
) + '\n'
7833 svntest
.main
.file_write(mu_path
, thirty_line_dummy_text
)
7834 expected_output
= wc
.State(wc_dir
, {'A/mu' : Item(verb
='Sending')})
7835 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
7836 expected_status
.tweak('A/mu', wc_rev
=2)
7837 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7838 expected_status
, None, wc_dir
)
7839 svntest
.actions
.run_and_verify_svn(None, None, [],
7840 'cp', A_url
, A_COPY_url
, '-m', 'rev 3')
7841 # Update the working copy to get A_COPY
7842 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
7843 expected_status
.add({'A_COPY' : Item(status
=' '),
7844 'A_COPY/mu' : Item(status
=' '),
7845 'A_COPY/C' : Item(status
=' '),
7846 'A_COPY/D' : Item(status
=' '),
7847 'A_COPY/B' : Item(status
=' '),
7848 'A_COPY/B/lambda' : Item(status
=' '),
7849 'A_COPY/B/E' : Item(status
=' '),
7850 'A_COPY/B/E/alpha' : Item(status
=' '),
7851 'A_COPY/B/E/beta' : Item(status
=' '),
7852 'A_COPY/B/F' : Item(status
=' '),
7853 'A_COPY/D/gamma' : Item(status
=' '),
7854 'A_COPY/D/G' : Item(status
=' '),
7855 'A_COPY/D/G/pi' : Item(status
=' '),
7856 'A_COPY/D/G/rho' : Item(status
=' '),
7857 'A_COPY/D/G/tau' : Item(status
=' '),
7858 'A_COPY/D/H' : Item(status
=' '),
7859 'A_COPY/D/H/chi' : Item(status
=' '),
7860 'A_COPY/D/H/omega' : Item(status
=' '),
7861 'A_COPY/D/H/psi' : Item(status
=' ')})
7862 expected_status
.tweak(wc_rev
=3)
7863 tweaked_7th_line
= thirty_line_dummy_text
.replace('line7', 'LINE 7')
7864 svntest
.main
.file_write(mu_path
, tweaked_7th_line
)
7865 expected_status
.tweak('A/mu', wc_rev
=4)
7866 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7867 expected_status
, None, wc_dir
)
7868 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
7869 expected_status
.tweak(wc_rev
=4)
7870 tweaked_17th_line
= tweaked_7th_line
.replace('line17', 'LINE 17')
7871 svntest
.main
.file_write(mu_path
, tweaked_17th_line
)
7872 svntest
.main
.run_svn(None, 'propset', 'prop1', 'val1', A_path
)
7873 expected_output
= wc
.State(wc_dir
,
7875 'A' : Item(verb
='Sending'),
7876 'A/mu' : Item(verb
='Sending')
7879 expected_status
.tweak('A', wc_rev
=5)
7880 expected_status
.tweak('A/mu', wc_rev
=5)
7881 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7882 expected_status
, None, wc_dir
)
7883 tweaked_27th_line
= tweaked_17th_line
.replace('line27', 'LINE 27')
7884 svntest
.main
.file_write(mu_path
, tweaked_27th_line
)
7885 expected_status
.tweak('A/mu', wc_rev
=6)
7886 expected_output
= wc
.State(wc_dir
, {'A/mu' : Item(verb
='Sending')})
7887 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
7888 expected_status
, None, wc_dir
)
7889 # Merge r5 to A_COPY/mu
7890 svntest
.actions
.run_and_verify_svn(None,
7891 expected_merge_output([[5]],
7892 ['U ' + A_COPY_mu_path
+ '\n']),
7898 short_A_COPY
= shorten_path_kludge(A_COPY_path
)
7899 saved_cwd
= os
.getcwd()
7900 os
.chdir(svntest
.main
.work_dir
)
7901 expected_skip
= wc
.State(short_A_COPY
, {})
7902 expected_output
= wc
.State(short_A_COPY
, {
7903 '' : Item(status
=' U'),
7904 'mu' : Item(status
='G '),
7906 expected_status
= wc
.State(short_A_COPY
, {
7907 '' : Item(status
=' M', wc_rev
=4),
7908 'mu' : Item(status
='M ', wc_rev
=4),
7909 'C' : Item(status
=' ', wc_rev
=4),
7910 'D' : Item(status
=' ', wc_rev
=4),
7911 'B' : Item(status
=' ', wc_rev
=4),
7912 'B/lambda' : Item(status
=' ', wc_rev
=4),
7913 'B/E' : Item(status
=' ', wc_rev
=4),
7914 'B/E/alpha': Item(status
=' ', wc_rev
=4),
7915 'B/E/beta' : Item(status
=' ', wc_rev
=4),
7916 'B/F' : Item(status
=' ', wc_rev
=4),
7917 'D/gamma' : Item(status
=' ', wc_rev
=4),
7918 'D/G' : Item(status
=' ', wc_rev
=4),
7919 'D/G/pi' : Item(status
=' ', wc_rev
=4),
7920 'D/G/rho' : Item(status
=' ', wc_rev
=4),
7921 'D/G/tau' : Item(status
=' ', wc_rev
=4),
7922 'D/H' : Item(status
=' ', wc_rev
=4),
7923 'D/H/chi' : Item(status
=' ', wc_rev
=4),
7924 'D/H/omega': Item(status
=' ', wc_rev
=4),
7925 'D/H/psi' : Item(status
=' ', wc_rev
=4),
7927 expected_disk
= wc
.State('', {
7928 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:4-6',
7930 'mu' : Item(tweaked_27th_line
),
7934 'B/lambda' : Item("This is the file 'lambda'.\n"),
7936 'B/E/alpha': Item("This is the file 'alpha'.\n"),
7937 'B/E/beta' : Item("This is the file 'beta'.\n"),
7939 'D/gamma' : Item("This is the file 'gamma'.\n"),
7941 'D/G/pi' : Item("This is the file 'pi'.\n"),
7942 'D/G/rho' : Item("This is the file 'rho'.\n"),
7943 'D/G/tau' : Item("This is the file 'tau'.\n"),
7945 'D/H/chi' : Item("This is the file 'chi'.\n"),
7946 'D/H/omega': Item("This is the file 'omega'.\n"),
7947 'D/H/psi' : Item("This is the file 'psi'.\n"),
7949 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '3', '6',
7955 None, None, None, None, None, 1)
7957 # Revert r5 and r6 on A_COPY/mu
7958 svntest
.actions
.run_and_verify_svn(None,
7959 expected_merge_output([[6,5]],
7960 ['G ' + A_COPY_mu_path
+ '\n']),
7966 expected_output
= wc
.State(short_A_COPY
, {
7967 '' : Item(status
=' G'), # merged removal of prop1 property
7968 'mu' : Item(status
='G '), # merged reversion of text changes
7971 expected_status
.tweak('', status
=' ')
7972 expected_status
.tweak('mu', status
=' ')
7973 expected_disk
.tweak('', props
={})
7974 expected_disk
.remove('')
7975 expected_disk
.tweak('mu', contents
=thirty_line_dummy_text
)
7976 os
.chdir(svntest
.main
.work_dir
)
7977 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '6', '3',
7983 None, None, None, None, None, 1)
7986 expected_disk
.add({'' : Item(props
={SVN_PROP_MERGEINFO
: '/A:4-6',
7987 'prop1' : 'val1'})})
7988 expected_disk
.tweak('mu', contents
=tweaked_27th_line
)
7989 expected_output
= wc
.State(short_A_COPY
, {
7990 '' : Item(status
=' U'), # new mergeinfo and prop1 property
7991 'mu' : Item(status
='U '), # text changes
7993 expected_status
.tweak('', status
=' M')
7994 expected_status
.tweak('mu', status
='M ')
7995 os
.chdir(svntest
.main
.work_dir
)
7996 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '3', '6',
8002 None, None, None, None, None, 1)
8004 #Revert r5 on A_COPY/mu
8005 svntest
.actions
.run_and_verify_svn(None,
8006 expected_merge_output([[-5]],
8007 ['G ' + A_COPY_mu_path
+ '\n']),
8012 tweaked_17th_line_1
= tweaked_27th_line
.replace('LINE 17',
8013 'some other line17')
8014 tweaked_17th_line_2
= thirty_line_dummy_text
.replace('line17',
8015 'some other line17')
8016 svntest
.main
.file_write(A_COPY_mu_path
, tweaked_17th_line_1
)
8017 expected_output
= wc
.State(short_A_COPY
, {
8018 '' : Item(status
=' G'),
8019 'mu' : Item(status
='G '),
8021 expected_status
.tweak('', status
=' ')
8022 expected_status
.tweak('mu', status
='M ')
8023 expected_disk
.remove('')
8024 expected_disk
.tweak('mu', contents
=tweaked_17th_line_2
)
8025 os
.chdir(svntest
.main
.work_dir
)
8026 svntest
.actions
.run_and_verify_merge(short_A_COPY
, '6', '3',
8032 None, None, None, None, None, 1)
8035 def merge_old_and_new_revs_from_renamed_file(sbox
):
8036 "merge -rold(before rename):head renamed file"
8038 ## See http://svn.haxx.se/dev/archive-2007-09/0706.shtml ##
8042 wc_dir
= sbox
.wc_dir
8044 # Some paths we'll care about
8045 mu_url
= sbox
.repo_url
+ '/A/mu'
8046 mu_MOVED_url
= sbox
.repo_url
+ '/A/mu_MOVED'
8047 mu_COPY_url
= sbox
.repo_url
+ '/A/mu_COPY'
8048 mu_COPY_path
= os
.path
.join(wc_dir
, 'A', 'mu_COPY')
8049 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
8050 mu_MOVED_path
= os
.path
.join(wc_dir
, 'A', 'mu_MOVED')
8052 # Copy mu to mu_COPY
8053 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 2.\n'],
8054 [], 'cp', '-m', 'cp mu to mu_COPY',
8055 mu_url
, mu_COPY_url
)
8057 # Make a modification to A/mu
8058 svntest
.main
.file_write(mu_path
, "This is the file 'mu' modified.\n")
8059 expected_output
= wc
.State(wc_dir
, {'A/mu' : Item(verb
='Sending')})
8060 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
8061 expected_status
.tweak('A/mu', wc_rev
=3)
8062 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8063 expected_status
, None, wc_dir
)
8065 # Move mu to mu_MOVED
8066 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 4.\n'],
8067 [], 'mv', '-m', 'mv mu to mu_MOVED',
8068 mu_url
, mu_MOVED_url
)
8070 # Update the working copy to get mu_MOVED
8071 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
8073 # Make a modification to mu_MOVED
8074 svntest
.main
.file_write(mu_MOVED_path
, "This is 'mu' in mu_MOVED.\n")
8075 expected_output
= wc
.State(wc_dir
, {'A/mu_MOVED' : Item(verb
='Sending')})
8076 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 4)
8077 expected_status
.remove('A/mu')
8078 expected_status
.add({
8079 'A/mu_MOVED' : Item(status
=' ', wc_rev
=5),
8080 'A/mu_COPY' : Item(status
=' ', wc_rev
=4),
8082 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8083 expected_status
, None, wc_dir
)
8085 # Merge A/mu_MOVED to A/mu_COPY - this happens in multiple passes
8086 # because A/mu_MOVED has renames in its history between the
8087 # boundaries of the requested merge range.
8088 expected_output
= expected_merge_output([[2,3],[4,5]],
8089 ['U %s\n' % (mu_COPY_path
),
8090 'G %s\n' % (mu_COPY_path
)])
8091 svntest
.actions
.run_and_verify_svn(None, expected_output
,
8092 [], 'merge', '-r', '1:5',
8095 svntest
.actions
.run_and_verify_svn(None, ['/A/mu:2-3\n',
8096 '/A/mu_MOVED:4-5\n'],
8097 [], 'propget', SVN_PROP_MERGEINFO
,
8101 def merge_with_auto_rev_range_detection(sbox
):
8102 "merge with auto detection of revision ranges"
8104 ## See http://svn.haxx.se/dev/archive-2007-09/0735.shtml ##
8108 wc_dir
= sbox
.wc_dir
8110 # Some paths we'll care about
8111 A_url
= sbox
.repo_url
+ '/A'
8112 A_COPY_url
= sbox
.repo_url
+ '/A_COPY'
8113 B1_path
= os
.path
.join(wc_dir
, 'A', 'B1')
8114 B1_mu_path
= os
.path
.join(wc_dir
, 'A', 'B1', 'mu')
8115 A_COPY_path
= os
.path
.join(wc_dir
, 'A_COPY')
8117 # Create B1 inside A
8118 svntest
.actions
.run_and_verify_svn(None, ["A " + B1_path
+ "\n"],
8122 # Add a file mu inside B1
8123 svntest
.main
.file_write(B1_mu_path
, "This is the file 'mu'.\n")
8124 svntest
.actions
.run_and_verify_svn(None, ["A " + B1_mu_path
+ "\n"],
8125 [], 'add', B1_mu_path
)
8127 # Commit B1 and B1/mu
8128 expected_output
= wc
.State(wc_dir
, {
8129 'A/B1' : Item(verb
='Adding'),
8130 'A/B1/mu' : Item(verb
='Adding'),
8132 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
8133 expected_status
.add({
8134 'A/B1' : Item(status
=' ', wc_rev
=2),
8135 'A/B1/mu' : Item(status
=' ', wc_rev
=2),
8137 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8138 expected_status
, None, wc_dir
)
8141 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 3.\n'],
8142 [], 'cp', '-m', 'cp A to A_COPY',
8145 # Make a modification to A/B1/mu
8146 svntest
.main
.file_write(B1_mu_path
, "This is the file 'mu' modified.\n")
8147 expected_output
= wc
.State(wc_dir
, {'A/B1/mu' : Item(verb
='Sending')})
8148 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
8149 expected_status
.add({
8150 'A/B1' : Item(status
=' ', wc_rev
=2),
8151 'A/B1/mu' : Item(status
=' ', wc_rev
=4),
8153 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8154 expected_status
, None, wc_dir
)
8156 # Update the working copy to get A_COPY
8157 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
8159 short_A_COPY
= shorten_path_kludge(A_COPY_path
)
8160 saved_cwd
= os
.getcwd()
8161 os
.chdir(svntest
.main
.work_dir
)
8163 # Merge /A to /A_COPY
8164 expected_output
= wc
.State(short_A_COPY
, {
8165 'B1/mu' : Item(status
='U '),
8167 expected_status
= wc
.State(short_A_COPY
, {
8168 '' : Item(status
=' M', wc_rev
=4),
8169 'mu' : Item(status
=' ', wc_rev
=4),
8170 'C' : Item(status
=' ', wc_rev
=4),
8171 'D' : Item(status
=' ', wc_rev
=4),
8172 'B' : Item(status
=' ', wc_rev
=4),
8173 'B/lambda' : Item(status
=' ', wc_rev
=4),
8174 'B/E' : Item(status
=' ', wc_rev
=4),
8175 'B/E/alpha': Item(status
=' ', wc_rev
=4),
8176 'B/E/beta' : Item(status
=' ', wc_rev
=4),
8177 'B/F' : Item(status
=' ', wc_rev
=4),
8178 'B1' : Item(status
=' ', wc_rev
=4),
8179 'B1/mu' : Item(status
='M ', wc_rev
=4),
8180 'D/gamma' : Item(status
=' ', wc_rev
=4),
8181 'D/G' : Item(status
=' ', wc_rev
=4),
8182 'D/G/pi' : Item(status
=' ', wc_rev
=4),
8183 'D/G/rho' : Item(status
=' ', wc_rev
=4),
8184 'D/G/tau' : Item(status
=' ', wc_rev
=4),
8185 'D/H' : Item(status
=' ', wc_rev
=4),
8186 'D/H/chi' : Item(status
=' ', wc_rev
=4),
8187 'D/H/omega': Item(status
=' ', wc_rev
=4),
8188 'D/H/psi' : Item(status
=' ', wc_rev
=4),
8190 expected_disk
= wc
.State('', {
8191 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:3-4'}),
8192 'mu' : Item("This is the file 'mu'.\n"),
8196 'B/lambda' : Item("This is the file 'lambda'.\n"),
8198 'B/E/alpha': Item("This is the file 'alpha'.\n"),
8199 'B/E/beta' : Item("This is the file 'beta'.\n"),
8202 'B1/mu' : Item("This is the file 'mu' modified.\n"),
8203 'D/gamma' : Item("This is the file 'gamma'.\n"),
8205 'D/G/pi' : Item("This is the file 'pi'.\n"),
8206 'D/G/rho' : Item("This is the file 'rho'.\n"),
8207 'D/G/tau' : Item("This is the file 'tau'.\n"),
8209 'D/H/chi' : Item("This is the file 'chi'.\n"),
8210 'D/H/omega': Item("This is the file 'omega'.\n"),
8211 'D/H/psi' : Item("This is the file 'psi'.\n"),
8213 expected_skip
= wc
.State(short_A_COPY
, {})
8214 svntest
.actions
.run_and_verify_merge(short_A_COPY
, None, None,
8220 None, None, None, None, None,
8224 def mergeinfo_recording_in_skipped_merge(sbox
):
8225 "mergeinfo recording in skipped merge"
8227 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2829. ##
8229 # Create a WC with a single branch
8231 wc_dir
= sbox
.wc_dir
8232 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
8234 # Some paths we'll care about
8235 A_url
= sbox
.repo_url
+ '/A'
8236 A_COPY_path
= os
.path
.join(wc_dir
, 'A_COPY')
8237 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
8238 alpha_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'alpha')
8239 A_COPY_B_E_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B', 'E')
8240 A_COPY_alpha_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B', 'E', 'alpha')
8241 A_COPY_beta_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B', 'E', 'beta')
8243 # Make a modification to A/mu
8244 svntest
.main
.file_write(mu_path
, "This is the file 'mu' modified.\n")
8245 expected_output
= wc
.State(wc_dir
, {'A/mu' : Item(verb
='Sending')})
8246 wc_status
.add({'A/mu' : Item(status
=' ', wc_rev
=3)})
8247 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8248 wc_status
, None, wc_dir
)
8250 # Make a modification to A/B/E/alpha
8251 svntest
.main
.file_write(alpha_path
, "This is the file 'alpha' modified.\n")
8252 expected_output
= wc
.State(wc_dir
, {'A/B/E/alpha' : Item(verb
='Sending')})
8253 wc_status
.add({'A/B/E/alpha' : Item(status
=' ', wc_rev
=4)})
8254 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8255 wc_status
, None, wc_dir
)
8258 svntest
.actions
.run_and_verify_svn(None, None, [], 'rm',
8261 short_A_COPY
= shorten_path_kludge(A_COPY_path
)
8262 saved_cwd
= os
.getcwd()
8263 os
.chdir(svntest
.main
.work_dir
)
8265 # Merge /A to /A_COPY ie., r1 to r4
8266 expected_output
= wc
.State(short_A_COPY
, {
8267 'mu' : Item(status
='U '),
8269 expected_status
= wc
.State(short_A_COPY
, {
8270 '' : Item(status
=' M', wc_rev
=2),
8271 'mu' : Item(status
='M ', wc_rev
=2),
8272 'B' : Item(status
=' M', wc_rev
=2),
8273 'B/lambda' : Item(status
=' M', wc_rev
=2),
8274 'B/F' : Item(status
=' M', wc_rev
=2),
8275 'B/E' : Item(status
='D ', wc_rev
=2),
8276 'B/E/alpha': Item(status
='D ', wc_rev
=2),
8277 'B/E/beta' : Item(status
='D ', wc_rev
=2),
8278 'C' : Item(status
=' ', wc_rev
=2),
8279 'D' : Item(status
=' ', wc_rev
=2),
8280 'D/gamma' : Item(status
=' ', wc_rev
=2),
8281 'D/G' : Item(status
=' ', wc_rev
=2),
8282 'D/G/pi' : Item(status
=' ', wc_rev
=2),
8283 'D/G/rho' : Item(status
=' ', wc_rev
=2),
8284 'D/G/tau' : Item(status
=' ', wc_rev
=2),
8285 'D/H' : Item(status
=' ', wc_rev
=2),
8286 'D/H/chi' : Item(status
=' ', wc_rev
=2),
8287 'D/H/omega': Item(status
=' ', wc_rev
=2),
8288 'D/H/psi' : Item(status
=' ', wc_rev
=2),
8290 expected_disk
= wc
.State('', {
8291 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:2-4'}),
8292 'mu' : Item("This is the file 'mu' modified.\n"),
8295 'B' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2-4*'}),
8296 'B/lambda' : Item(contents
="This is the file 'lambda'.\n",
8297 props
={SVN_PROP_MERGEINFO
: '/A/B/lambda:2-4'}),
8298 'B/F' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:2-4'}),
8300 'D/gamma' : Item("This is the file 'gamma'.\n"),
8302 'D/G/pi' : Item("This is the file 'pi'.\n"),
8303 'D/G/rho' : Item("This is the file 'rho'.\n"),
8304 'D/G/tau' : Item("This is the file 'tau'.\n"),
8306 'D/H/chi' : Item("This is the file 'chi'.\n"),
8307 'D/H/omega': Item("This is the file 'omega'.\n"),
8308 'D/H/psi' : Item("This is the file 'psi'.\n"),
8310 expected_skip
= wc
.State(short_A_COPY
, {
8311 'B/E/alpha' : Item(),
8313 svntest
.actions
.run_and_verify_merge(short_A_COPY
, None, None,
8319 None, None, None, None, None,
8324 # Test for issue 2818: Provide a 'merge' API which allows for merging of
8325 # arbitrary revision ranges (e.g. '-c 3,5,7')
8326 def cherry_picking(sbox
):
8327 "command line supports cherry picked merge ranges"
8330 wc_dir
= sbox
.wc_dir
8331 wc_disk
, wc_status
= set_up_branch(sbox
)
8333 # Some paths we'll care about
8334 H_path
= os
.path
.join(wc_dir
, "A", "D", "H")
8335 G_path
= os
.path
.join(wc_dir
, "A", "D", "G")
8336 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
8337 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
8338 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
8339 H_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H")
8340 rho_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G", "rho")
8341 omega_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "omega")
8342 psi_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "psi")
8344 # Update working copy
8345 expected_output
= svntest
.wc
.State(wc_dir
, {})
8346 wc_status
.tweak(wc_rev
='6')
8347 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
8349 None, None, None, None, None, True)
8351 # Make some prop changes to some dirs.
8352 svntest
.actions
.run_and_verify_svn(None,
8353 ["property 'prop:name' set on '" +
8354 G_path
+ "'\n"], [], 'ps',
8355 'prop:name', 'propval', G_path
)
8356 expected_output
= svntest
.wc
.State(wc_dir
, {'A/D/G': Item(verb
='Sending'),})
8357 wc_status
.tweak('A/D/G', wc_rev
=7)
8358 wc_disk
.tweak('A/D/G', props
={'prop:name' : 'propval'})
8360 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
8362 svntest
.actions
.run_and_verify_svn(None,
8363 ["property 'prop:name' set on '" +
8364 H_path
+ "'\n"], [], 'ps',
8365 'prop:name', 'propval', H_path
)
8366 expected_output
= svntest
.wc
.State(wc_dir
, {'A/D/H': Item(verb
='Sending'),})
8367 wc_status
.tweak('A/D/H', wc_rev
=8)
8368 wc_disk
.tweak('A/D/H', props
={'prop:name' : 'propval'})
8369 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
8372 # Do multiple additive merges to a file"
8373 # Merge -r2:4 -c6 into A_COPY/D/G/rho.
8374 short_rho_COPY_path
= shorten_path_kludge(rho_COPY_path
)
8375 expected_skip
= wc
.State(short_rho_COPY_path
, { })
8376 saved_cwd
= os
.getcwd()
8377 os
.chdir(svntest
.main
.work_dir
)
8378 # run_and_verify_merge doesn't support merging to a file WCPATH
8379 # so use run_and_verify_svn.
8380 svntest
.actions
.run_and_verify_svn(None,
8381 expected_merge_output(
8383 'U ' + short_rho_COPY_path
+ '\n'),
8384 [], 'merge', '-r2:4', '-c6',
8385 sbox
.repo_url
+ '/A/D/G/rho',
8386 short_rho_COPY_path
)
8389 # Check rho's status and props.
8390 expected_status
= wc
.State(rho_COPY_path
,
8391 {'' : Item(status
='MM', wc_rev
=6)})
8392 svntest
.actions
.run_and_verify_status(rho_COPY_path
, expected_status
)
8393 svntest
.actions
.run_and_verify_svn(None, ["/A/D/G/rho:3-4,6\n"], [],
8394 'propget', SVN_PROP_MERGEINFO
,
8397 #Do multiple additive merges to a directory:
8398 # Merge -c6 -c8 into A_COPY/D/H
8399 short_H_COPY_path
= shorten_path_kludge(H_COPY_path
)
8400 short_omega_COPY_path
= shorten_path_kludge(omega_COPY_path
)
8401 expected_output
= expected_merge_output(
8403 ['U ' + short_omega_COPY_path
+ '\n',
8404 ' U ' + short_H_COPY_path
+ '\n'])
8405 os
.chdir(svntest
.main
.work_dir
)
8406 svntest
.actions
.run_and_verify_svn(None, expected_output
,
8407 [], 'merge', '-c6', '-c8',
8408 sbox
.repo_url
+ '/A/D/H',
8412 # Check A_COPY/D/H's status and props.
8413 expected_status
= wc
.State(H_COPY_path
,
8414 {'' : Item(status
=' M', wc_rev
=6),
8415 'psi' : Item(status
=' ', wc_rev
=6),
8416 'chi' : Item(status
=' ', wc_rev
=6),
8417 'omega': Item(status
='M ', wc_rev
=6),})
8418 svntest
.actions
.run_and_verify_status(H_COPY_path
, expected_status
)
8419 svntest
.actions
.run_and_verify_svn(None,
8420 [H_COPY_path
+ " - /A/D/H:6,8\n"],
8421 [], 'propget', '-R', SVN_PROP_MERGEINFO
,
8424 # Do multiple reverse merges to a directory:
8425 # Merge -c-6 -c-3 into A_COPY
8426 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
8427 short_omega_COPY_path
= shorten_path_kludge(omega_COPY_path
)
8428 expected_output
= expected_merge_output(
8429 [[-3],[-6]], 'G ' + short_omega_COPY_path
+ '\n')
8430 os
.chdir(svntest
.main
.work_dir
)
8431 svntest
.actions
.run_and_verify_svn(None, expected_output
,
8432 [], 'merge', '-c-3', '-c-6',
8433 sbox
.repo_url
+ '/A',
8436 expected_status
= wc
.State(A_COPY_path
,
8437 {'' : Item(status
=' ', wc_rev
=6),
8438 'B' : Item(status
=' ', wc_rev
=6),
8439 'B/lambda' : Item(status
=' ', wc_rev
=6),
8440 'B/E' : Item(status
=' ', wc_rev
=6),
8441 'B/E/alpha' : Item(status
=' ', wc_rev
=6),
8442 'B/E/beta' : Item(status
=' ', wc_rev
=6),
8443 'B/F' : Item(status
=' ', wc_rev
=6),
8444 'mu' : Item(status
=' ', wc_rev
=6),
8445 'C' : Item(status
=' ', wc_rev
=6),
8446 'D' : Item(status
=' ', wc_rev
=6),
8447 'D/gamma' : Item(status
=' ', wc_rev
=6),
8448 'D/G' : Item(status
=' ', wc_rev
=6),
8449 'D/G/pi' : Item(status
=' ', wc_rev
=6),
8450 'D/G/rho' : Item(status
='MM', wc_rev
=6),
8451 'D/G/tau' : Item(status
=' ', wc_rev
=6),
8452 'D/H' : Item(status
=' M', wc_rev
=6),
8453 'D/H/chi' : Item(status
=' ', wc_rev
=6),
8454 'D/H/psi' : Item(status
=' ', wc_rev
=6),
8455 'D/H/omega' : Item(status
=' ', wc_rev
=6),})
8456 svntest
.actions
.run_and_verify_status(A_COPY_path
, expected_status
)
8457 expected_out
= H_COPY_path
+ " - /A/D/H:8\n|" + \
8458 rho_COPY_path
+ " - /A/D/G/rho:4\n"
8459 # Construct proper regex for '\' infested Windows paths.
8460 if sys
.platform
== 'win32':
8461 expected_out
= expected_out
.replace("\\", "\\\\")
8462 svntest
.actions
.run_and_verify_svn(None, expected_out
, [],
8463 'propget', '-R', SVN_PROP_MERGEINFO
,
8466 # Do both additive and reverse merges to a directory:
8467 # Merge -r2:3 -c-4 -r4:7 to A_COPY/D
8468 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
8469 short_psi_COPY_path
= shorten_path_kludge(psi_COPY_path
)
8470 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
8471 expected_output
= expected_merge_output(
8473 [' U ' + short_G_COPY_path
+ '\n',
8474 'U ' + short_omega_COPY_path
+ '\n',
8475 'U ' + short_psi_COPY_path
+ '\n',
8476 'G ' + short_rho_COPY_path
+ '\n'])
8478 os
.chdir(svntest
.main
.work_dir
)
8479 svntest
.actions
.run_and_verify_svn(None, expected_output
, [], 'merge',
8480 '-r2:3', '-c-4', '-r4:7',
8481 sbox
.repo_url
+ '/A/D',
8484 expected_status
= wc
.State(D_COPY_path
,
8485 {'' : Item(status
=' M', wc_rev
=6),
8486 'gamma' : Item(status
=' ', wc_rev
=6),
8487 'G' : Item(status
=' M', wc_rev
=6),
8488 'G/pi' : Item(status
=' ', wc_rev
=6),
8489 'G/rho' : Item(status
=' ', wc_rev
=6),
8490 'G/tau' : Item(status
=' ', wc_rev
=6),
8491 'H' : Item(status
=' M', wc_rev
=6),
8492 'H/chi' : Item(status
=' ', wc_rev
=6),
8493 'H/psi' : Item(status
='M ', wc_rev
=6),
8494 'H/omega' : Item(status
='M ', wc_rev
=6),})
8495 svntest
.actions
.run_and_verify_status(D_COPY_path
, expected_status
)
8496 expected_out
= D_COPY_path
+ " - /A/D:3,5-7\n|" + \
8497 H_COPY_path
+ " - /A/D/H:3,5-8\n"
8498 # Construct proper regex for '\' infested Windows paths.
8499 if sys
.platform
== 'win32':
8500 expected_out
= expected_out
.replace("\\", "\\\\")
8501 svntest
.actions
.run_and_verify_svn(None, expected_out
, [],
8502 'propget', '-R', SVN_PROP_MERGEINFO
,
8505 def propchange_of_subdir_raises_conflict(sbox
):
8506 "merge of propchange on subdir raises conflict"
8508 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2969. ##
8510 # Create a WC with a single branch
8512 wc_dir
= sbox
.wc_dir
8513 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
8515 # Some paths we'll care about
8516 B_url
= sbox
.repo_url
+ '/A/B'
8517 E_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E')
8518 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
8519 A_COPY_B_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B')
8520 A_COPY_B_E_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B', 'E')
8521 A_COPY_lambda_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B', 'E', 'lambda')
8523 # Set a property on A/B/E and Make a modification to A/B/lambda
8524 svntest
.main
.run_svn(None, 'propset', 'x', 'x', E_path
)
8526 svntest
.main
.file_write(lambda_path
, "This is the file 'lambda' modified.\n")
8527 expected_output
= wc
.State(wc_dir
, {
8528 'A/B/lambda' : Item(verb
='Sending'),
8529 'A/B/E' : Item(verb
='Sending'),
8532 'A/B/lambda' : Item(status
=' ', wc_rev
=3),
8533 'A/B/E' : Item(status
=' ', wc_rev
=3),
8535 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8536 wc_status
, None, wc_dir
)
8538 short_A_COPY_B
= shorten_path_kludge(A_COPY_B_path
)
8539 saved_cwd
= os
.getcwd()
8540 os
.chdir(svntest
.main
.work_dir
)
8542 # Merge /A/B to /A_COPY/B ie., r1 to r3 with depth files
8543 expected_output
= wc
.State(short_A_COPY_B
, {
8544 'lambda' : Item(status
='U '),
8546 expected_disk
= wc
.State('', {
8547 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2-3*'}),
8548 'lambda' : Item(contents
="This is the file 'lambda' modified.\n",
8549 props
={SVN_PROP_MERGEINFO
: '/A/B/lambda:2-3'}),
8552 'E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
8553 'E/beta' : Item(contents
="This is the file 'beta'.\n"),
8555 expected_status
= wc
.State(short_A_COPY_B
, {
8556 '' : Item(status
=' M', wc_rev
=2),
8557 'lambda' : Item(status
='MM', wc_rev
=2),
8558 'F' : Item(status
=' ', wc_rev
=2),
8559 'E' : Item(status
=' ', wc_rev
=2),
8560 'E/alpha' : Item(status
=' ', wc_rev
=2),
8561 'E/beta' : Item(status
=' ', wc_rev
=2),
8563 expected_skip
= wc
.State(short_A_COPY_B
, {})
8565 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, None, None,
8571 None, None, None, None, None,
8572 1, 1, '--depth', 'files')
8574 # Merge /A/B to /A_COPY/B ie., r1 to r3 with infinite depth
8575 expected_output
= wc
.State(short_A_COPY_B
, {
8576 'E' : Item(status
=' U'),
8578 expected_disk
= wc
.State('', {
8579 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2-3'}),
8580 'lambda' : Item(contents
="This is the file 'lambda' modified.\n"),
8582 'E' : Item(props
={'x': 'x'}),
8583 'E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
8584 'E/beta' : Item(contents
="This is the file 'beta'.\n"),
8586 expected_status
= wc
.State(short_A_COPY_B
, {
8587 '' : Item(status
=' M', wc_rev
=2),
8588 'lambda' : Item(status
='M ', wc_rev
=2),
8589 'F' : Item(status
=' ', wc_rev
=2),
8590 'E' : Item(status
=' M', wc_rev
=2),
8591 'E/alpha' : Item(status
=' ', wc_rev
=2),
8592 'E/beta' : Item(status
=' ', wc_rev
=2),
8595 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, None, None,
8601 None, None, None, None, None,
8606 # Test for issue #2971: Reverse merge of prop add segfaults if
8607 # merging to parent of first merge
8608 def reverse_merge_prop_add_on_child(sbox
):
8609 "reverse merge of prop add on child"
8612 wc_dir
= sbox
.wc_dir
8613 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
8615 # Some paths we'll care about
8616 G_path
= os
.path
.join(wc_dir
, "A", "D", "G")
8617 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
8618 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
8620 # Make some prop changes to some dirs.
8621 svntest
.actions
.run_and_verify_svn(None,
8622 ["property 'prop:name' set on '" +
8623 G_path
+ "'\n"], [], 'ps',
8624 'prop:name', 'propval', G_path
)
8625 expected_output
= svntest
.wc
.State(wc_dir
, {'A/D/G': Item(verb
='Sending'),})
8626 wc_status
.tweak('A/D/G', wc_rev
=3)
8627 wc_disk
.tweak('A/D/G', props
={'prop:name' : 'propval'})
8629 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
, wc_status
,
8632 # Merge -c3's prop add to A_COPY/D/G
8633 saved_cwd
= os
.getcwd()
8634 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
8635 expected_output
= wc
.State(short_G_COPY_path
, {
8636 '' : Item(status
=' U')
8638 expected_status
= wc
.State(short_G_COPY_path
, {
8639 '' : Item(status
=' M', wc_rev
=2),
8640 'pi' : Item(status
=' ', wc_rev
=2),
8641 'rho' : Item(status
=' ', wc_rev
=2),
8642 'tau' : Item(status
=' ', wc_rev
=2),
8644 expected_disk
= wc
.State('', {
8645 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:3',
8646 'prop:name' : 'propval'}),
8647 'pi' : Item("This is the file 'pi'.\n"),
8648 'rho' : Item("This is the file 'rho'.\n"),
8649 'tau' : Item("This is the file 'tau'.\n"),
8651 expected_skip
= wc
.State(short_G_COPY_path
, { })
8652 os
.chdir(svntest
.main
.work_dir
)
8653 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '2', '3',
8660 None, None, None, None,
8664 # Now merge -c-3 but target the previous target's parent instead.
8665 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
8666 expected_output
= wc
.State(short_D_COPY_path
, {
8667 'G' : Item(status
=' G'),
8669 expected_status
= wc
.State(short_D_COPY_path
, {
8670 '' : Item(status
=' ', wc_rev
=2),
8671 'G' : Item(status
=' ', wc_rev
=2),
8672 'G/pi' : Item(status
=' ', wc_rev
=2),
8673 'G/rho' : Item(status
=' ', wc_rev
=2),
8674 'G/tau' : Item(status
=' ', wc_rev
=2),
8675 'H' : Item(status
=' ', wc_rev
=2),
8676 'H/chi' : Item(status
=' ', wc_rev
=2),
8677 'H/psi' : Item(status
=' ', wc_rev
=2),
8678 'H/omega' : Item(status
=' ', wc_rev
=2),
8679 'gamma' : Item(status
=' ', wc_rev
=2),
8681 expected_disk
= wc
.State('', {
8683 'G/pi' : Item("This is the file 'pi'.\n"),
8684 'G/rho' : Item("This is the file 'rho'.\n"),
8685 'G/tau' : Item("This is the file 'tau'.\n"),
8687 'H/chi' : Item("This is the file 'chi'.\n"),
8688 'H/psi' : Item("This is the file 'psi'.\n"),
8689 'H/omega' : Item("This is the file 'omega'.\n"),
8690 'gamma' : Item("This is the file 'gamma'.\n")
8692 expected_skip
= wc
.State(short_D_COPY_path
, { })
8693 os
.chdir(svntest
.main
.work_dir
)
8694 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '3', '2',
8701 None, None, None, None,
8705 def merge_target_with_non_inheritable_mergeinfo(sbox
):
8706 "merge target with non inheritable mergeinfo"
8708 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2970. ##
8710 # Create a WC with a single branch
8712 wc_dir
= sbox
.wc_dir
8713 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
8715 # Some paths we'll care about
8716 B_url
= sbox
.repo_url
+ '/A/B'
8717 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
8718 newfile_path
= os
.path
.join(wc_dir
, 'A', 'B', 'E', 'newfile')
8719 A_COPY_B_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B')
8721 # Make a modifications to A/B/lambda and add A/B/E/newfile
8722 svntest
.main
.file_write(lambda_path
, "This is the file 'lambda' modified.\n")
8723 svntest
.main
.file_write(newfile_path
, "This is the file 'newfile'.\n")
8724 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', newfile_path
)
8725 expected_output
= wc
.State(wc_dir
, {
8726 'A/B/lambda' : Item(verb
='Sending'),
8727 'A/B/E/newfile' : Item(verb
='Adding'),
8730 'A/B/lambda' : Item(status
=' ', wc_rev
=3),
8731 'A/B/E/newfile' : Item(status
=' ', wc_rev
=3),
8733 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8734 wc_status
, None, wc_dir
)
8736 short_A_COPY_B
= shorten_path_kludge(A_COPY_B_path
)
8737 saved_cwd
= os
.getcwd()
8738 os
.chdir(svntest
.main
.work_dir
)
8740 # Merge /A/B to /A_COPY/B ie., r1 to r3 with depth immediates
8741 expected_output
= wc
.State(short_A_COPY_B
, {
8742 'lambda' : Item(status
='U '),
8744 expected_disk
= wc
.State('', {
8745 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:1-3'}),
8746 'lambda' : Item(contents
="This is the file 'lambda' modified.\n"),
8747 'F' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/F:1,2-3*'}),
8748 'E' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B/E:1,2-3*'}),
8749 'E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
8750 'E/beta' : Item(contents
="This is the file 'beta'.\n"),
8752 expected_status
= wc
.State(short_A_COPY_B
, {
8753 '' : Item(status
=' M', wc_rev
=2),
8754 'lambda' : Item(status
='M ', wc_rev
=2),
8755 'F' : Item(status
=' M', wc_rev
=2),
8756 'E' : Item(status
=' M', wc_rev
=2),
8757 'E/alpha' : Item(status
=' ', wc_rev
=2),
8758 'E/beta' : Item(status
=' ', wc_rev
=2),
8760 expected_skip
= wc
.State(short_A_COPY_B
, {})
8762 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, None, None,
8768 None, None, None, None, None,
8769 1, 1, '--depth', 'immediates')
8771 # Merge /A/B to /A_COPY/B ie., r1 to r3 with infinite depth
8772 expected_output
= wc
.State(short_A_COPY_B
, {
8773 'E/newfile' : Item(status
='A '),
8775 expected_disk
= wc
.State('', {
8776 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:1-3'}),
8777 'lambda' : Item(contents
="This is the file 'lambda' modified.\n"),
8780 'E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
8781 'E/beta' : Item(contents
="This is the file 'beta'.\n"),
8782 'E/newfile' : Item(contents
="This is the file 'newfile'.\n"),
8784 expected_status
= wc
.State(short_A_COPY_B
, {
8785 '' : Item(status
=' M', wc_rev
=2),
8786 'lambda' : Item(status
='M ', wc_rev
=2),
8787 'F' : Item(status
=' ', wc_rev
=2),
8788 'E' : Item(status
=' ', wc_rev
=2),
8789 'E/alpha' : Item(status
=' ', wc_rev
=2),
8790 'E/beta' : Item(status
=' ', wc_rev
=2),
8791 'E/newfile' : Item(status
='A ', wc_rev
=2),
8794 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, None, None,
8800 None, None, None, None, None,
8805 def self_reverse_merge(sbox
):
8806 "revert a commit on a target"
8809 wc_dir
= sbox
.wc_dir
8811 # Make changes to the working copy
8812 mu_path
= os
.path
.join(wc_dir
, 'A', 'mu')
8813 svntest
.main
.file_append(mu_path
, 'appended mu text')
8815 # Created expected output tree for 'svn ci'
8816 expected_output
= wc
.State(wc_dir
, {
8817 'A/mu' : Item(verb
='Sending'),
8820 # Create expected status tree; all local revisions should be at 1,
8821 # but mu should be at revision 2.
8822 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 1)
8823 expected_status
.tweak('A/mu', wc_rev
=2)
8825 svntest
.actions
.run_and_verify_commit(wc_dir
,
8831 # update to HEAD so that the to-be-undone revision is found in the
8832 # implicit mergeinfo (the natural history) of the target.
8833 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
)
8835 expected_output
= wc
.State(wc_dir
, {
8836 'A/mu' : Item(status
='U ')
8838 expected_skip
= wc
.State(wc_dir
, { })
8839 expected_disk
= svntest
.main
.greek_state
.copy()
8840 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
8841 expected_status
.tweak('A/mu', status
='M ')
8842 svntest
.actions
.run_and_verify_merge(wc_dir
, '2', '1', sbox
.repo_url
,
8843 expected_output
, expected_disk
,
8844 expected_status
, expected_skip
,
8845 None, None, None, None, None, 1, 1)
8846 svntest
.actions
.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir
)
8848 # record dummy self mergeinfo to test the fact that self-reversal should work
8849 # irrespective of mergeinfo.
8850 svntest
.actions
.run_and_verify_svn(None, None, [], 'merge', '-c', '1',
8851 '--record-only', sbox
.repo_url
, wc_dir
)
8853 # Bad svntest.main.greek_state does not have '', so adding it explicitly.
8854 expected_disk
.add({'' : Item(props
={SVN_PROP_MERGEINFO
: '/:1'})})
8855 expected_status
= svntest
.actions
.get_virginal_state(wc_dir
, 2)
8856 expected_status
.tweak('', status
= ' M')
8857 expected_status
.tweak('A/mu', status
= 'M ')
8858 svntest
.actions
.run_and_verify_merge(wc_dir
, '2', '1', sbox
.repo_url
,
8859 expected_output
, expected_disk
,
8860 expected_status
, expected_skip
,
8861 None, None, None, None, None, 1, 1)
8863 def ignore_ancestry_and_mergeinfo(sbox
):
8864 "--ignore-ancestry also ignores mergeinfo"
8866 # Create a WC with a single branch
8868 wc_dir
= sbox
.wc_dir
8869 wc_disk
, wc_status
= set_up_branch(sbox
, True, 1)
8871 # Some paths we'll care about
8872 A_B_url
= sbox
.repo_url
+ '/A/B'
8873 A_COPY_B_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B')
8874 lambda_path
= os
.path
.join(wc_dir
, 'A', 'B', 'lambda')
8875 A_COPY_lambda_path
= os
.path
.join(wc_dir
, 'A_COPY', 'B', 'lambda')
8877 # Make modifications to A/B/lambda
8878 svntest
.main
.file_write(lambda_path
, "This is the file 'lambda' modified.\n")
8879 expected_output
= wc
.State(wc_dir
, {
8880 'A/B/lambda' : Item(verb
='Sending'),
8883 'A/B/lambda' : Item(status
=' ', wc_rev
=3),
8885 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
8886 wc_status
, None, wc_dir
)
8888 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
8890 short_A_COPY_B
= shorten_path_kludge(A_COPY_B_path
)
8891 short_A_COPY_lambda
= shorten_path_kludge(A_COPY_lambda_path
)
8892 saved_cwd
= os
.getcwd()
8893 os
.chdir(svntest
.main
.work_dir
)
8895 # Merge /A/B to /A_COPY/B ie., r1 to r3 with depth immediates
8896 expected_output
= wc
.State(short_A_COPY_B
, {
8897 'lambda' : Item(status
='U '),
8899 expected_disk
= wc
.State('', {
8900 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/B:2-3'}),
8901 'lambda' : Item(contents
="This is the file 'lambda' modified.\n"),
8902 'F' : Item(props
={}),
8903 'E' : Item(props
={}),
8904 'E/alpha' : Item(contents
="This is the file 'alpha'.\n"),
8905 'E/beta' : Item(contents
="This is the file 'beta'.\n"),
8907 expected_status
= wc
.State(short_A_COPY_B
, {
8908 '' : Item(status
=' M', wc_rev
=3),
8909 'lambda' : Item(status
='M ', wc_rev
=3),
8910 'F' : Item(status
=' ', wc_rev
=3),
8911 'E' : Item(status
=' ', wc_rev
=3),
8912 'E/alpha' : Item(status
=' ', wc_rev
=3),
8913 'E/beta' : Item(status
=' ', wc_rev
=3),
8915 expected_skip
= wc
.State(short_A_COPY_B
, {})
8917 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, 1, 3,
8923 None, None, None, None, None, 1, 1)
8925 # Now, revert lambda and repeat the merge. Nothing should happen.
8926 svntest
.actions
.run_and_verify_svn(None, None, [], 'revert', '-R',
8927 short_A_COPY_lambda
)
8928 expected_output
.remove('lambda')
8929 expected_disk
.tweak('lambda', contents
="This is the file 'lambda'.\n")
8930 expected_status
.tweak('lambda', status
=' ')
8931 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, 1, 3,
8937 None, None, None, None, None, 1, 1)
8939 # Now, try the merge again with --ignore-ancestry. We should get
8940 # lambda re-modified. */
8941 expected_output
= wc
.State(short_A_COPY_B
, {
8942 'lambda' : Item(status
='U '),
8944 expected_disk
.tweak('lambda',
8945 contents
="This is the file 'lambda' modified.\n")
8946 expected_status
.tweak('lambda', status
='M ')
8947 svntest
.actions
.run_and_verify_merge(short_A_COPY_B
, 1, 3,
8953 None, None, None, None, None, 1, 1,
8954 '--ignore-ancestry')
8958 def merge_from_renamed_branch_fails_while_avoiding_repeat_merge(sbox
):
8959 "merge from renamed branch"
8960 #Copy A/C to A/COPY_C results in r2.
8961 #Rename A/COPY_C to A/RENAMED_C results in r3.
8962 #Add A/RENAMED_C/file1 and commit, results in r4.
8963 #Change A/RENAMED_C/file1 and commit, results in r5.
8964 #Merge r4 from A/RENAMED_C to A/C
8965 #Merge r2:5 from A/RENAMED_C to A/C <-- This fails tracked via #3032.
8967 ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3032. ##
8969 # Create a WC with a single branch
8971 wc_dir
= sbox
.wc_dir
8972 # Some paths we'll care about
8973 A_C_url
= sbox
.repo_url
+ '/A/C'
8974 A_COPY_C_url
= sbox
.repo_url
+ '/A/COPY_C'
8975 A_RENAMED_C_url
= sbox
.repo_url
+ '/A/RENAMED_C'
8976 A_C_path
= os
.path
.join(wc_dir
, 'A', 'C')
8977 A_RENAMED_C_path
= os
.path
.join(wc_dir
, 'A', 'RENAMED_C')
8978 A_RENAMED_C_file1_path
= os
.path
.join(wc_dir
, 'A', 'RENAMED_C', 'file1')
8980 svntest
.main
.run_svn(None, 'cp', A_C_url
, A_COPY_C_url
, '-m', 'copy...')
8981 svntest
.main
.run_svn(None, 'mv', A_COPY_C_url
, A_RENAMED_C_url
, '-m',
8983 svntest
.actions
.run_and_verify_svn(None, None, [], 'up', wc_dir
)
8985 svntest
.main
.file_write(A_RENAMED_C_file1_path
, "This is the file1.\n")
8986 svntest
.main
.run_svn(None, 'add', A_RENAMED_C_file1_path
)
8987 expected_output
= wc
.State(A_RENAMED_C_path
, {
8988 'file1' : Item(verb
='Adding'),
8990 expected_status
= wc
.State(A_RENAMED_C_path
, {
8991 '' : Item(status
=' ', wc_rev
=3),
8992 'file1' : Item(status
=' ', wc_rev
=4),
8994 svntest
.actions
.run_and_verify_commit(A_RENAMED_C_path
, expected_output
,
8995 expected_status
, None,
8997 svntest
.main
.file_write(A_RENAMED_C_file1_path
,
8998 "This is the file1 modified.\n")
8999 expected_output
= wc
.State(A_RENAMED_C_path
, {
9000 'file1' : Item(verb
='Sending'),
9002 expected_status
.tweak('file1', wc_rev
=5)
9003 svntest
.actions
.run_and_verify_commit(A_RENAMED_C_path
, expected_output
,
9004 expected_status
, None,
9007 short_A_C
= shorten_path_kludge(A_C_path
)
9008 expected_skip
= wc
.State(short_A_C
, {})
9009 expected_output
= wc
.State(short_A_C
, {
9010 'file1' : Item(status
='A '),
9012 expected_disk
= wc
.State('', {
9013 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/RENAMED_C:4'}),
9014 'file1' : Item("This is the file1.\n"),
9016 expected_status
= wc
.State(short_A_C
, {
9017 '' : Item(status
=' M', wc_rev
=3),
9018 'file1' : Item(status
='A ', wc_rev
='-', copied
='+'),
9020 saved_cwd
= os
.getcwd()
9021 os
.chdir(svntest
.main
.work_dir
)
9022 svntest
.actions
.run_and_verify_merge(short_A_C
, 3, 4,
9028 None, None, None, None, None, 1, 1)
9030 expected_output
= wc
.State(short_A_C
, {
9031 'file1' : Item(status
='U '),
9033 expected_disk
= wc
.State('', {
9034 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/RENAMED_C:3-5'}),
9035 'file1' : Item("This is the file1 modified.\n"),
9037 expected_status
= wc
.State(short_A_C
, {
9038 '' : Item(status
=' M', wc_rev
=3),
9039 'file1' : Item(status
='A ', wc_rev
='-', copied
='+'),
9041 svntest
.actions
.run_and_verify_merge(short_A_C
, 2, 5,
9047 None, None, None, None, None, 1, 1)
9050 # Test for part of issue #2877: 'do subtree merge only if subtree has
9051 # explicit mergeinfo set and exists in the merge source'
9052 def merge_source_normalization_and_subtree_merges(sbox
):
9053 "normalized mergeinfo is recorded on subtrees"
9056 wc_dir
= sbox
.wc_dir
9058 # Some paths we'll care about
9059 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
9060 G_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "G")
9062 # Use our helper to copy 'A' to 'A_COPY' then make some changes under 'A'
9063 wc_disk
, wc_status
= set_up_branch(sbox
)
9065 # r7 - Move A to A_MOVED
9066 svntest
.actions
.run_and_verify_svn(None, ['\n', 'Committed revision 7.\n'],
9067 [], 'mv', '-m', 'mv A to A_MOVED',
9068 sbox
.repo_url
+ '/A',
9069 sbox
.repo_url
+ '/A_MOVED')
9071 'A_MOVED/B' : Item(),
9072 'A_MOVED/B/lambda' : Item(),
9073 'A_MOVED/B/E' : Item(),
9074 'A_MOVED/B/E/alpha' : Item(),
9075 'A_MOVED/B/E/beta' : Item(),
9076 'A_MOVED/B/F' : Item(),
9077 'A_MOVED/mu' : Item(),
9078 'A_MOVED/C' : Item(),
9079 'A_MOVED/D' : Item(),
9080 'A_MOVED/D/gamma' : Item(),
9081 'A_MOVED/D/G' : Item(),
9082 'A_MOVED/D/G/pi' : Item(),
9083 'A_MOVED/D/G/rho' : Item(),
9084 'A_MOVED/D/G/tau' : Item(),
9085 'A_MOVED/D/H' : Item(),
9086 'A_MOVED/D/H/chi' : Item(),
9087 'A_MOVED/D/H/omega' : Item(),
9088 'A_MOVED/D/H/psi' : Item(),
9089 'A_MOVED' : Item()})
9090 wc_status
.remove('A', 'A/B', 'A/B/lambda', 'A/B/E', 'A/B/E/alpha',
9091 'A/B/E/beta', 'A/B/F', 'A/mu', 'A/C', 'A/D',
9092 'A/D/gamma', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho',
9093 'A/D/G/tau' , 'A/D/H', 'A/D/H/chi', 'A/D/H/omega',
9095 wc_status
.tweak(status
=' ', wc_rev
=7)
9098 svntest
.actions
.run_and_verify_svn(None, None, [],
9101 # r8 - Make a text mod to 'A_MOVED/D/G/tau'
9102 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A_MOVED", "D", "G", "tau"),
9104 expected_output
= wc
.State(wc_dir
,
9105 {'A_MOVED/D/G/tau' : Item(verb
='Sending')})
9106 wc_status
.tweak('A_MOVED/D/G/tau', status
=' ', wc_rev
=8)
9107 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9108 wc_status
, None, wc_dir
)
9110 # Merge -c4 URL/A_MOVED/D/G A_COPY/D/G.
9112 # Search for the comment entitled "The Merge Kluge" elsewhere in
9113 # this file, to understand why we shorten and chdir() below.
9115 # A_MOVED/D/G doesn't exist at r3:4, it's still A/D/G,
9116 # so the merge source normalization logic should set
9117 # mergeinfo of '/A/D/G:4' on A_COPY/D/G, *not* 'A_MOVED/D/G:4',
9119 short_G_COPY_path
= shorten_path_kludge(G_COPY_path
)
9120 expected_output
= wc
.State(short_G_COPY_path
, {
9121 'rho' : Item(status
='U ')
9123 expected_status
= wc
.State(short_G_COPY_path
, {
9124 '' : Item(status
=' M', wc_rev
=7),
9125 'pi' : Item(status
=' ', wc_rev
=7),
9126 'rho' : Item(status
='M ', wc_rev
=7),
9127 'tau' : Item(status
=' ', wc_rev
=7),
9129 expected_disk
= wc
.State('', {
9130 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G:4'}),
9131 'pi' : Item("This is the file 'pi'.\n"),
9132 'rho' : Item("New content"),
9133 'tau' : Item("This is the file 'tau'.\n"),
9135 expected_skip
= wc
.State(short_G_COPY_path
, { })
9136 saved_cwd
= os
.getcwd()
9137 os
.chdir(svntest
.main
.work_dir
)
9138 svntest
.actions
.run_and_verify_merge(short_G_COPY_path
, '3', '4',
9139 sbox
.repo_url
+ '/A_MOVED/D/G',
9144 None, None, None, None,
9148 # Merge -c8 URL/A_MOVED/D A_COPY/D.
9150 # The merge target A_COPY/D and the subtree at A_COPY/D/G
9151 # should both have their mergeinfo updated with r8
9152 # from A_MOVED_D, see reopened issue #2877.
9153 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
9154 expected_output
= wc
.State(short_D_COPY_path
, {
9155 'G/tau' : Item(status
='U '),
9157 expected_status
= wc
.State(short_D_COPY_path
, {
9158 '' : Item(status
=' M', wc_rev
=7),
9159 'G' : Item(status
=' M', wc_rev
=7),
9160 'G/pi' : Item(status
=' ', wc_rev
=7),
9161 'G/rho' : Item(status
='M ', wc_rev
=7),
9162 'G/tau' : Item(status
='M ', wc_rev
=7),
9163 'H' : Item(status
=' ', wc_rev
=7),
9164 'H/chi' : Item(status
=' ', wc_rev
=7),
9165 'H/psi' : Item(status
=' ', wc_rev
=7),
9166 'H/omega' : Item(status
=' ', wc_rev
=7),
9167 'gamma' : Item(status
=' ', wc_rev
=7),
9169 expected_disk
= wc
.State('', {
9170 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A_MOVED/D:8'}),
9171 'G' : Item(props
={SVN_PROP_MERGEINFO
:
9172 '/A/D/G:4\n/A_MOVED/D/G:8\n'}),
9173 'G/pi' : Item("This is the file 'pi'.\n"),
9174 'G/rho' : Item("New content"),
9175 'G/tau' : Item("New content"),
9177 'H/chi' : Item("This is the file 'chi'.\n"),
9178 'H/psi' : Item("This is the file 'psi'.\n"),
9179 'H/omega' : Item("This is the file 'omega'.\n"),
9180 'gamma' : Item("This is the file 'gamma'.\n")
9182 expected_skip
= wc
.State(short_D_COPY_path
, { })
9183 os
.chdir(svntest
.main
.work_dir
)
9184 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '7', '8',
9191 None, None, None, None,
9195 # Test for issue #3067: 'subtrees with intersecting mergeinfo, that don't
9196 # exist at the start of a merge range shouldn't break the merge'
9197 def new_subtrees_should_not_break_merge(sbox
):
9198 "subtrees added after start of merge range are ok"
9201 wc_dir
= sbox
.wc_dir
9202 wc_disk
, wc_status
= set_up_branch(sbox
)
9204 # Some paths we'll care about
9205 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
9206 D_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D")
9207 nu_path
= os
.path
.join(wc_dir
, "A", "D", "H", "nu")
9208 nu_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H", "nu")
9209 H_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "D", "H")
9211 # Create 'A/D/H/nu', commit it as r7, make a text mod to it in r8.
9212 svntest
.main
.file_write(nu_path
, "This is the file 'nu'.\n")
9213 svntest
.actions
.run_and_verify_svn(None, None, [], 'add', nu_path
)
9214 expected_output
= wc
.State(wc_dir
, {'A/D/H/nu' : Item(verb
='Adding')})
9215 wc_status
.add({'A/D/H/nu' : Item(status
=' ', wc_rev
=7)})
9216 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9217 wc_status
, None, wc_dir
)
9218 svntest
.main
.file_write(nu_path
, "New content")
9219 expected_output
= wc
.State(wc_dir
, {'A/D/H/nu' : Item(verb
='Sending')})
9220 wc_status
.tweak('A/D/H/nu', wc_rev
=8)
9221 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9222 wc_status
, None, wc_dir
)
9224 # Merge r7 to A_COPY/D/H, then, so it has it's own explicit mergeinfo,
9225 # then merge r8 to A_COPY/D/H/nu so it too has explicit mergeinfo.
9226 short_H_COPY_path
= shorten_path_kludge(H_COPY_path
)
9227 expected_output
= wc
.State(short_H_COPY_path
, {
9228 'nu' : Item(status
='A '),
9230 expected_status
= wc
.State(short_H_COPY_path
, {
9231 '' : Item(status
=' M', wc_rev
=2),
9232 'psi' : Item(status
=' ', wc_rev
=2),
9233 'omega' : Item(status
=' ', wc_rev
=2),
9234 'chi' : Item(status
=' ', wc_rev
=2),
9235 'nu' : Item(status
='A ', copied
='+', wc_rev
='-'),
9237 expected_disk
= wc
.State('', {
9238 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:7'}),
9239 'psi' : Item("This is the file 'psi'.\n"),
9240 'omega' : Item("This is the file 'omega'.\n"),
9241 'chi' : Item("This is the file 'chi'.\n"),
9242 'nu' : Item("This is the file 'nu'.\n"),
9244 expected_skip
= wc
.State(short_H_COPY_path
, {})
9245 saved_cwd
= os
.getcwd()
9246 os
.chdir(svntest
.main
.work_dir
)
9247 svntest
.actions
.run_and_verify_merge(short_H_COPY_path
, '6', '7',
9248 sbox
.repo_url
+ '/A/D/H',
9249 expected_output
, expected_disk
,
9250 expected_status
, expected_skip
,
9251 None, None, None, None, None, 1)
9252 # run_and_verify_merge doesn't support merging to a file WCPATH
9253 # so use run_and_verify_svn.
9254 short_nu_COPY_path
= shorten_path_kludge(nu_COPY_path
)
9255 svntest
.actions
.run_and_verify_svn(None,
9256 expected_merge_output([[8]],
9257 'U ' + short_nu_COPY_path
+ '\n'),
9259 sbox
.repo_url
+ '/A/D/H/nu',
9261 # Merge -r4:6 to A_COPY, then reverse merge r6 from A_COPY/D.
9262 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
9263 expected_output
= wc
.State(short_A_COPY_path
, {
9264 'B/E/beta' : Item(status
='U '),
9265 'D/H/omega': Item(status
='U '),
9267 expected_status
= wc
.State(short_A_COPY_path
, {
9268 '' : Item(status
=' M', wc_rev
=2),
9269 'B' : Item(status
=' ', wc_rev
=2),
9270 'mu' : Item(status
=' ', wc_rev
=2),
9271 'B/E' : Item(status
=' ', wc_rev
=2),
9272 'B/E/alpha' : Item(status
=' ', wc_rev
=2),
9273 'B/E/beta' : Item(status
='M ', wc_rev
=2),
9274 'B/lambda' : Item(status
=' ', wc_rev
=2),
9275 'B/F' : Item(status
=' ', wc_rev
=2),
9276 'C' : Item(status
=' ', wc_rev
=2),
9277 'D' : Item(status
=' ', wc_rev
=2),
9278 'D/G' : Item(status
=' ', wc_rev
=2),
9279 'D/G/pi' : Item(status
=' ', wc_rev
=2),
9280 'D/G/rho' : Item(status
=' ', wc_rev
=2),
9281 'D/G/tau' : Item(status
=' ', wc_rev
=2),
9282 'D/gamma' : Item(status
=' ', wc_rev
=2),
9283 'D/H' : Item(status
=' M', wc_rev
=2),
9284 'D/H/chi' : Item(status
=' ', wc_rev
=2),
9285 'D/H/psi' : Item(status
=' ', wc_rev
=2),
9286 'D/H/omega' : Item(status
='M ', wc_rev
=2),
9287 'D/H/nu' : Item(status
='A ', copied
='+', wc_rev
='-'),
9289 expected_disk
= wc
.State('', {
9290 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5-6'}),
9292 'mu' : Item("This is the file 'mu'.\n"),
9294 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
9295 'B/E/beta' : Item("New content"),
9296 'B/lambda' : Item("This is the file 'lambda'.\n"),
9301 'D/G/pi' : Item("This is the file 'pi'.\n"),
9302 'D/G/rho' : Item("This is the file 'rho'.\n"),
9303 'D/G/tau' : Item("This is the file 'tau'.\n"),
9304 'D/gamma' : Item("This is the file 'gamma'.\n"),
9305 'D/H' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-7'}),
9306 'D/H/chi' : Item("This is the file 'chi'.\n"),
9307 'D/H/psi' : Item("This is the file 'psi'.\n"),
9308 'D/H/omega' : Item("New content"),
9309 'D/H/nu' : Item("New content",
9310 props
={SVN_PROP_MERGEINFO
: '/A/D/H/nu:5-8'}),
9312 expected_skip
= wc
.State(short_A_COPY_path
, { })
9313 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '4', '6',
9320 None, None, None, None,
9322 short_D_COPY_path
= shorten_path_kludge(D_COPY_path
)
9323 expected_output
= wc
.State(short_D_COPY_path
, {
9324 'H/omega': Item(status
='G '),
9326 expected_status
= wc
.State(short_D_COPY_path
, {
9327 '' : Item(status
=' M', wc_rev
=2),
9328 'G' : Item(status
=' ', wc_rev
=2),
9329 'G/pi' : Item(status
=' ', wc_rev
=2),
9330 'G/rho' : Item(status
=' ', wc_rev
=2),
9331 'G/tau' : Item(status
=' ', wc_rev
=2),
9332 'gamma' : Item(status
=' ', wc_rev
=2),
9333 'H' : Item(status
=' M', wc_rev
=2),
9334 'H/chi' : Item(status
=' ', wc_rev
=2),
9335 'H/psi' : Item(status
=' ', wc_rev
=2),
9336 'H/omega' : Item(status
=' ', wc_rev
=2),
9337 'H/nu' : Item(status
='A ', copied
='+', wc_rev
='-'),
9339 expected_disk
= wc
.State('', {
9340 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D:5'}),
9341 'G/pi' : Item("This is the file 'pi'.\n"),
9342 'G/rho' : Item("This is the file 'rho'.\n"),
9343 'G/tau' : Item("This is the file 'tau'.\n"),
9344 'gamma' : Item("This is the file 'gamma'.\n"),
9345 'H' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:5,7'}),
9346 'H/chi' : Item("This is the file 'chi'.\n"),
9347 'H/psi' : Item("This is the file 'psi'.\n"),
9348 'H/omega' : Item("This is the file 'omega'.\n"),
9349 'H/nu' : Item("New content",
9350 props
={SVN_PROP_MERGEINFO
: '/A/D/H/nu:5,7-8'}),
9352 expected_skip
= wc
.State(short_D_COPY_path
, { })
9353 svntest
.actions
.run_and_verify_merge(short_D_COPY_path
, '6', '5',
9360 None, None, None, None,
9362 # Now once again merge r6 to A_COPY. A_COPY already has r6 in its mergeinfo
9363 # so we expect only subtree merges on A_COPY/D, A_COPY_D_H, and
9364 # A_COPY/D/H/nu. The fact that A/D/H/nu doesn't exist at r6 should not cause
9365 # the merge to fail.
9366 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
9367 expected_output
= wc
.State(short_A_COPY_path
, {
9368 'D/H/omega': Item(status
='U '),
9370 expected_status
= wc
.State(short_A_COPY_path
, {
9371 '' : Item(status
=' M', wc_rev
=2),
9372 'B' : Item(status
=' ', wc_rev
=2),
9373 'mu' : Item(status
=' ', wc_rev
=2),
9374 'B/E' : Item(status
=' ', wc_rev
=2),
9375 'B/E/alpha' : Item(status
=' ', wc_rev
=2),
9376 'B/E/beta' : Item(status
='M ', wc_rev
=2),
9377 'B/lambda' : Item(status
=' ', wc_rev
=2),
9378 'B/F' : Item(status
=' ', wc_rev
=2),
9379 'C' : Item(status
=' ', wc_rev
=2),
9380 'D' : Item(status
=' ', wc_rev
=2),
9381 'D/G' : Item(status
=' ', wc_rev
=2),
9382 'D/G/pi' : Item(status
=' ', wc_rev
=2),
9383 'D/G/rho' : Item(status
=' ', wc_rev
=2),
9384 'D/G/tau' : Item(status
=' ', wc_rev
=2),
9385 'D/gamma' : Item(status
=' ', wc_rev
=2),
9386 'D/H' : Item(status
=' M', wc_rev
=2),
9387 'D/H/chi' : Item(status
=' ', wc_rev
=2),
9388 'D/H/psi' : Item(status
=' ', wc_rev
=2),
9389 'D/H/omega' : Item(status
='M ', wc_rev
=2),
9390 'D/H/nu' : Item(status
='A ', copied
='+', wc_rev
='-'),
9392 expected_disk
= wc
.State('', {
9393 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5-6'}),
9395 'mu' : Item("This is the file 'mu'.\n"),
9397 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
9398 'B/E/beta' : Item("New content"),
9399 'B/lambda' : Item("This is the file 'lambda'.\n"),
9402 'D' : Item(), # Mergeinfo elides to 'A_COPY'
9404 'D/G/pi' : Item("This is the file 'pi'.\n"),
9405 'D/G/rho' : Item("This is the file 'rho'.\n"),
9406 'D/G/tau' : Item("This is the file 'tau'.\n"),
9407 'D/gamma' : Item("This is the file 'gamma'.\n"),
9408 'D/H' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/H:5-7'}),
9409 'D/H/chi' : Item("This is the file 'chi'.\n"),
9410 'D/H/psi' : Item("This is the file 'psi'.\n"),
9411 'D/H/omega' : Item("New content"),
9412 'D/H/nu' : Item("New content",
9413 props
={SVN_PROP_MERGEINFO
: '/A/D/H/nu:5-8'}),
9415 expected_skip
= wc
.State(short_A_COPY_path
, { })
9416 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '5', '6',
9423 None, None, None, None,
9427 def basic_reintegrate(sbox
):
9428 "basic merge --reintegrate support"
9430 # Make A_COPY branch in r2, and do a few more commits to A in r3-6.
9432 wc_dir
= sbox
.wc_dir
9433 expected_disk
, expected_status
= set_up_branch(sbox
)
9435 # Make a change on the branch, to A/mu. Commit in r7.
9436 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A_COPY", "mu"),
9437 "Changed on the branch.")
9438 expected_output
= wc
.State(wc_dir
, {'A_COPY/mu' : Item(verb
='Sending')})
9439 expected_status
.tweak('A_COPY/mu', wc_rev
=7)
9440 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9441 expected_status
, None, wc_dir
)
9442 expected_disk
.tweak('A_COPY/mu', contents
='Changed on the branch.')
9445 expected_output
= wc
.State(wc_dir
, {})
9446 expected_status
.tweak(wc_rev
='7')
9447 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
9448 expected_disk
, expected_status
,
9449 None, None, None, None, None, True)
9451 # Merge from trunk to branch (ie, r3-6), using normal cherry-harvest.
9452 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
9453 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
9454 expected_output
= wc
.State(short_A_COPY_path
, {
9455 'D/H/psi' : Item(status
='U '),
9456 'D/G/rho' : Item(status
='U '),
9457 'B/E/beta' : Item(status
='U '),
9458 'D/H/omega' : Item(status
='U '),
9460 k_expected_status
= wc
.State(short_A_COPY_path
, {
9461 "B" : Item(status
=' ', wc_rev
=7),
9462 "B/lambda" : Item(status
=' ', wc_rev
=7),
9463 "B/E" : Item(status
=' ', wc_rev
=7),
9464 "B/E/alpha" : Item(status
=' ', wc_rev
=7),
9465 "B/E/beta" : Item(status
='M ', wc_rev
=7),
9466 "B/F" : Item(status
=' ', wc_rev
=7),
9467 "mu" : Item(status
=' ', wc_rev
=7),
9468 "C" : Item(status
=' ', wc_rev
=7),
9469 "D" : Item(status
=' ', wc_rev
=7),
9470 "D/gamma" : Item(status
=' ', wc_rev
=7),
9471 "D/G" : Item(status
=' ', wc_rev
=7),
9472 "D/G/pi" : Item(status
=' ', wc_rev
=7),
9473 "D/G/rho" : Item(status
='M ', wc_rev
=7),
9474 "D/G/tau" : Item(status
=' ', wc_rev
=7),
9475 "D/H" : Item(status
=' ', wc_rev
=7),
9476 "D/H/chi" : Item(status
=' ', wc_rev
=7),
9477 "D/H/omega" : Item(status
='M ', wc_rev
=7),
9478 "D/H/psi" : Item(status
='M ', wc_rev
=7),
9479 "" : Item(status
=' M', wc_rev
=7),
9481 k_expected_disk
= wc
.State('', {
9482 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:2-7'}),
9484 'B/lambda' : Item("This is the file 'lambda'.\n"),
9486 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
9487 'B/E/beta' : Item("New content"),
9489 'mu' : Item("Changed on the branch."),
9492 'D/gamma' : Item("This is the file 'gamma'.\n"),
9494 'D/G/pi' : Item("This is the file 'pi'.\n"),
9495 'D/G/rho' : Item("New content"),
9496 'D/G/tau' : Item("This is the file 'tau'.\n"),
9498 'D/H/chi' : Item("This is the file 'chi'.\n"),
9499 'D/H/omega' : Item("New content"),
9500 'D/H/psi' : Item("New content"),
9502 expected_skip
= wc
.State(short_A_COPY_path
, {})
9503 saved_cwd
= os
.getcwd()
9504 os
.chdir(svntest
.main
.work_dir
)
9505 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, None, None,
9506 sbox
.repo_url
+ '/A',
9511 None, None, None, None,
9514 expected_disk
.tweak('A_COPY', props
={SVN_PROP_MERGEINFO
: '/A:2-7'})
9515 expected_disk
.tweak('A_COPY/B/E/beta', contents
="New content")
9516 expected_disk
.tweak('A_COPY/D/G/rho', contents
="New content")
9517 expected_disk
.tweak('A_COPY/D/H/omega', contents
="New content")
9518 expected_disk
.tweak('A_COPY/D/H/psi', contents
="New content")
9520 # Commit the merge to branch (r8).
9521 expected_output
= wc
.State(wc_dir
, {
9522 'A_COPY/D/H/psi' : Item(verb
='Sending'),
9523 'A_COPY/D/G/rho' : Item(verb
='Sending'),
9524 'A_COPY/B/E/beta' : Item(verb
='Sending'),
9525 'A_COPY/D/H/omega' : Item(verb
='Sending'),
9526 'A_COPY' : Item(verb
='Sending'),
9528 expected_status
.tweak('A_COPY', 'A_COPY/D/H/psi', 'A_COPY/D/G/rho',
9529 'A_COPY/B/E/beta', 'A_COPY/D/H/omega', wc_rev
=8)
9530 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9531 expected_status
, None, wc_dir
)
9534 # Update the wcs again.
9536 # Note: this update had to be added because of r28942 (which was
9537 # merged into the reintegrate branch in r28947). Without this
9538 # update, the mergeinfo will not be inherited properly as part of
9539 # the 'svn cp tau tauprime' step, and later (during the post-commit
9540 # update, with the new expected_disk) we'll get an error like this:
9542 # =============================================================
9543 # Expected 'tauprime' and actual 'tauprime' in disk tree are different!
9544 # =============================================================
9545 # EXPECTED NODE TO BE:
9546 # =============================================================
9547 # * Node name: tauprime
9548 # Path: A_COPY/D/G/tauprime
9549 # Contents: This is the file 'tau'.
9551 # Properties: {'svn:mergeinfo': '/A/D/G/tau:2-7'}
9553 # Children: N/A (node is a file)
9554 # =============================================================
9555 # ACTUAL NODE FOUND:
9556 # =============================================================
9557 # * Node name: tauprime
9559 # Contents: This is the file 'tau'.
9561 # Properties: {'svn:mergeinfo': ''}
9563 # Children: N/A (node is a file)
9565 expected_output
= wc
.State(wc_dir
, {})
9566 expected_status
.tweak(wc_rev
='8')
9567 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
9568 expected_disk
, expected_status
,
9569 None, None, None, None, None, True)
9571 # Make another change on the branch: copy tau to tauprime. Commit
9573 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp',
9574 os
.path
.join(wc_dir
, 'A_COPY', 'D', 'G',
9576 os
.path
.join(wc_dir
, 'A_COPY', 'D', 'G',
9579 expected_output
= wc
.State(wc_dir
, {
9580 'A_COPY/D/G/tauprime' : Item(verb
='Adding')
9582 expected_status
.add({'A_COPY/D/G/tauprime': Item(status
=' ', wc_rev
=9)})
9583 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9584 expected_status
, None, wc_dir
)
9587 'A_COPY/D/G/tauprime' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:2-7'},
9588 contents
="This is the file 'tau'.\n")
9591 # Update the trunk (well, the whole wc) (since reintegrate really
9592 # wants a clean wc).
9593 expected_output
= wc
.State(wc_dir
, {})
9594 expected_status
.tweak(wc_rev
='9')
9595 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
9596 expected_disk
, expected_status
,
9597 None, None, None, None, None, True)
9599 # *finally*, actually run merge --reintegrate in trunk with the
9600 # branch URL. This should bring in the mu change and the tauprime
9602 A_path
= os
.path
.join(wc_dir
, "A")
9603 short_A_path
= shorten_path_kludge(A_path
)
9604 expected_output
= wc
.State(short_A_path
, {
9605 '' : Item(status
=' U'),
9606 'mu' : Item(status
='U '),
9607 'D/G/tauprime' : Item(status
='A '),
9609 k_expected_status
= wc
.State(short_A_path
, {
9610 "B" : Item(status
=' ', wc_rev
=9),
9611 "B/lambda" : Item(status
=' ', wc_rev
=9),
9612 "B/E" : Item(status
=' ', wc_rev
=9),
9613 "B/E/alpha" : Item(status
=' ', wc_rev
=9),
9614 "B/E/beta" : Item(status
=' ', wc_rev
=9),
9615 "B/F" : Item(status
=' ', wc_rev
=9),
9616 "mu" : Item(status
='M ', wc_rev
=9),
9617 "C" : Item(status
=' ', wc_rev
=9),
9618 "D" : Item(status
=' ', wc_rev
=9),
9619 "D/gamma" : Item(status
=' ', wc_rev
=9),
9620 "D/G" : Item(status
=' ', wc_rev
=9),
9621 "D/G/pi" : Item(status
=' ', wc_rev
=9),
9622 "D/G/rho" : Item(status
=' ', wc_rev
=9),
9623 "D/G/tau" : Item(status
=' ', wc_rev
=9),
9624 "D/G/tauprime" : Item(status
='A ', wc_rev
='-', copied
='+'),
9625 "D/H" : Item(status
=' ', wc_rev
=9),
9626 "D/H/chi" : Item(status
=' ', wc_rev
=9),
9627 "D/H/omega" : Item(status
=' ', wc_rev
=9),
9628 "D/H/psi" : Item(status
=' ', wc_rev
=9),
9629 "" : Item(status
=' M', wc_rev
=9),
9631 k_expected_disk
.tweak('', props
={SVN_PROP_MERGEINFO
: '/A_COPY:2-9'})
9632 k_expected_disk
.add({
9633 'D/G/tauprime' : Item(props
={SVN_PROP_MERGEINFO
: '/A/D/G/tau:2-7'},
9634 contents
="This is the file 'tau'.\n")
9636 expected_skip
= wc
.State(short_A_path
, {})
9637 saved_cwd
= os
.getcwd()
9638 os
.chdir(svntest
.main
.work_dir
)
9639 svntest
.actions
.run_and_verify_merge(short_A_path
, None, None,
9640 sbox
.repo_url
+ '/A_COPY',
9645 None, None, None, None,
9650 # Finally, commit the result of the merge (r10).
9651 expected_output
= wc
.State(wc_dir
, {
9652 'A/D/G/tauprime' : Item(verb
='Adding'),
9653 'A/mu' : Item(verb
='Sending'),
9654 'A' : Item(verb
='Sending'),
9656 expected_status
.add({
9657 'A/D/G/tauprime' : Item(status
=' ', wc_rev
=10),
9659 expected_status
.tweak('A', 'A/mu', wc_rev
=10)
9660 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9661 expected_status
, None, wc_dir
)
9663 def reintegrate_branch_never_merged_to(sbox
):
9664 "merge --reintegrate on a never-updated branch"
9666 # Make A_COPY branch in r2, and do a few more commits to A in r3-6.
9668 wc_dir
= sbox
.wc_dir
9669 expected_disk
, expected_status
= set_up_branch(sbox
)
9671 # Make a change on the branch, to A/mu. Commit in r7.
9672 svntest
.main
.file_write(os
.path
.join(wc_dir
, "A_COPY", "mu"),
9673 "Changed on the branch.")
9674 expected_output
= wc
.State(wc_dir
, {'A_COPY/mu' : Item(verb
='Sending')})
9675 expected_status
.tweak('A_COPY/mu', wc_rev
=7)
9676 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9677 expected_status
, None, wc_dir
)
9678 expected_disk
.tweak('A_COPY/mu', contents
='Changed on the branch.')
9681 expected_output
= wc
.State(wc_dir
, {})
9682 expected_status
.tweak(wc_rev
='7')
9683 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
9684 expected_disk
, expected_status
,
9685 None, None, None, None, None, True)
9687 # Make another change on the branch: copy tau to tauprime. Commit
9689 svntest
.actions
.run_and_verify_svn(None, None, [], 'cp',
9690 os
.path
.join(wc_dir
, 'A_COPY', 'D', 'G',
9692 os
.path
.join(wc_dir
, 'A_COPY', 'D', 'G',
9694 expected_output
= wc
.State(wc_dir
, {
9695 'A_COPY/D/G/tauprime' : Item(verb
='Adding')
9697 expected_status
.add({'A_COPY/D/G/tauprime': Item(status
=' ', wc_rev
=8)})
9698 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9699 expected_status
, None, wc_dir
)
9701 'A_COPY/D/G/tauprime' : Item(props
={SVN_PROP_MERGEINFO
: ''},
9702 ### TODO(reint): why empty?
9703 contents
="This is the file 'tau'.\n")
9706 # Update the trunk (well, the whole wc) (since reintegrate really
9707 # wants a clean wc).
9708 expected_output
= wc
.State(wc_dir
, {})
9709 expected_status
.tweak(wc_rev
='8')
9710 svntest
.actions
.run_and_verify_update(wc_dir
, expected_output
,
9711 expected_disk
, expected_status
,
9712 None, None, None, None, None, True)
9714 # *finally*, actually run merge --reintegrate in trunk with the
9715 # branch URL. This should bring in the mu change and the tauprime
9717 A_path
= os
.path
.join(wc_dir
, "A")
9718 short_A_path
= shorten_path_kludge(A_path
)
9719 expected_output
= wc
.State(short_A_path
, {
9720 'mu' : Item(status
='U '),
9721 'D/G/tauprime' : Item(status
='A '),
9723 k_expected_status
= wc
.State(short_A_path
, {
9724 "B" : Item(status
=' ', wc_rev
=8),
9725 "B/lambda" : Item(status
=' ', wc_rev
=8),
9726 "B/E" : Item(status
=' ', wc_rev
=8),
9727 "B/E/alpha" : Item(status
=' ', wc_rev
=8),
9728 "B/E/beta" : Item(status
=' ', wc_rev
=8),
9729 "B/F" : Item(status
=' ', wc_rev
=8),
9730 "mu" : Item(status
='M ', wc_rev
=8),
9731 "C" : Item(status
=' ', wc_rev
=8),
9732 "D" : Item(status
=' ', wc_rev
=8),
9733 "D/gamma" : Item(status
=' ', wc_rev
=8),
9734 "D/G" : Item(status
=' ', wc_rev
=8),
9735 "D/G/pi" : Item(status
=' ', wc_rev
=8),
9736 "D/G/rho" : Item(status
=' ', wc_rev
=8),
9737 "D/G/tau" : Item(status
=' ', wc_rev
=8),
9738 "D/G/tauprime" : Item(status
='A ', wc_rev
='-', copied
='+'),
9739 "D/H" : Item(status
=' ', wc_rev
=8),
9740 "D/H/chi" : Item(status
=' ', wc_rev
=8),
9741 "D/H/omega" : Item(status
=' ', wc_rev
=8),
9742 "D/H/psi" : Item(status
=' ', wc_rev
=8),
9743 "" : Item(status
=' M', wc_rev
=8),
9745 k_expected_disk
= wc
.State('', {
9746 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A_COPY:2-8'}),
9748 'B/lambda' : Item("This is the file 'lambda'.\n"),
9750 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
9751 'B/E/beta' : Item("New content"),
9753 'mu' : Item("Changed on the branch."),
9756 'D/gamma' : Item("This is the file 'gamma'.\n"),
9758 'D/G/pi' : Item("This is the file 'pi'.\n"),
9759 'D/G/rho' : Item("New content"),
9760 'D/G/tau' : Item("This is the file 'tau'.\n"),
9761 'D/G/tauprime' : Item("This is the file 'tau'.\n",
9762 ### TODO(reint): why empty?
9763 props
={SVN_PROP_MERGEINFO
: ''}),
9765 'D/H/chi' : Item("This is the file 'chi'.\n"),
9766 'D/H/omega' : Item("New content"),
9767 'D/H/psi' : Item("New content"),
9769 expected_skip
= wc
.State(short_A_path
, {})
9770 saved_cwd
= os
.getcwd()
9771 os
.chdir(svntest
.main
.work_dir
)
9772 svntest
.actions
.run_and_verify_merge(short_A_path
, None, None,
9773 sbox
.repo_url
+ '/A_COPY',
9778 None, None, None, None,
9783 # Finally, commit the result of the merge (r9).
9784 expected_output
= wc
.State(wc_dir
, {
9785 'A/D/G/tauprime' : Item(verb
='Adding'),
9786 'A/mu' : Item(verb
='Sending'),
9787 'A' : Item(verb
='Sending'),
9789 expected_status
.add({
9790 'A/D/G/tauprime' : Item(status
=' ', wc_rev
=9),
9792 expected_status
.tweak('A', 'A/mu', wc_rev
=9)
9793 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9794 expected_status
, None, wc_dir
)
9796 def reintegrate_fail_on_modified_wc(sbox
):
9797 "merge --reintegrate should fail in modified wc"
9799 wc_dir
= sbox
.wc_dir
9800 A_path
= os
.path
.join(wc_dir
, "A")
9801 mu_path
= os
.path
.join(A_path
, "mu")
9802 ignored_expected_disk
, ignored_expected_status
= set_up_branch(sbox
)
9803 svntest
.main
.file_write(mu_path
, "Changed on 'trunk' (the merge target).")
9804 svntest
.actions
.run_and_verify_merge(
9805 A_path
, None, None, sbox
.repo_url
+ '/A_COPY', None, None, None, None,
9806 ".*Cannot reintegrate into a working copy that has local modifications.*",
9807 None, None, None, None, True, False, '--reintegrate')
9809 def reintegrate_fail_on_mixed_rev_wc(sbox
):
9810 "merge --reintegrate should fail in mixed-rev wc"
9812 wc_dir
= sbox
.wc_dir
9813 A_path
= os
.path
.join(wc_dir
, "A")
9814 mu_path
= os
.path
.join(A_path
, "mu")
9815 ignored_expected_disk
, expected_status
= set_up_branch(sbox
)
9816 # Make and commit a change, in order to get a mixed-rev wc.
9817 svntest
.main
.file_write(mu_path
, "Changed on 'trunk' (the merge target).")
9818 expected_output
= wc
.State(wc_dir
, {
9819 'A/mu' : Item(verb
='Sending'),
9821 expected_status
.tweak('A/mu', wc_rev
=7)
9822 svntest
.actions
.run_and_verify_commit(wc_dir
, expected_output
,
9823 expected_status
, None, wc_dir
)
9824 # Try merging into that same wc, expecting failure.
9825 svntest
.actions
.run_and_verify_merge(
9826 A_path
, None, None, sbox
.repo_url
+ '/A_COPY', None, None, None, None,
9827 ".*Cannot reintegrate into mixed-revision working copy.*",
9828 None, None, None, None, True, False, '--reintegrate')
9830 def reintegrate_fail_on_switched_wc(sbox
):
9831 "merge --reintegrate should fail in switched wc"
9833 wc_dir
= sbox
.wc_dir
9834 A_path
= os
.path
.join(wc_dir
, "A")
9835 G_path
= os
.path
.join(A_path
, "D", "G")
9836 switch_url
= sbox
.repo_url
+ "/A/D/H"
9837 expected_disk
, expected_status
= set_up_branch(sbox
)
9839 # Switch a subdir of the target.
9840 expected_output
= svntest
.wc
.State(wc_dir
, {
9841 'A/D/G/pi' : Item(status
='D '),
9842 'A/D/G/rho' : Item(status
='D '),
9843 'A/D/G/tau' : Item(status
='D '),
9844 'A/D/G/chi' : Item(status
='A '),
9845 'A/D/G/psi' : Item(status
='A '),
9846 'A/D/G/omega' : Item(status
='A '),
9848 expected_disk
.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
9850 'A/D/G/chi' : Item(contents
="This is the file 'chi'.\n"),
9851 'A/D/G/psi' : Item(contents
="New content"),
9852 'A/D/G/omega' : Item(contents
="New content"),
9854 expected_status
.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
9855 expected_status
.add({
9856 'A/D/G' : Item(status
=' ', wc_rev
=6, switched
='S'),
9857 'A/D/G/chi' : Item(status
=' ', wc_rev
=6),
9858 'A/D/G/psi' : Item(status
=' ', wc_rev
=6),
9859 'A/D/G/omega' : Item(status
=' ', wc_rev
=6),
9861 svntest
.actions
.run_and_verify_switch(wc_dir
,
9867 None, None, None, None, False);
9868 svntest
.actions
.run_and_verify_merge(
9869 A_path
, None, None, sbox
.repo_url
+ '/A_COPY', None, None, None, None,
9870 ".*Cannot reintegrate into a working copy with a switched subtree.*",
9871 None, None, None, None, True, False, '--reintegrate')
9873 def reintegrate_fail_on_shallow_wc(sbox
):
9874 "merge --reintegrate should fail in shallow wc"
9876 wc_dir
= sbox
.wc_dir
9877 expected_disk
, expected_status
= set_up_branch(sbox
)
9878 A_path
= os
.path
.join(wc_dir
, "A")
9879 G_path
= os
.path
.join(A_path
, "D", "G")
9880 # Our default checkout doesn't have any subdirs at non-infinite
9881 # depth, so we'll have to create one the old-fashioned way: remove a
9882 # tree, then "update" it back into existence at a shallower depth.
9883 svntest
.main
.safe_rmtree(G_path
)
9884 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', G_path
,
9886 # Even though everything is actually present (as G has no subdirs
9887 # anyway), the reintegration should fail, because G's depth is other
9889 svntest
.actions
.run_and_verify_merge(
9890 A_path
, None, None, sbox
.repo_url
+ '/A_COPY', None, None, None, None,
9891 ".*Cannot reintegrate into a working copy not.*at infinite depth.*",
9892 None, None, None, None, True, False, '--reintegrate')
9894 def reintegrate_fail_on_stale_source(sbox
):
9895 "merge --reintegrate should fail on stale source"
9897 wc_dir
= sbox
.wc_dir
9898 expected_disk
, expected_status
= set_up_branch(sbox
)
9899 A_path
= os
.path
.join(wc_dir
, "A")
9900 mu_path
= os
.path
.join(A_path
, "mu")
9901 svntest
.main
.file_append(mu_path
, 'some text appended to mu\n')
9902 svntest
.actions
.run_and_verify_svn(None, None, [], 'commit',
9903 '-m', 'a change to mu', mu_path
);
9904 # Unmix the revisions in the working copy.
9905 svntest
.actions
.run_and_verify_svn(None, None, [], 'update', wc_dir
);
9906 # The merge --reintegrate should fail because target has changes not
9907 # present in source.
9908 svntest
.actions
.run_and_verify_merge(
9909 A_path
, None, None, sbox
.repo_url
+ '/A_COPY', None, None, None, None,
9910 ".*", ###TODO(reint): need a more specific check here
9911 None, None, None, None, True, False, '--reintegrate')
9913 def dont_add_mergeinfo_from_own_history(sbox
):
9914 "cyclic merges dont add mergeinfo from own history"
9917 wc_dir
= sbox
.wc_dir
9918 wc_disk
, wc_status
= set_up_branch(sbox
)
9920 # Some paths we'll care about
9921 A_path
= os
.path
.join(wc_dir
, "A")
9922 A_MOVED_path
= os
.path
.join(wc_dir
, "A_MOVED")
9923 mu_path
= os
.path
.join(wc_dir
, "A", "mu")
9924 mu_MOVED_path
= os
.path
.join(wc_dir
, "A_MOVED", "mu")
9925 A_COPY_path
= os
.path
.join(wc_dir
, "A_COPY")
9926 mu_COPY_path
= os
.path
.join(wc_dir
, "A_COPY", "mu")
9928 # Merge r5 from 'A' to 'A_COPY' and commit as r7. This creates mergeinfo
9929 # of '/A:5' on 'A_COPY'. Then merge r7 from 'A_COPY' to 'A'. This attempts
9930 # to add the mergeinfo '/A:5' to 'A', but since this revision already exists
9931 # in 'A's history it should be filtered out. In addition, as there is no
9932 # other operative change to 'A', the merge should be a no-op.
9934 # Search for the comment entitled "The Merge Kluge" elsewhere in
9935 # this file, to understand why we shorten and chdir() below.
9936 short_A_COPY_path
= shorten_path_kludge(A_COPY_path
)
9937 expected_output
= wc
.State(short_A_COPY_path
, {
9938 'B/E/beta' : Item(status
='U '),
9940 expected_A_COPY_status
= wc
.State(short_A_COPY_path
, {
9941 '' : Item(status
=' M', wc_rev
=2),
9942 'B' : Item(status
=' ', wc_rev
=2),
9943 'mu' : Item(status
=' ', wc_rev
=2),
9944 'B/E' : Item(status
=' ', wc_rev
=2),
9945 'B/E/alpha' : Item(status
=' ', wc_rev
=2),
9946 'B/E/beta' : Item(status
='M ', wc_rev
=2),
9947 'B/lambda' : Item(status
=' ', wc_rev
=2),
9948 'B/F' : Item(status
=' ', wc_rev
=2),
9949 'C' : Item(status
=' ', wc_rev
=2),
9950 'D' : Item(status
=' ', wc_rev
=2),
9951 'D/G' : Item(status
=' ', wc_rev
=2),
9952 'D/G/pi' : Item(status
=' ', wc_rev
=2),
9953 'D/G/rho' : Item(status
=' ', wc_rev
=2),
9954 'D/G/tau' : Item(status
=' ', wc_rev
=2),
9955 'D/gamma' : Item(status
=' ', wc_rev
=2),
9956 'D/H' : Item(status
=' ', wc_rev
=2),
9957 'D/H/chi' : Item(status
=' ', wc_rev
=2),
9958 'D/H/psi' : Item(status
=' ', wc_rev
=2),
9959 'D/H/omega' : Item(status
=' ', wc_rev
=2),
9961 expected_A_COPY_disk
= wc
.State('', {
9962 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:5'}),
9964 'mu' : Item("This is the file 'mu'.\n"),
9966 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
9967 'B/E/beta' : Item("New content"),
9968 'B/lambda' : Item("This is the file 'lambda'.\n"),
9973 'D/G/pi' : Item("This is the file 'pi'.\n"),
9974 'D/G/rho' : Item("This is the file 'rho'.\n"),
9975 'D/G/tau' : Item("This is the file 'tau'.\n"),
9976 'D/gamma' : Item("This is the file 'gamma'.\n"),
9978 'D/H/chi' : Item("This is the file 'chi'.\n"),
9979 'D/H/psi' : Item("This is the file 'psi'.\n"),
9980 'D/H/omega' : Item("This is the file 'omega'.\n"),
9982 expected_A_COPY_skip
= wc
.State(short_A_COPY_path
, { })
9983 saved_cwd
= os
.getcwd()
9984 os
.chdir(svntest
.main
.work_dir
)
9985 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '4', '5',
9989 expected_A_COPY_disk
,
9990 expected_A_COPY_status
,
9991 expected_A_COPY_skip
,
9992 None, None, None, None,
9997 expected_output
= wc
.State(wc_dir
, {
9998 'A_COPY' : Item(verb
='Sending'),
9999 'A_COPY/B/E/beta' : Item(verb
='Sending'),
10001 wc_status
.tweak('A_COPY', 'A_COPY/B/E/beta', wc_rev
=7)
10002 svntest
.actions
.run_and_verify_commit(wc_dir
,
10008 # Merge r7 back to the original source.
10009 os
.chdir(svntest
.main
.work_dir
)
10010 short_A_path
= shorten_path_kludge(A_path
)
10011 svntest
.actions
.run_and_verify_svn(None, [], [], 'merge', '-c', '7',
10012 sbox
.repo_url
+ '/A_COPY',
10014 os
.chdir(saved_cwd
)
10016 # Now merge r3 from 'A' to 'A_COPY', make a text mod to 'A_COPY/mu' and
10017 # commit both as r8. This results in mergeinfo of '/A:3,5' on 'A_COPY'.
10018 # Then merge r8 from 'A_COPY' to 'A'. This attempts to add the mergeinfo
10019 # '/A:3' to 'A', which is again filtered out, but the change to 'A/mu'
10020 # makes the merge operative, so 'A' should get the mergeinfo '/A_COPY:8'.
10021 os
.chdir(svntest
.main
.work_dir
)
10022 expected_output
= wc
.State(short_A_COPY_path
, {
10023 'D/H/psi' : Item(status
='U '),
10025 expected_A_COPY_status
.tweak('B/E/beta', status
=' ', wc_rev
=7)
10026 expected_A_COPY_status
.tweak('', status
=' M', wc_rev
=7)
10027 expected_A_COPY_status
.tweak('D/H/psi', status
='M ')
10028 expected_A_COPY_disk
.tweak('D/H/psi', contents
='New content')
10029 expected_A_COPY_disk
.tweak('', props
={SVN_PROP_MERGEINFO
: '/A:3,5'})
10030 svntest
.actions
.run_and_verify_merge(short_A_COPY_path
, '2', '3',
10034 expected_A_COPY_disk
,
10035 expected_A_COPY_status
,
10036 expected_A_COPY_skip
,
10037 None, None, None, None,
10039 os
.chdir(saved_cwd
)
10041 # Change 'A_COPY/mu'
10042 svntest
.main
.file_write(mu_COPY_path
, "New content")
10045 expected_output
= wc
.State(wc_dir
, {
10046 'A_COPY' : Item(verb
='Sending'),
10047 'A_COPY/D/H/psi' : Item(verb
='Sending'),
10048 'A_COPY/mu' : Item(verb
='Sending'),
10050 wc_status
.tweak('A_COPY', 'A_COPY/D/H/psi', 'A_COPY/mu', wc_rev
=8)
10051 svntest
.actions
.run_and_verify_commit(wc_dir
,
10057 # Merge r8 back to the 'A'
10058 short_A_path
= shorten_path_kludge(A_path
)
10059 expected_output
= wc
.State(short_A_path
, {
10060 'mu' : Item(status
='U '),
10062 expected_A_status
= wc
.State(short_A_path
, {
10063 '' : Item(status
=' M', wc_rev
=1),
10064 'B' : Item(status
=' ', wc_rev
=1),
10065 'mu' : Item(status
='M ', wc_rev
=1),
10066 'B/E' : Item(status
=' ', wc_rev
=1),
10067 'B/E/alpha' : Item(status
=' ', wc_rev
=1),
10068 'B/E/beta' : Item(status
=' ', wc_rev
=5),
10069 'B/lambda' : Item(status
=' ', wc_rev
=1),
10070 'B/F' : Item(status
=' ', wc_rev
=1),
10071 'C' : Item(status
=' ', wc_rev
=1),
10072 'D' : Item(status
=' ', wc_rev
=1),
10073 'D/G' : Item(status
=' ', wc_rev
=1),
10074 'D/G/pi' : Item(status
=' ', wc_rev
=1),
10075 'D/G/rho' : Item(status
=' ', wc_rev
=4),
10076 'D/G/tau' : Item(status
=' ', wc_rev
=1),
10077 'D/gamma' : Item(status
=' ', wc_rev
=1),
10078 'D/H' : Item(status
=' ', wc_rev
=1),
10079 'D/H/chi' : Item(status
=' ', wc_rev
=1),
10080 'D/H/psi' : Item(status
=' ', wc_rev
=3),
10081 'D/H/omega' : Item(status
=' ', wc_rev
=6),
10083 expected_A_disk
= wc
.State('', {
10084 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A_COPY:8'}),
10086 'mu' : Item("New content"),
10088 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
10089 'B/E/beta' : Item("New content"),
10090 'B/lambda' : Item("This is the file 'lambda'.\n"),
10095 'D/G/pi' : Item("This is the file 'pi'.\n"),
10096 'D/G/rho' : Item("New content"),
10097 'D/G/tau' : Item("This is the file 'tau'.\n"),
10098 'D/gamma' : Item("This is the file 'gamma'.\n"),
10100 'D/H/chi' : Item("This is the file 'chi'.\n"),
10101 'D/H/psi' : Item("New content"),
10102 'D/H/omega' : Item("New content"),
10104 expected_A_skip
= wc
.State(short_A_path
, {})
10105 os
.chdir(svntest
.main
.work_dir
)
10106 svntest
.actions
.run_and_verify_merge(short_A_path
, '7', '8',
10113 None, None, None, None,
10115 os
.chdir(saved_cwd
)
10117 # Revert all local mods
10118 svntest
.actions
.run_and_verify_svn(None,
10119 ["Reverted '" + A_path
+ "'\n",
10120 "Reverted '" + mu_path
+ "'\n"],
10121 [], 'revert', '-R', wc_dir
)
10123 # Move 'A' to 'A_MOVED' and once again merge r8 from 'A_COPY', this time
10124 # to 'A_MOVED'. This attempts to add the mergeinfo '/A:3' to
10125 # 'A_MOVED', but 'A_MOVED@3' is 'A', so again this mergeinfo is filtered
10126 # out, leaving the only the mergeinfo created from the merge itself:
10128 svntest
.actions
.run_and_verify_svn(None,
10129 ['\n', 'Committed revision 9.\n'],
10131 sbox
.repo_url
+ '/A',
10132 sbox
.repo_url
+ '/A_MOVED',
10133 '-m', 'Copy A to A_MOVED')
10134 wc_status
.remove('A', 'A/B', 'A/B/lambda', 'A/B/E', 'A/B/E/alpha',
10135 'A/B/E/beta', 'A/B/F', 'A/mu', 'A/C', 'A/D', 'A/D/gamma', 'A/D/G',
10136 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H', 'A/D/H/chi',
10137 'A/D/H/omega', 'A/D/H/psi')
10139 'A_MOVED' : Item(),
10140 'A_MOVED/B' : Item(),
10141 'A_MOVED/B/lambda' : Item(),
10142 'A_MOVED/B/E' : Item(),
10143 'A_MOVED/B/E/alpha' : Item(),
10144 'A_MOVED/B/E/beta' : Item(),
10145 'A_MOVED/B/F' : Item(),
10146 'A_MOVED/mu' : Item(),
10147 'A_MOVED/C' : Item(),
10148 'A_MOVED/D' : Item(),
10149 'A_MOVED/D/gamma' : Item(),
10150 'A_MOVED/D/G' : Item(),
10151 'A_MOVED/D/G/pi' : Item(),
10152 'A_MOVED/D/G/rho' : Item(),
10153 'A_MOVED/D/G/tau' : Item(),
10154 'A_MOVED/D/H' : Item(),
10155 'A_MOVED/D/H/chi' : Item(),
10156 'A_MOVED/D/H/omega' : Item(),
10157 'A_MOVED/D/H/psi' : Item(),
10159 wc_status
.tweak(wc_rev
=9, status
=' ')
10160 wc_disk
.remove('A', 'A/B', 'A/B/lambda', 'A/B/E', 'A/B/E/alpha',
10161 'A/B/E/beta', 'A/B/F', 'A/mu', 'A/C', 'A/D', 'A/D/gamma',
10162 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau', 'A/D/H',
10163 'A/D/H/chi', 'A/D/H/omega', 'A/D/H/psi' )
10165 'A_MOVED' : Item(),
10166 'A_MOVED/B' : Item(),
10167 'A_MOVED/B/lambda' : Item("This is the file 'lambda'.\n"),
10168 'A_MOVED/B/E' : Item(),
10169 'A_MOVED/B/E/alpha' : Item("This is the file 'alpha'.\n"),
10170 'A_MOVED/B/E/beta' : Item("New content"),
10171 'A_MOVED/B/F' : Item(),
10172 'A_MOVED/mu' : Item("This is the file 'mu'.\n"),
10173 'A_MOVED/C' : Item(),
10174 'A_MOVED/D' : Item(),
10175 'A_MOVED/D/gamma' : Item("This is the file 'gamma'.\n"),
10176 'A_MOVED/D/G' : Item(),
10177 'A_MOVED/D/G/pi' : Item("This is the file 'pi'.\n"),
10178 'A_MOVED/D/G/rho' : Item("New content"),
10179 'A_MOVED/D/G/tau' : Item("This is the file 'tau'.\n"),
10180 'A_MOVED/D/H' : Item(),
10181 'A_MOVED/D/H/chi' : Item("This is the file 'chi'.\n"),
10182 'A_MOVED/D/H/omega' : Item("New content"),
10183 'A_MOVED/D/H/psi' : Item("New content"),
10185 wc_disk
.tweak('A_COPY/D/H/psi', 'A_COPY/mu', 'A_COPY/B/E/beta',
10186 contents
='New content')
10187 wc_disk
.tweak('A_COPY', props
={SVN_PROP_MERGEINFO
: '/A:3,5'})
10188 expected_output
= wc
.State(wc_dir
, {
10189 'A' : Item(status
='D '),
10190 'A_MOVED' : Item(status
='A '),
10191 'A_MOVED/B' : Item(status
='A '),
10192 'A_MOVED/B/lambda' : Item(status
='A '),
10193 'A_MOVED/B/E' : Item(status
='A '),
10194 'A_MOVED/B/E/alpha' : Item(status
='A '),
10195 'A_MOVED/B/E/beta' : Item(status
='A '),
10196 'A_MOVED/B/F' : Item(status
='A '),
10197 'A_MOVED/mu' : Item(status
='A '),
10198 'A_MOVED/C' : Item(status
='A '),
10199 'A_MOVED/D' : Item(status
='A '),
10200 'A_MOVED/D/gamma' : Item(status
='A '),
10201 'A_MOVED/D/G' : Item(status
='A '),
10202 'A_MOVED/D/G/pi' : Item(status
='A '),
10203 'A_MOVED/D/G/rho' : Item(status
='A '),
10204 'A_MOVED/D/G/tau' : Item(status
='A '),
10205 'A_MOVED/D/H' : Item(status
='A '),
10206 'A_MOVED/D/H/chi' : Item(status
='A '),
10207 'A_MOVED/D/H/omega' : Item(status
='A '),
10208 'A_MOVED/D/H/psi' : Item(status
='A ')
10210 svntest
.actions
.run_and_verify_update(wc_dir
,
10214 None, None, None, None, None,
10216 short_A_MOVED_path
= shorten_path_kludge(A_MOVED_path
)
10217 expected_output
= wc
.State(short_A_MOVED_path
, {
10218 'mu' : Item(status
='U '),
10220 expected_A_status
= wc
.State(short_A_MOVED_path
, {
10221 '' : Item(status
=' M', wc_rev
=9),
10222 'B' : Item(status
=' ', wc_rev
=9),
10223 'mu' : Item(status
='M ', wc_rev
=9),
10224 'B/E' : Item(status
=' ', wc_rev
=9),
10225 'B/E/alpha' : Item(status
=' ', wc_rev
=9),
10226 'B/E/beta' : Item(status
=' ', wc_rev
=9),
10227 'B/lambda' : Item(status
=' ', wc_rev
=9),
10228 'B/F' : Item(status
=' ', wc_rev
=9),
10229 'C' : Item(status
=' ', wc_rev
=9),
10230 'D' : Item(status
=' ', wc_rev
=9),
10231 'D/G' : Item(status
=' ', wc_rev
=9),
10232 'D/G/pi' : Item(status
=' ', wc_rev
=9),
10233 'D/G/rho' : Item(status
=' ', wc_rev
=9),
10234 'D/G/tau' : Item(status
=' ', wc_rev
=9),
10235 'D/gamma' : Item(status
=' ', wc_rev
=9),
10236 'D/H' : Item(status
=' ', wc_rev
=9),
10237 'D/H/chi' : Item(status
=' ', wc_rev
=9),
10238 'D/H/psi' : Item(status
=' ', wc_rev
=9),
10239 'D/H/omega' : Item(status
=' ', wc_rev
=9),
10241 # We can reuse expected_A_disk from above without change.
10242 os
.chdir(svntest
.main
.work_dir
)
10243 svntest
.actions
.run_and_verify_merge(short_A_MOVED_path
, '7', '8',
10250 None, None, None, None,
10252 os
.chdir(saved_cwd
)
10254 # Revert all local mods
10255 svntest
.actions
.run_and_verify_svn(None,
10256 ["Reverted '" + A_MOVED_path
+ "'\n",
10257 "Reverted '" + mu_MOVED_path
+ "'\n"],
10258 [], 'revert', '-R', wc_dir
)
10260 # Create a new 'A' unrelated to the old 'A' which was moved. Then merge
10261 # r8 from 'A_COPY' to this new 'A'. Since the new 'A' shares no history
10262 # with the mergeinfo 'A@3', the mergeinfo '/A:3' is added and when combined
10263 # with the mergeinfo created from the merge should result in
10264 # '/A:3\n/A_COPY:8'
10266 # Create the new 'A' by exporting the old 'A@1'.
10267 expected_output
= svntest
.verify
.UnorderedOutput(
10268 ["A " + os
.path
.join(wc_dir
, "A") + "\n",
10269 "A " + os
.path
.join(wc_dir
, "A", "B") + "\n",
10270 "A " + os
.path
.join(wc_dir
, "A", "B", "lambda") + "\n",
10271 "A " + os
.path
.join(wc_dir
, "A", "B", "E") + "\n",
10272 "A " + os
.path
.join(wc_dir
, "A", "B", "E", "alpha") + "\n",
10273 "A " + os
.path
.join(wc_dir
, "A", "B", "E", "beta") + "\n",
10274 "A " + os
.path
.join(wc_dir
, "A", "B", "F") + "\n",
10275 "A " + os
.path
.join(wc_dir
, "A", "mu") + "\n",
10276 "A " + os
.path
.join(wc_dir
, "A", "C") + "\n",
10277 "A " + os
.path
.join(wc_dir
, "A", "D") + "\n",
10278 "A " + os
.path
.join(wc_dir
, "A", "D", "gamma") + "\n",
10279 "A " + os
.path
.join(wc_dir
, "A", "D", "G") + "\n",
10280 "A " + os
.path
.join(wc_dir
, "A", "D", "G", "pi") + "\n",
10281 "A " + os
.path
.join(wc_dir
, "A", "D", "G", "rho") + "\n",
10282 "A " + os
.path
.join(wc_dir
, "A", "D", "G", "tau") + "\n",
10283 "A " + os
.path
.join(wc_dir
, "A", "D", "H") + "\n",
10284 "A " + os
.path
.join(wc_dir
, "A", "D", "H", "chi") + "\n",
10285 "A " + os
.path
.join(wc_dir
, "A", "D", "H", "omega") + "\n",
10286 "A " + os
.path
.join(wc_dir
, "A", "D", "H", "psi") + "\n",
10287 "Exported revision 1.\n",]
10289 svntest
.actions
.run_and_verify_svn(None, expected_output
, [],
10290 'export', sbox
.repo_url
+ '/A@1',
10292 expected_output
= svntest
.verify
.UnorderedOutput(
10293 ["A " + os
.path
.join(wc_dir
, "A") + "\n",
10294 "A " + os
.path
.join(wc_dir
, "A", "B") + "\n",
10295 "A " + os
.path
.join(wc_dir
, "A", "B", "lambda") + "\n",
10296 "A " + os
.path
.join(wc_dir
, "A", "B", "E") + "\n",
10297 "A " + os
.path
.join(wc_dir
, "A", "B", "E", "alpha") + "\n",
10298 "A " + os
.path
.join(wc_dir
, "A", "B", "E", "beta") + "\n",
10299 "A " + os
.path
.join(wc_dir
, "A", "B", "F") + "\n",
10300 "A " + os
.path
.join(wc_dir
, "A", "mu") + "\n",
10301 "A " + os
.path
.join(wc_dir
, "A", "C") + "\n",
10302 "A " + os
.path
.join(wc_dir
, "A", "D") + "\n",
10303 "A " + os
.path
.join(wc_dir
, "A", "D", "gamma") + "\n",
10304 "A " + os
.path
.join(wc_dir
, "A", "D", "G") + "\n",
10305 "A " + os
.path
.join(wc_dir
, "A", "D", "G", "pi") + "\n",
10306 "A " + os
.path
.join(wc_dir
, "A", "D", "G", "rho") + "\n",
10307 "A " + os
.path
.join(wc_dir
, "A", "D", "G", "tau") + "\n",
10308 "A " + os
.path
.join(wc_dir
, "A", "D", "H") + "\n",
10309 "A " + os
.path
.join(wc_dir
, "A", "D", "H", "chi") + "\n",
10310 "A " + os
.path
.join(wc_dir
, "A", "D", "H", "omega") + "\n",
10311 "A " + os
.path
.join(wc_dir
, "A", "D", "H", "psi") + "\n",]
10313 svntest
.actions
.run_and_verify_svn(None, expected_output
, [],
10315 # Commit the new 'A' as r10
10316 expected_output
= wc
.State(wc_dir
, {
10317 'A' : Item(verb
='Adding'),
10318 'A/B' : Item(verb
='Adding'),
10319 'A/mu' : Item(verb
='Adding'),
10320 'A/B/E' : Item(verb
='Adding'),
10321 'A/B/E/alpha' : Item(verb
='Adding'),
10322 'A/B/E/beta' : Item(verb
='Adding'),
10323 'A/B/lambda' : Item(verb
='Adding'),
10324 'A/B/F' : Item(verb
='Adding'),
10325 'A/C' : Item(verb
='Adding'),
10326 'A/D' : Item(verb
='Adding'),
10327 'A/D/G' : Item(verb
='Adding'),
10328 'A/D/G/pi' : Item(verb
='Adding'),
10329 'A/D/G/rho' : Item(verb
='Adding'),
10330 'A/D/G/tau' : Item(verb
='Adding'),
10331 'A/D/gamma' : Item(verb
='Adding'),
10332 'A/D/H' : Item(verb
='Adding'),
10333 'A/D/H/chi' : Item(verb
='Adding'),
10334 'A/D/H/psi' : Item(verb
='Adding'),
10335 'A/D/H/omega' : Item(verb
='Adding'),
10337 wc_status
.tweak(wc_rev
=9)
10339 'A' : Item(wc_rev
=10),
10340 'A/B' : Item(wc_rev
=10),
10341 'A/B/lambda' : Item(wc_rev
=10),
10342 'A/B/E' : Item(wc_rev
=10),
10343 'A/B/E/alpha' : Item(wc_rev
=10),
10344 'A/B/E/beta' : Item(wc_rev
=10),
10345 'A/B/F' : Item(wc_rev
=10),
10346 'A/mu' : Item(wc_rev
=10),
10347 'A/C' : Item(wc_rev
=10),
10348 'A/D' : Item(wc_rev
=10),
10349 'A/D/gamma' : Item(wc_rev
=10),
10350 'A/D/G' : Item(wc_rev
=10),
10351 'A/D/G/pi' : Item(wc_rev
=10),
10352 'A/D/G/rho' : Item(wc_rev
=10),
10353 'A/D/G/tau' : Item(wc_rev
=10),
10354 'A/D/H' : Item(wc_rev
=10),
10355 'A/D/H/chi' : Item(wc_rev
=10),
10356 'A/D/H/omega' : Item(wc_rev
=10),
10357 'A/D/H/psi' : Item(wc_rev
=10),
10359 wc_status
.tweak(status
=' ')
10360 svntest
.actions
.run_and_verify_commit(wc_dir
,
10366 expected_output
= wc
.State(short_A_path
, {
10367 'mu' : Item(status
='U '),
10368 'D/H/psi' : Item(status
='U '),
10369 '' : Item(status
=' U'),
10371 expected_A_status
= wc
.State(short_A_path
, {
10372 '' : Item(status
=' M', wc_rev
=10),
10373 'B' : Item(status
=' ', wc_rev
=10),
10374 'mu' : Item(status
='M ', wc_rev
=10),
10375 'B/E' : Item(status
=' ', wc_rev
=10),
10376 'B/E/alpha' : Item(status
=' ', wc_rev
=10),
10377 'B/E/beta' : Item(status
=' ', wc_rev
=10),
10378 'B/lambda' : Item(status
=' ', wc_rev
=10),
10379 'B/F' : Item(status
=' ', wc_rev
=10),
10380 'C' : Item(status
=' ', wc_rev
=10),
10381 'D' : Item(status
=' ', wc_rev
=10),
10382 'D/G' : Item(status
=' ', wc_rev
=10),
10383 'D/G/pi' : Item(status
=' ', wc_rev
=10),
10384 'D/G/rho' : Item(status
=' ', wc_rev
=10),
10385 'D/G/tau' : Item(status
=' ', wc_rev
=10),
10386 'D/gamma' : Item(status
=' ', wc_rev
=10),
10387 'D/H' : Item(status
=' ', wc_rev
=10),
10388 'D/H/chi' : Item(status
=' ', wc_rev
=10),
10389 'D/H/psi' : Item(status
='M ', wc_rev
=10),
10390 'D/H/omega' : Item(status
=' ', wc_rev
=10),
10392 expected_A_disk
= wc
.State('', {
10393 '' : Item(props
={SVN_PROP_MERGEINFO
: '/A:3\n/A_COPY:8\n'}),
10395 'mu' : Item("New content"),
10397 'B/E/alpha' : Item("This is the file 'alpha'.\n"),
10398 'B/E/beta' : Item("This is the file 'beta'.\n"),
10399 'B/lambda' : Item("This is the file 'lambda'.\n"),
10404 'D/G/pi' : Item("This is the file 'pi'.\n"),
10405 'D/G/rho' : Item("This is the file 'rho'.\n"),
10406 'D/G/tau' : Item("This is the file 'tau'.\n"),
10407 'D/gamma' : Item("This is the file 'gamma'.\n"),
10409 'D/H/chi' : Item("This is the file 'chi'.\n"),
10410 'D/H/psi' : Item("New content"),
10411 'D/H/omega' : Item("This is the file 'omega'.\n"),
10413 expected_A_skip
= wc
.State(short_A_path
, {})
10414 os
.chdir(svntest
.main
.work_dir
)
10415 svntest
.actions
.run_and_verify_merge(short_A_path
, '7', '8',
10422 None, None, None, None,
10424 os
.chdir(saved_cwd
)
10426 ########################################################################
10430 # list all tests here, starting with None:
10431 test_list
= [ None,
10432 textual_merges_galore
,
10434 delete_file_and_dir
,
10435 simple_property_merges
,
10436 merge_with_implicit_target_using_r
,
10437 merge_with_implicit_target_using_c
,
10438 merge_with_implicit_target_and_revs
,
10439 merge_catches_nonexistent_target
,
10440 merge_tree_deleted_in_target
,
10441 merge_similar_unrelated_trees
,
10444 three_way_merge_add_of_existing_binary_file
,
10445 merge_one_file_using_r
,
10446 merge_one_file_using_c
,
10447 merge_one_file_using_implicit_revs
,
10449 merge_in_new_file_and_diff
,
10450 merge_skips_obstructions
,
10451 merge_into_missing
,
10452 dry_run_adds_file_with_prop
,
10453 merge_binary_with_common_ancestry
,
10454 merge_funny_chars_on_path
,
10455 merge_keyword_expansions
,
10456 merge_prop_change_to_deleted_target
,
10457 merge_file_with_space_in_its_name
,
10458 merge_dir_branches
,
10459 safe_property_merge
,
10460 property_merge_from_branch
,
10461 property_merge_undo_redo
,
10462 cherry_pick_text_conflict
,
10463 merge_file_replace
,
10465 XFail(merge_dir_and_file_replace
),
10466 merge_file_replace_to_mixed_rev_wc
,
10467 merge_added_dir_to_deleted_in_target
,
10468 merge_ignore_whitespace
,
10469 merge_ignore_eolstyle
,
10470 merge_add_over_versioned_file_conflicts
,
10471 merge_conflict_markers_matching_eol
,
10472 merge_eolstyle_handling
,
10473 avoid_repeated_merge_using_inherited_merge_info
,
10474 avoid_repeated_merge_on_subtree_with_merge_info
,
10475 obey_reporter_api_semantics_while_doing_subtree_merges
,
10476 SkipUnless(mergeinfo_inheritance
,
10477 server_has_mergeinfo
),
10479 mergeinfo_inheritance_and_discontinuous_ranges
,
10480 SkipUnless(merge_to_target_with_copied_children
,
10481 server_has_mergeinfo
),
10482 merge_to_switched_path
,
10483 SkipUnless(merge_to_path_with_switched_children
,
10484 server_has_mergeinfo
),
10485 merge_with_implicit_target_file
,
10486 SkipUnless(empty_mergeinfo
,
10487 server_has_mergeinfo
),
10488 prop_add_to_child_with_mergeinfo
,
10489 diff_repos_does_not_update_mergeinfo
,
10490 XFail(avoid_reflected_revs
),
10491 update_loses_mergeinfo
,
10492 XFail(merge_loses_mergeinfo
),
10493 single_file_replace_style_merge_capability
,
10494 merge_to_out_of_date_target
,
10495 merge_with_depth_files
,
10496 merge_fails_if_subtree_is_deleted_on_src
,
10497 no_mergeinfo_from_no_op_merge
,
10498 merge_to_sparse_directories
,
10499 merge_old_and_new_revs_from_renamed_dir
,
10500 merge_with_child_having_different_rev_ranges_to_merge
,
10501 merge_old_and_new_revs_from_renamed_file
,
10502 merge_with_auto_rev_range_detection
,
10503 mergeinfo_recording_in_skipped_merge
,
10505 propchange_of_subdir_raises_conflict
,
10506 reverse_merge_prop_add_on_child
,
10507 XFail(merge_target_with_non_inheritable_mergeinfo
),
10508 self_reverse_merge
,
10509 ignore_ancestry_and_mergeinfo
,
10510 merge_from_renamed_branch_fails_while_avoiding_repeat_merge
,
10511 merge_source_normalization_and_subtree_merges
,
10512 new_subtrees_should_not_break_merge
,
10514 reintegrate_branch_never_merged_to
,
10515 reintegrate_fail_on_modified_wc
,
10516 reintegrate_fail_on_mixed_rev_wc
,
10517 reintegrate_fail_on_switched_wc
,
10518 reintegrate_fail_on_shallow_wc
,
10519 XFail(reintegrate_fail_on_stale_source
),
10520 dont_add_mergeinfo_from_own_history
,
10523 if __name__
== '__main__':
10524 svntest
.main
.run_tests(test_list
)