867
845
old = transform.trans_id_tree_path('old')
868
846
subdir = transform.trans_id_tree_file_id('subdir-id')
869
847
new = transform.trans_id_tree_path('new')
870
self.assertEqual([], list(transform.iter_changes()))
848
self.assertEqual([], list(transform._iter_changes()))
872
850
#content deletion
873
851
transform.delete_contents(old)
874
852
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
875
853
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
876
(False, False))], list(transform.iter_changes()))
854
(False, False))], list(transform._iter_changes()))
879
857
transform.create_file('blah', old)
880
858
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
881
859
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
882
(False, False))], list(transform.iter_changes()))
860
(False, False))], list(transform._iter_changes()))
883
861
transform.cancel_deletion(old)
884
862
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
885
863
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
886
(False, False))], list(transform.iter_changes()))
864
(False, False))], list(transform._iter_changes()))
887
865
transform.cancel_creation(old)
889
867
# move file_id to a different file
890
self.assertEqual([], list(transform.iter_changes()))
868
self.assertEqual([], list(transform._iter_changes()))
891
869
transform.unversion_file(old)
892
870
transform.version_file('id-1', new)
893
871
transform.adjust_path('old', root, new)
894
872
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
895
873
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
896
(False, False))], list(transform.iter_changes()))
874
(False, False))], list(transform._iter_changes()))
897
875
transform.cancel_versioning(new)
898
876
transform._removed_id = set()
901
self.assertEqual([], list(transform.iter_changes()))
879
self.assertEqual([], list(transform._iter_changes()))
902
880
transform.set_executability(True, old)
903
881
self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
904
882
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
905
(False, True))], list(transform.iter_changes()))
883
(False, True))], list(transform._iter_changes()))
906
884
transform.set_executability(None, old)
909
self.assertEqual([], list(transform.iter_changes()))
887
self.assertEqual([], list(transform._iter_changes()))
910
888
transform.adjust_path('new', root, old)
911
889
transform._new_parent = {}
912
890
self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
913
891
('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
914
(False, False))], list(transform.iter_changes()))
892
(False, False))], list(transform._iter_changes()))
915
893
transform._new_name = {}
917
895
# parent directory
918
self.assertEqual([], list(transform.iter_changes()))
896
self.assertEqual([], list(transform._iter_changes()))
919
897
transform.adjust_path('new', subdir, old)
920
898
transform._new_name = {}
921
899
self.assertEqual([('id-1', ('old', 'subdir/old'), False,
922
900
(True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
923
901
('file', 'file'), (False, False))],
924
list(transform.iter_changes()))
902
list(transform._iter_changes()))
925
903
transform._new_path = {}
1967
1801
parent = tt.trans_id_file_id('parent-id')
1968
1802
tt.new_file('file', parent, 'Contents')
1969
1803
resolve_conflicts(tt)
1972
class TestTransformPreview(tests.TestCaseWithTransport):
1974
def create_tree(self):
1975
tree = self.make_branch_and_tree('.')
1976
self.build_tree_contents([('a', 'content 1')])
1977
tree.add('a', 'a-id')
1978
tree.commit('rev1', rev_id='rev1')
1979
return tree.branch.repository.revision_tree('rev1')
1981
def get_empty_preview(self):
1982
repository = self.make_repository('repo')
1983
tree = repository.revision_tree(_mod_revision.NULL_REVISION)
1984
preview = TransformPreview(tree)
1985
self.addCleanup(preview.finalize)
1988
def test_transform_preview(self):
1989
revision_tree = self.create_tree()
1990
preview = TransformPreview(revision_tree)
1991
self.addCleanup(preview.finalize)
1993
def test_transform_preview_tree(self):
1994
revision_tree = self.create_tree()
1995
preview = TransformPreview(revision_tree)
1996
self.addCleanup(preview.finalize)
1997
preview.get_preview_tree()
1999
def test_transform_new_file(self):
2000
revision_tree = self.create_tree()
2001
preview = TransformPreview(revision_tree)
2002
self.addCleanup(preview.finalize)
2003
preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2004
preview_tree = preview.get_preview_tree()
2005
self.assertEqual(preview_tree.kind('file2-id'), 'file')
2007
preview_tree.get_file('file2-id').read(), 'content B\n')
2009
def test_diff_preview_tree(self):
2010
revision_tree = self.create_tree()
2011
preview = TransformPreview(revision_tree)
2012
self.addCleanup(preview.finalize)
2013
preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2014
preview_tree = preview.get_preview_tree()
2016
show_diff_trees(revision_tree, preview_tree, out)
2017
lines = out.getvalue().splitlines()
2018
self.assertEqual(lines[0], "=== added file 'file2'")
2019
# 3 lines of diff administrivia
2020
self.assertEqual(lines[4], "+content B")
2022
def test_transform_conflicts(self):
2023
revision_tree = self.create_tree()
2024
preview = TransformPreview(revision_tree)
2025
self.addCleanup(preview.finalize)
2026
preview.new_file('a', preview.root, 'content 2')
2027
resolve_conflicts(preview)
2028
trans_id = preview.trans_id_file_id('a-id')
2029
self.assertEqual('a.moved', preview.final_name(trans_id))
2031
def get_tree_and_preview_tree(self):
2032
revision_tree = self.create_tree()
2033
preview = TransformPreview(revision_tree)
2034
self.addCleanup(preview.finalize)
2035
a_trans_id = preview.trans_id_file_id('a-id')
2036
preview.delete_contents(a_trans_id)
2037
preview.create_file('b content', a_trans_id)
2038
preview_tree = preview.get_preview_tree()
2039
return revision_tree, preview_tree
2041
def test_iter_changes(self):
2042
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2043
root = revision_tree.inventory.root.file_id
2044
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2045
(root, root), ('a', 'a'), ('file', 'file'),
2047
list(preview_tree.iter_changes(revision_tree)))
2049
def test_wrong_tree_value_error(self):
2050
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2051
e = self.assertRaises(ValueError, preview_tree.iter_changes,
2053
self.assertEqual('from_tree must be transform source tree.', str(e))
2055
def test_include_unchanged_value_error(self):
2056
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2057
e = self.assertRaises(ValueError, preview_tree.iter_changes,
2058
revision_tree, include_unchanged=True)
2059
self.assertEqual('include_unchanged is not supported', str(e))
2061
def test_specific_files(self):
2062
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2063
e = self.assertRaises(ValueError, preview_tree.iter_changes,
2064
revision_tree, specific_files=['pete'])
2065
self.assertEqual('specific_files is not supported', str(e))
2067
def test_want_unversioned_value_error(self):
2068
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2069
e = self.assertRaises(ValueError, preview_tree.iter_changes,
2070
revision_tree, want_unversioned=True)
2071
self.assertEqual('want_unversioned is not supported', str(e))
2073
def test_ignore_extra_trees_no_specific_files(self):
2074
# extra_trees is harmless without specific_files, so we'll silently
2075
# accept it, even though we won't use it.
2076
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2077
preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
2079
def test_ignore_require_versioned_no_specific_files(self):
2080
# require_versioned is meaningless without specific_files.
2081
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2082
preview_tree.iter_changes(revision_tree, require_versioned=False)
2084
def test_ignore_pb(self):
2085
# pb could be supported, but TT.iter_changes doesn't support it.
2086
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2087
preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
2089
def test_kind(self):
2090
revision_tree = self.create_tree()
2091
preview = TransformPreview(revision_tree)
2092
self.addCleanup(preview.finalize)
2093
preview.new_file('file', preview.root, 'contents', 'file-id')
2094
preview.new_directory('directory', preview.root, 'dir-id')
2095
preview_tree = preview.get_preview_tree()
2096
self.assertEqual('file', preview_tree.kind('file-id'))
2097
self.assertEqual('directory', preview_tree.kind('dir-id'))
2099
def test_get_file_mtime(self):
2100
preview = self.get_empty_preview()
2101
file_trans_id = preview.new_file('file', preview.root, 'contents',
2103
limbo_path = preview._limbo_name(file_trans_id)
2104
preview_tree = preview.get_preview_tree()
2105
self.assertEqual(os.stat(limbo_path).st_mtime,
2106
preview_tree.get_file_mtime('file-id'))
2108
def test_get_file(self):
2109
preview = self.get_empty_preview()
2110
preview.new_file('file', preview.root, 'contents', 'file-id')
2111
preview_tree = preview.get_preview_tree()
2112
tree_file = preview_tree.get_file('file-id')
2114
self.assertEqual('contents', tree_file.read())
2118
def test_get_symlink_target(self):
2119
self.requireFeature(SymlinkFeature)
2120
preview = self.get_empty_preview()
2121
preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2122
preview_tree = preview.get_preview_tree()
2123
self.assertEqual('target',
2124
preview_tree.get_symlink_target('symlink-id'))
2126
def test_all_file_ids(self):
2127
tree = self.make_branch_and_tree('tree')
2128
self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2129
tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2130
preview = TransformPreview(tree)
2131
self.addCleanup(preview.finalize)
2132
preview.unversion_file(preview.trans_id_file_id('b-id'))
2133
c_trans_id = preview.trans_id_file_id('c-id')
2134
preview.unversion_file(c_trans_id)
2135
preview.version_file('c-id', c_trans_id)
2136
preview_tree = preview.get_preview_tree()
2137
self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2138
preview_tree.all_file_ids())
2140
def test_path2id_deleted_unchanged(self):
2141
tree = self.make_branch_and_tree('tree')
2142
self.build_tree(['tree/unchanged', 'tree/deleted'])
2143
tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2144
preview = TransformPreview(tree)
2145
self.addCleanup(preview.finalize)
2146
preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2147
preview_tree = preview.get_preview_tree()
2148
self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2149
self.assertIs(None, preview_tree.path2id('deleted'))
2151
def test_path2id_created(self):
2152
tree = self.make_branch_and_tree('tree')
2153
self.build_tree(['tree/unchanged'])
2154
tree.add(['unchanged'], ['unchanged-id'])
2155
preview = TransformPreview(tree)
2156
self.addCleanup(preview.finalize)
2157
preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2158
'contents', 'new-id')
2159
preview_tree = preview.get_preview_tree()
2160
self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2162
def test_path2id_moved(self):
2163
tree = self.make_branch_and_tree('tree')
2164
self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2165
tree.add(['old_parent', 'old_parent/child'],
2166
['old_parent-id', 'child-id'])
2167
preview = TransformPreview(tree)
2168
self.addCleanup(preview.finalize)
2169
new_parent = preview.new_directory('new_parent', preview.root,
2171
preview.adjust_path('child', new_parent,
2172
preview.trans_id_file_id('child-id'))
2173
preview_tree = preview.get_preview_tree()
2174
self.assertIs(None, preview_tree.path2id('old_parent/child'))
2175
self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2177
def test_path2id_renamed_parent(self):
2178
tree = self.make_branch_and_tree('tree')
2179
self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2180
tree.add(['old_name', 'old_name/child'],
2181
['parent-id', 'child-id'])
2182
preview = TransformPreview(tree)
2183
self.addCleanup(preview.finalize)
2184
preview.adjust_path('new_name', preview.root,
2185
preview.trans_id_file_id('parent-id'))
2186
preview_tree = preview.get_preview_tree()
2187
self.assertIs(None, preview_tree.path2id('old_name/child'))
2188
self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
2190
def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2191
preview_tree = tt.get_preview_tree()
2192
preview_result = list(preview_tree.iter_entries_by_dir(
2196
actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2197
self.assertEqual(actual_result, preview_result)
2199
def test_iter_entries_by_dir_new(self):
2200
tree = self.make_branch_and_tree('tree')
2201
tt = TreeTransform(tree)
2202
tt.new_file('new', tt.root, 'contents', 'new-id')
2203
self.assertMatchingIterEntries(tt)
2205
def test_iter_entries_by_dir_deleted(self):
2206
tree = self.make_branch_and_tree('tree')
2207
self.build_tree(['tree/deleted'])
2208
tree.add('deleted', 'deleted-id')
2209
tt = TreeTransform(tree)
2210
tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2211
self.assertMatchingIterEntries(tt)
2213
def test_iter_entries_by_dir_unversioned(self):
2214
tree = self.make_branch_and_tree('tree')
2215
self.build_tree(['tree/removed'])
2216
tree.add('removed', 'removed-id')
2217
tt = TreeTransform(tree)
2218
tt.unversion_file(tt.trans_id_file_id('removed-id'))
2219
self.assertMatchingIterEntries(tt)
2221
def test_iter_entries_by_dir_moved(self):
2222
tree = self.make_branch_and_tree('tree')
2223
self.build_tree(['tree/moved', 'tree/new_parent/'])
2224
tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2225
tt = TreeTransform(tree)
2226
tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2227
tt.trans_id_file_id('moved-id'))
2228
self.assertMatchingIterEntries(tt)
2230
def test_iter_entries_by_dir_specific_file_ids(self):
2231
tree = self.make_branch_and_tree('tree')
2232
tree.set_root_id('tree-root-id')
2233
self.build_tree(['tree/parent/', 'tree/parent/child'])
2234
tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2235
tt = TreeTransform(tree)
2236
self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
2238
def test_symlink_content_summary(self):
2239
self.requireFeature(SymlinkFeature)
2240
preview = self.get_empty_preview()
2241
preview.new_symlink('path', preview.root, 'target', 'path-id')
2242
summary = preview.get_preview_tree().path_content_summary('path')
2243
self.assertEqual(('symlink', None, None, 'target'), summary)
2245
def test_missing_content_summary(self):
2246
preview = self.get_empty_preview()
2247
summary = preview.get_preview_tree().path_content_summary('path')
2248
self.assertEqual(('missing', None, None, None), summary)
2250
def test_deleted_content_summary(self):
2251
tree = self.make_branch_and_tree('tree')
2252
self.build_tree(['tree/path/'])
2254
preview = TransformPreview(tree)
2255
self.addCleanup(preview.finalize)
2256
preview.delete_contents(preview.trans_id_tree_path('path'))
2257
summary = preview.get_preview_tree().path_content_summary('path')
2258
self.assertEqual(('missing', None, None, None), summary)
2260
def test_file_content_summary_executable(self):
2261
if not osutils.supports_executable():
2262
raise TestNotApplicable()
2263
preview = self.get_empty_preview()
2264
path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2265
preview.set_executability(True, path_id)
2266
summary = preview.get_preview_tree().path_content_summary('path')
2267
self.assertEqual(4, len(summary))
2268
self.assertEqual('file', summary[0])
2269
# size must be known
2270
self.assertEqual(len('contents'), summary[1])
2272
self.assertEqual(True, summary[2])
2273
# will not have hash (not cheap to determine)
2274
self.assertIs(None, summary[3])
2276
def test_change_executability(self):
2277
if not osutils.supports_executable():
2278
raise TestNotApplicable()
2279
tree = self.make_branch_and_tree('tree')
2280
self.build_tree(['tree/path'])
2282
preview = TransformPreview(tree)
2283
self.addCleanup(preview.finalize)
2284
path_id = preview.trans_id_tree_path('path')
2285
preview.set_executability(True, path_id)
2286
summary = preview.get_preview_tree().path_content_summary('path')
2287
self.assertEqual(True, summary[2])
2289
def test_file_content_summary_non_exec(self):
2290
preview = self.get_empty_preview()
2291
preview.new_file('path', preview.root, 'contents', 'path-id')
2292
summary = preview.get_preview_tree().path_content_summary('path')
2293
self.assertEqual(4, len(summary))
2294
self.assertEqual('file', summary[0])
2295
# size must be known
2296
self.assertEqual(len('contents'), summary[1])
2298
if osutils.supports_executable():
2299
self.assertEqual(False, summary[2])
2301
self.assertEqual(None, summary[2])
2302
# will not have hash (not cheap to determine)
2303
self.assertIs(None, summary[3])
2305
def test_dir_content_summary(self):
2306
preview = self.get_empty_preview()
2307
preview.new_directory('path', preview.root, 'path-id')
2308
summary = preview.get_preview_tree().path_content_summary('path')
2309
self.assertEqual(('directory', None, None, None), summary)
2311
def test_tree_content_summary(self):
2312
preview = self.get_empty_preview()
2313
path = preview.new_directory('path', preview.root, 'path-id')
2314
preview.set_tree_reference('rev-1', path)
2315
summary = preview.get_preview_tree().path_content_summary('path')
2316
self.assertEqual(4, len(summary))
2317
self.assertEqual('tree-reference', summary[0])
2319
def test_annotate(self):
2320
tree = self.make_branch_and_tree('tree')
2321
self.build_tree_contents([('tree/file', 'a\n')])
2322
tree.add('file', 'file-id')
2323
tree.commit('a', rev_id='one')
2324
self.build_tree_contents([('tree/file', 'a\nb\n')])
2325
preview = TransformPreview(tree)
2326
self.addCleanup(preview.finalize)
2327
file_trans_id = preview.trans_id_file_id('file-id')
2328
preview.delete_contents(file_trans_id)
2329
preview.create_file('a\nb\nc\n', file_trans_id)
2330
preview_tree = preview.get_preview_tree()
2336
annotation = preview_tree.annotate_iter('file-id', 'me:')
2337
self.assertEqual(expected, annotation)
2339
def test_annotate_missing(self):
2340
preview = self.get_empty_preview()
2341
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2342
preview_tree = preview.get_preview_tree()
2348
annotation = preview_tree.annotate_iter('file-id', 'me:')
2349
self.assertEqual(expected, annotation)
2351
def test_annotate_rename(self):
2352
tree = self.make_branch_and_tree('tree')
2353
self.build_tree_contents([('tree/file', 'a\n')])
2354
tree.add('file', 'file-id')
2355
tree.commit('a', rev_id='one')
2356
preview = TransformPreview(tree)
2357
self.addCleanup(preview.finalize)
2358
file_trans_id = preview.trans_id_file_id('file-id')
2359
preview.adjust_path('newname', preview.root, file_trans_id)
2360
preview_tree = preview.get_preview_tree()
2364
annotation = preview_tree.annotate_iter('file-id', 'me:')
2365
self.assertEqual(expected, annotation)
2367
def test_annotate_deleted(self):
2368
tree = self.make_branch_and_tree('tree')
2369
self.build_tree_contents([('tree/file', 'a\n')])
2370
tree.add('file', 'file-id')
2371
tree.commit('a', rev_id='one')
2372
self.build_tree_contents([('tree/file', 'a\nb\n')])
2373
preview = TransformPreview(tree)
2374
self.addCleanup(preview.finalize)
2375
file_trans_id = preview.trans_id_file_id('file-id')
2376
preview.delete_contents(file_trans_id)
2377
preview_tree = preview.get_preview_tree()
2378
annotation = preview_tree.annotate_iter('file-id', 'me:')
2379
self.assertIs(None, annotation)
2381
def test_stored_kind(self):
2382
preview = self.get_empty_preview()
2383
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2384
preview_tree = preview.get_preview_tree()
2385
self.assertEqual('file', preview_tree.stored_kind('file-id'))
2387
def test_is_executable(self):
2388
preview = self.get_empty_preview()
2389
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2390
preview.set_executability(True, preview.trans_id_file_id('file-id'))
2391
preview_tree = preview.get_preview_tree()
2392
self.assertEqual(True, preview_tree.is_executable('file-id'))
2394
def test_get_set_parent_ids(self):
2395
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2396
self.assertEqual([], preview_tree.get_parent_ids())
2397
preview_tree.set_parent_ids(['rev-1'])
2398
self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2400
def test_plan_file_merge(self):
2401
work_a = self.make_branch_and_tree('wta')
2402
self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2403
work_a.add('file', 'file-id')
2404
base_id = work_a.commit('base version')
2405
tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2406
preview = TransformPreview(work_a)
2407
self.addCleanup(preview.finalize)
2408
trans_id = preview.trans_id_file_id('file-id')
2409
preview.delete_contents(trans_id)
2410
preview.create_file('b\nc\nd\ne\n', trans_id)
2411
self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2412
tree_a = preview.get_preview_tree()
2413
tree_a.set_parent_ids([base_id])
2415
('killed-a', 'a\n'),
2416
('killed-b', 'b\n'),
2417
('unchanged', 'c\n'),
2418
('unchanged', 'd\n'),
2421
], list(tree_a.plan_file_merge('file-id', tree_b)))
2423
def test_plan_file_merge_revision_tree(self):
2424
work_a = self.make_branch_and_tree('wta')
2425
self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2426
work_a.add('file', 'file-id')
2427
base_id = work_a.commit('base version')
2428
tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2429
preview = TransformPreview(work_a.basis_tree())
2430
self.addCleanup(preview.finalize)
2431
trans_id = preview.trans_id_file_id('file-id')
2432
preview.delete_contents(trans_id)
2433
preview.create_file('b\nc\nd\ne\n', trans_id)
2434
self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2435
tree_a = preview.get_preview_tree()
2436
tree_a.set_parent_ids([base_id])
2438
('killed-a', 'a\n'),
2439
('killed-b', 'b\n'),
2440
('unchanged', 'c\n'),
2441
('unchanged', 'd\n'),
2444
], list(tree_a.plan_file_merge('file-id', tree_b)))