36
from ..conflicts import ConflictList
37
from ..bzr.conflicts import TextConflict, MissingParent, UnversionedParent, DeletingParent, ContentsConflict
36
from ..conflicts import ConflictList, TextConflict
38
37
from ..errors import UnrelatedBranches, NoCommits
39
38
from ..merge import transform_tree, merge_inner, _PlanMerge
40
39
from ..osutils import basename, pathjoin, file_kind
40
from ..sixish import int2byte
43
43
TestCaseWithMemoryTransport,
135
135
this_branch=wt.branch,
137
137
with merger.make_preview_transform() as tt:
138
self.assertEqual([], tt.find_raw_conflicts())
138
self.assertEqual([], tt.find_conflicts())
139
139
preview = tt.get_preview_tree()
140
self.assertEqual(wt.path2id(''), preview.path2id(''))
140
self.assertEqual(wt.get_root_id(), preview.get_root_id())
142
142
def test_merge_unrelated_retains_root(self):
143
143
wt = self.make_branch_and_tree('tree')
146
146
merger = _mod_merge.Merge3Merger(wt, wt, wt.basis_tree(), other_tree,
147
147
this_branch=wt.branch,
149
with wt.preview_transform() as merger.tt:
149
with transform.TransformPreview(wt) as merger.tt:
150
150
merger._compute_transform()
151
151
new_root_id = merger.tt.final_file_id(merger.tt.root)
152
self.assertEqual(wt.path2id(''), new_root_id)
152
self.assertEqual(wt.get_root_id(), new_root_id)
154
154
def test_create_rename(self):
155
155
"""Rename an inventory entry while creating the file"""
199
199
def test_merge_inner_conflicts(self):
200
200
tree_a = self.make_branch_and_tree('a')
201
tree_a.set_conflicts([TextConflict('patha')])
201
tree_a.set_conflicts(ConflictList([TextConflict('patha')]))
202
202
merge_inner(tree_a.branch, tree_a, tree_a, this_tree=tree_a)
203
203
self.assertEqual(1, len(tree_a.conflicts()))
220
220
tree_z.commit('removed b')
221
221
merge_inner(tree_z.branch, tree_a, base_tree, this_tree=tree_z)
222
222
self.assertEqual([
223
MissingParent('Created directory', 'b', b'b-id'),
224
UnversionedParent('Versioned directory', 'b', b'b-id')],
223
conflicts.MissingParent('Created directory', 'b', b'b-id'),
224
conflicts.UnversionedParent('Versioned directory', 'b', b'b-id')],
225
225
tree_z.conflicts())
226
226
merge_inner(tree_a.branch, tree_z.basis_tree(), base_tree,
227
227
this_tree=tree_a)
228
228
self.assertEqual([
229
DeletingParent('Not deleting', 'b', b'b-id'),
230
UnversionedParent('Versioned directory', 'b', b'b-id')],
229
conflicts.DeletingParent('Not deleting', 'b', b'b-id'),
230
conflicts.UnversionedParent('Versioned directory', 'b', b'b-id')],
231
231
tree_a.conflicts())
233
233
def test_nested_merge(self):
288
288
tree_b.commit('content change')
289
289
tree_b.merge_from_branch(tree_a.branch)
290
290
self.assertEqual(tree_b.conflicts(),
291
[ContentsConflict('file', file_id=b'file-id')])
291
[conflicts.ContentsConflict('file',
292
file_id=b'file-id')])
293
294
def test_merge_type_registry(self):
294
295
merge_type_option = option.Option.OPTIONS['merge-type']
476
477
this_tree, b'rev2b', other_branch=other_tree.branch)
477
478
merger.merge_type = _mod_merge.Merge3Merger
478
479
tree_merger = merger.make_merger()
479
with tree_merger.make_preview_transform() as tt:
480
preview_tree = tt.get_preview_tree()
481
with this_tree.get_file('file') as tree_file:
482
self.assertEqual(b'1\n2a\n', tree_file.read())
483
with preview_tree.get_file('file') as preview_file:
484
self.assertEqual(b'2b\n1\n2a\n', preview_file.read())
480
tt = tree_merger.make_preview_transform()
481
self.addCleanup(tt.finalize)
482
preview_tree = tt.get_preview_tree()
483
with this_tree.get_file('file') as tree_file:
484
self.assertEqual(b'1\n2a\n', tree_file.read())
485
with preview_tree.get_file('file') as preview_file:
486
self.assertEqual(b'2b\n1\n2a\n', preview_file.read())
486
488
def test_do_merge(self):
487
489
this_tree = self.make_branch_and_tree('this')
510
512
self.build_tree(['a'])
512
514
first_rev = tree.commit("added a")
513
old_root_id = tree.path2id('')
515
old_root_id = tree.get_root_id()
514
516
merger = _mod_merge.Merger.from_revision_ids(tree,
515
517
_mod_revision.NULL_REVISION,
564
566
self.plan_merge_vf.fallback_versionedfiles.append(self.vf)
566
568
def add_version(self, key, parents, text):
568
key, parents, [bytes([c]) + b'\n' for c in bytearray(text)])
569
self.vf.add_lines(key, parents, [int2byte(
570
c) + b'\n' for c in bytearray(text)])
570
572
def add_rev(self, prefix, revision_id, parents, text):
571
573
self.add_version((prefix, revision_id), [(prefix, p) for p in parents],
574
576
def add_uncommitted_version(self, key, parents, text):
575
577
self.plan_merge_vf.add_lines(key, parents,
576
[bytes([c]) + b'\n' for c in bytearray(text)])
578
[int2byte(c) + b'\n' for c in bytearray(text)])
578
580
def setup_plan_merge(self):
579
581
self.add_rev(b'root', b'A', [], b'abc')
1432
1434
((u'a', [u'a', u'a']), u'a', u'a'),
1433
1435
((root_id, [root_id, root_id]), root_id, root_id),
1434
1436
((u'a', [u'a', u'a']), u'a', u'a'),
1435
((False, [False, False]), False, False),
1437
((False, [False, False]), False, False)),
1439
1440
def test_not_in_base(self):
1479
1480
((None, [u'bar', u'bar']), u'bar', u'bar'),
1480
1481
((None, [root_id, root_id]), root_id, root_id),
1481
1482
((None, [u'bar', u'bar']), u'bar', u'bar'),
1482
((None, [False, False]), False, False),
1483
((None, [False, False]), False, False)),
1486
1486
def test_not_in_this(self):
1513
1513
((u'a', [u'a', u'a']), u'a', None),
1514
1514
((root_id, [root_id, root_id]), root_id, None),
1515
1515
((u'a', [u'a', u'a']), u'a', None),
1516
((False, [False, False]), False, None),
1516
((False, [False, False]), False, None)),
1520
1519
def test_file_not_in_one_lca(self):
1565
1564
((u'a', [u'a', u'a']), None, u'a'),
1566
1565
((root_id, [root_id, root_id]), None, root_id),
1567
1566
((u'a', [u'a', u'a']), None, u'a'),
1568
((False, [False, False]), None, False),
1567
((False, [False, False]), None, False)),
1572
1570
def test_not_in_other_or_lca(self):
1632
1630
((u'foo', [u'foo', None]), None, u'foo'),
1633
1631
((root_id, [root_id, None]), None, root_id),
1634
1632
((u'foo', [u'foo', None]), None, 'foo'),
1635
((False, [False, None]), None, False),
1633
((False, [False, None]), None, False)),
1639
1636
def test_only_in_one_lca(self):
1688
1685
((None, [None, None]), u'a', None),
1689
1686
((None, [None, None]), root_id, None),
1690
1687
((None, [None, None]), u'a', None),
1691
((None, [None, None]), False, None),
1688
((None, [None, None]), False, None)),
1695
1691
def test_one_lca_supersedes(self):
1820
1816
[(b'foo-id', False,
1821
1817
((root_id, [root_id, root_id]), root_id, root_id),
1822
1818
((u'foo', [u'bar', u'foo']), u'bar', u'bing'),
1823
((False, [False, False]), False, False),
1819
((False, [False, False]), False, False)),
1827
1822
def test_both_sides_revert(self):
1853
1848
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1854
1849
((root_id, [root_id, root_id]), root_id, root_id),
1855
1850
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1856
((False, [False, False]), False, False),
1851
((False, [False, False]), False, False)),
1860
1854
def test_different_lca_resolve_one_side_updates_content(self):
1892
1886
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1893
1887
((root_id, [root_id, root_id]), root_id, root_id),
1894
1888
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
1895
((False, [False, False]), False, False),
1889
((False, [False, False]), False, False)),
1899
1892
def test_same_lca_resolution_one_side_updates_content(self):
1955
1948
((u'a', [u'a', u'a']), u'b', u'a'),
1956
1949
((root_id, [root_id, root_id]), root_id, root_id),
1957
1950
((u'a', [u'a', u'a']), u'b', u'a'),
1958
((False, [False, False]), False, False),
1951
((False, [False, False]), False, False)),
1962
1954
def test_kind_changed(self):
1982
1974
((u'a', [u'a', u'a']), u'a', u'a'),
1983
1975
((root_id, [root_id, root_id]), root_id, root_id),
1984
1976
((u'a', [u'a', u'a']), u'a', u'a'),
1985
((False, [False, False]), False, False),
1977
((False, [False, False]), False, False)),
1989
1980
def test_this_changed_kind(self):
2029
2020
((u'b', [u'b', u'b']), u'b', u'b'),
2030
2021
((root_id, [root_id, root_id]), root_id, root_id),
2031
2022
((u'b', [u'b', u'b']), u'b', u'b'),
2032
((False, [False, False]), False, False),
2023
((False, [False, False]), False, False)),
2036
2026
def test_interesting_file_in_this(self):
2058
2048
((u'b', [u'b', u'b']), u'b', u'c'),
2059
2049
((root_id, [root_id, root_id]), root_id, root_id),
2060
2050
((u'b', [u'b', u'b']), u'b', u'c'),
2061
((False, [False, False]), False, False),
2051
((False, [False, False]), False, False)),
2065
2054
def test_interesting_file_in_base(self):
2089
2078
((u'c', [u'b', u'b']), u'b', u'b'),
2090
2079
((root_id, [root_id, root_id]), root_id, root_id),
2091
2080
((u'c', [u'b', u'b']), u'b', u'b'),
2092
((False, [False, False]), False, False),
2081
((False, [False, False]), False, False)),
2096
2084
def test_interesting_file_in_lca(self):
2118
2106
((u'b', [u'c', u'b']), u'b', u'b'),
2119
2107
((root_id, [root_id, root_id]), root_id, root_id),
2120
2108
((u'b', [u'c', u'b']), u'b', u'b'),
2121
((False, [False, False]), False, False),
2109
((False, [False, False]), False, False)),
2125
2112
def test_interesting_files(self):
2144
2131
((u'b', [u'b', u'b']), u'b', u'b'),
2145
2132
((root_id, [root_id, root_id]), root_id, root_id),
2146
2133
((u'b', [u'b', u'b']), u'b', u'b'),
2147
((False, [False, False]), False, False),
2134
((False, [False, False]), False, False)),
2275
2261
builder.build_snapshot([b'C-id', b'B-id'], [], revision_id=b'E-id')
2276
2262
# Have to use a real WT, because BranchBuilder doesn't support exec bit
2277
2263
wt = self.get_wt_from_builder(builder)
2278
with wt.transform() as tt:
2264
tt = transform.TreeTransform(wt)
2279
2266
tt.set_executability(True, tt.trans_id_tree_path('foo'))
2281
2271
self.assertTrue(wt.is_executable('foo'))
2282
2272
wt.commit('F-id', rev_id=b'F-id')
2283
2273
# Reset to D, so that we can merge F
2455
2445
((u'foo', [u'barry', u'foo']), u'blah', u'barry'),
2456
2446
((root_id, [root_id, root_id]), root_id, root_id),
2457
2447
((u'foo', [u'barry', u'foo']), u'blah', u'barry'),
2458
((False, [False, False]), False, False),
2448
((False, [False, False]), False, False)),
2461
2450
conflicts = wt.merge_from_branch(wt.branch, to_revision=b'F-id')
2462
2451
self.assertEqual(0, conflicts)
2561
2550
((None, [u'foo', None]), u'foo', u'foo'),
2562
2551
((None, [root_id, None]), root_id, root_id),
2563
2552
((None, [u'foo', None]), u'foo', u'foo'),
2564
((None, [False, None]), False, False),
2553
((None, [False, None]), False, False)),
2568
2556
def test_symlink_all_wt(self):
2624
2612
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2625
2613
((root_id, [root_id, root_id]), root_id, root_id),
2626
2614
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2627
((False, [False, False]), False, False),
2615
((False, [False, False]), False, False)),
2631
2618
def test_other_reverted_path_to_base(self):
2752
2739
((u'a', [u'a', u'b']), u'c', u'b'),
2753
2740
((root_id, [root_id, root_id]), root_id, root_id),
2754
2741
((u'a', [u'a', u'b']), u'c', u'b'),
2755
((False, [False, False]), False, False),
2742
((False, [False, False]), False, False)),
2757
2743
(b'foo-id', True,
2758
2744
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2759
2745
((root_id, [root_id, root_id]), root_id, root_id),
2760
2746
((u'foo', [u'foo', u'foo']), u'foo', u'foo'),
2761
((False, [False, False]), False, False),
2747
((False, [False, False]), False, False)),
2765
2750
def test_nested_tree_unmodified(self):
2874
2859
((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2875
2860
((root_id, [root_id, root_id]), root_id, root_id),
2876
2861
((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2877
((False, [False, False]), False, False),
2862
((False, [False, False]), False, False)),
2881
2865
def test_nested_tree_subtree_renamed_and_modified(self):
2920
2904
((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2921
2905
((root_id, [root_id, root_id]), root_id, root_id),
2922
2906
((u'sub', [u'sub', u'sub']), u'alt_sub', u'sub'),
2923
((False, [False, False]), False, False),
2907
((False, [False, False]), False, False)),
3126
3109
def test_uses_this_branch(self):
3127
3110
builder = self.make_text_conflict()
3128
with builder.make_preview_transform() as tt:
3111
tt = builder.make_preview_transform()
3112
self.addCleanup(tt.finalize)
3131
3114
def test_affected_files_cached(self):
3132
3115
"""Ensures that the config variable is cached"""
3201
3184
:param merge_as: the path in a tree to add the new directory as.
3202
3185
:returns: the conflicts from 'do_merge'.
3204
with contextlib.ExitStack() as stack:
3205
# Open and lock the various tree and branch objects
3206
wt, subdir_relpath = WorkingTree.open_containing(merge_as)
3207
stack.enter_context(wt.lock_write())
3208
branch_to_merge, subdir_to_merge = _mod_branch.Branch.open_containing(
3210
stack.enter_context(branch_to_merge.lock_read())
3211
other_tree = branch_to_merge.basis_tree()
3212
stack.enter_context(other_tree.lock_read())
3214
merger = _mod_merge.MergeIntoMerger(
3215
this_tree=wt, other_tree=other_tree, other_branch=branch_to_merge,
3216
target_subdir=subdir_relpath, source_subpath=subdir_to_merge)
3217
merger.set_base_revision(_mod_revision.NULL_REVISION, branch_to_merge)
3218
conflicts = merger.do_merge()
3219
merger.set_pending()
3187
operation = cleanup.OperationWithCleanups(self._merge_into)
3188
return operation.run(location, merge_as)
3190
def _merge_into(self, op, location, merge_as):
3191
# Open and lock the various tree and branch objects
3192
wt, subdir_relpath = WorkingTree.open_containing(merge_as)
3193
op.add_cleanup(wt.lock_write().unlock)
3194
branch_to_merge, subdir_to_merge = _mod_branch.Branch.open_containing(
3196
op.add_cleanup(branch_to_merge.lock_read().unlock)
3197
other_tree = branch_to_merge.basis_tree()
3198
op.add_cleanup(other_tree.lock_read().unlock)
3200
merger = _mod_merge.MergeIntoMerger(
3201
this_tree=wt, other_tree=other_tree, other_branch=branch_to_merge,
3202
target_subdir=subdir_relpath, source_subpath=subdir_to_merge)
3203
merger.set_base_revision(_mod_revision.NULL_REVISION, branch_to_merge)
3204
conflicts = merger.do_merge()
3205
merger.set_pending()
3222
3208
def assertTreeEntriesEqual(self, expected_entries, tree):
3223
3209
"""Assert that 'tree' contains the expected inventory entries.