/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/transform.py

  • Committer: Jelmer Vernooij
  • Date: 2018-03-24 10:24:48 UTC
  • mfrom: (6910 work)
  • mto: This revision was merged to the branch mainline in revision 6913.
  • Revision ID: jelmer@jelmer.uk-20180324102448-132p8l8t5ogdzhhu
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
69
69
    viewitems,
70
70
    viewvalues,
71
71
    )
 
72
from .tree import (
 
73
    find_previous_path,
 
74
    )
72
75
 
73
76
 
74
77
ROOT_PARENT = "root-parent"
90
93
class TreeTransformBase(object):
91
94
    """The base class for TreeTransform and its kin."""
92
95
 
93
 
    def __init__(self, tree, pb=None,
94
 
                 case_sensitive=True):
 
96
    def __init__(self, tree, pb=None, case_sensitive=True):
95
97
        """Constructor.
96
98
 
97
99
        :param tree: The tree that will be transformed, but not necessarily
132
134
        # The trans_id that will be used as the tree root
133
135
        root_id = tree.get_root_id()
134
136
        if root_id is not None:
135
 
            self._new_root = self.trans_id_tree_file_id(root_id)
 
137
            self._new_root = self.trans_id_tree_path('')
136
138
        else:
137
139
            self._new_root = None
138
140
        # Indicator of whether the transform has been applied
216
218
        # the physical root needs a new transaction id
217
219
        self._tree_path_ids.pop("")
218
220
        self._tree_id_paths.pop(old_root)
219
 
        self._new_root = self.trans_id_tree_file_id(self._tree.get_root_id())
 
221
        self._new_root = self.trans_id_tree_path('')
220
222
        if parent == old_root:
221
223
            parent = self._new_root
222
224
        self.adjust_path(name, parent, old_root)
285
287
        del self._new_parent[old_new_root]
286
288
        del self._new_name[old_new_root]
287
289
 
288
 
    def trans_id_tree_file_id(self, inventory_id):
289
 
        """Determine the transaction id of a working tree file.
290
 
 
291
 
        This reflects only files that already exist, not ones that will be
292
 
        added by transactions.
293
 
        """
294
 
        if inventory_id is None:
295
 
            raise ValueError('None is not a valid file id')
296
 
        path = self._tree.id2path(inventory_id)
297
 
        return self.trans_id_tree_path(path)
298
 
 
299
290
    def trans_id_file_id(self, file_id):
300
291
        """Determine or set the transaction id associated with a file ID.
301
292
        A new id is only created for file_ids that were never present.  If
308
299
            return self._r_new_id[file_id]
309
300
        else:
310
301
            try:
311
 
                next(self._tree.iter_entries_by_dir([file_id]))
312
 
            except StopIteration:
 
302
                path = self._tree.id2path(file_id)
 
303
            except errors.NoSuchId:
313
304
                if file_id in self._non_present_ids:
314
305
                    return self._non_present_ids[file_id]
315
306
                else:
317
308
                    self._non_present_ids[file_id] = trans_id
318
309
                    return trans_id
319
310
            else:
320
 
                return self.trans_id_tree_file_id(file_id)
 
311
                return self.trans_id_tree_path(path)
321
312
 
322
313
    def trans_id_tree_path(self, path):
323
314
        """Determine (and maybe set) the transaction ID for a tree path."""
454
445
        else:
455
446
            return self.tree_kind(trans_id)
456
447
 
 
448
    def tree_path(self, trans_id):
 
449
        """Determine the tree path associated with the trans_id."""
 
450
        return self._tree_id_paths.get(trans_id)
 
451
 
457
452
    def tree_file_id(self, trans_id):
458
453
        """Determine the file id associated with the trans_id in the tree"""
459
 
        try:
460
 
            path = self._tree_id_paths[trans_id]
461
 
        except KeyError:
462
 
            # the file is a new, unversioned file, or invalid trans_id
 
454
        path = self.tree_path(trans_id)
 
455
        if path is None:
463
456
            return None
464
457
        # the file is old; the old id is still valid
465
458
        if self._new_root == trans_id:
567
560
        parents.extend([t for t in self._removed_contents if
568
561
                        self.tree_kind(t) == 'directory'])
569
562
        for trans_id in self._removed_id:
570
 
            file_id = self.tree_file_id(trans_id)
571
 
            path = self._tree.id2path(file_id)
572
 
            if file_id is not None:
573
 
                if self._tree.stored_kind(path, file_id) == 'directory':
 
563
            path = self.tree_path(trans_id)
 
564
            if path is not None:
 
565
                if self._tree.stored_kind(path) == 'directory':
574
566
                    parents.append(trans_id)
575
567
            elif self.tree_kind(trans_id) == 'directory':
576
568
                parents.append(trans_id)
735
727
        active_tree_ids = all_ids.difference(removed_tree_ids)
736
728
        for trans_id, file_id in viewitems(self._new_id):
737
729
            if file_id in active_tree_ids:
738
 
                old_trans_id = self.trans_id_tree_file_id(file_id)
 
730
                path = self._tree.id2path(file_id)
 
731
                old_trans_id = self.trans_id_tree_path(path)
739
732
                conflicts.append(('duplicate id', old_trans_id, trans_id))
740
733
        return conflicts
741
734
 
901
894
                to_trans_ids[to_file_id] = trans_id
902
895
        return from_trans_ids, to_trans_ids
903
896
 
904
 
    def _from_file_data(self, from_trans_id, from_versioned, file_id):
 
897
    def _from_file_data(self, from_trans_id, from_versioned, from_path):
905
898
        """Get data about a file in the from (tree) state
906
899
 
907
900
        Return a (name, parent, kind, executable) tuple
909
902
        from_path = self._tree_id_paths.get(from_trans_id)
910
903
        if from_versioned:
911
904
            # get data from working tree if versioned
912
 
            from_entry = self._tree.iter_entries_by_dir([file_id]).next()[1]
 
905
            from_entry = self._tree.iter_entries_by_dir(
 
906
                    specific_files=[from_path]).next()[1]
913
907
            from_name = from_entry.name
914
908
            from_parent = from_entry.parent_id
915
909
        else:
978
972
            else:
979
973
                to_versioned = True
980
974
 
981
 
            from_name, from_parent, from_kind, from_executable = \
982
 
                self._from_file_data(from_trans_id, from_versioned, file_id)
983
 
 
984
 
            to_name, to_parent, to_kind, to_executable = \
985
 
                self._to_file_data(to_trans_id, from_trans_id, from_executable)
986
 
 
987
975
            if not from_versioned:
988
976
                from_path = None
989
977
            else:
992
980
                to_path = None
993
981
            else:
994
982
                to_path = final_paths.get_path(to_trans_id)
 
983
 
 
984
            from_name, from_parent, from_kind, from_executable = \
 
985
                self._from_file_data(from_trans_id, from_versioned, from_path)
 
986
 
 
987
            to_name, to_parent, to_kind, to_executable = \
 
988
                self._to_file_data(to_trans_id, from_trans_id, from_executable)
 
989
 
995
990
            if from_kind != to_kind:
996
991
                modified = True
997
992
            elif to_kind in ('file', 'symlink') and (
1077
1072
        return revision_id
1078
1073
 
1079
1074
    def _text_parent(self, trans_id):
1080
 
        file_id = self.tree_file_id(trans_id)
 
1075
        path = self.tree_path(trans_id)
1081
1076
        try:
1082
 
            if (file_id is None or
1083
 
                    self._tree.kind(self._tree.id2path(file_id), file_id) != 'file'):
 
1077
            if path is None or self._tree.kind(path) != 'file':
1084
1078
                return None
1085
1079
        except errors.NoSuchFile:
1086
1080
            return None
1087
 
        return file_id
 
1081
        return path
1088
1082
 
1089
1083
    def _get_parents_texts(self, trans_id):
1090
1084
        """Get texts for compression parents of this file."""
1091
 
        file_id = self._text_parent(trans_id)
1092
 
        if file_id is None:
 
1085
        path = self._text_parent(trans_id)
 
1086
        if path is None:
1093
1087
            return ()
1094
 
        return (self._tree.get_file_text(self._tree.id2path(file_id), file_id),)
 
1088
        return (self._tree.get_file_text(path),)
1095
1089
 
1096
1090
    def _get_parents_lines(self, trans_id):
1097
1091
        """Get lines for compression parents of this file."""
1098
 
        file_id = self._text_parent(trans_id)
1099
 
        if file_id is None:
 
1092
        path = self._text_parent(trans_id)
 
1093
        if path is None:
1100
1094
            return ()
1101
 
        return (self._tree.get_file_lines(self._tree.id2path(file_id), file_id),)
 
1095
        return (self._tree.get_file_lines(path),)
1102
1096
 
1103
1097
    def serialize(self, serializer):
1104
1098
        """Serialize this TreeTransform.
1407
1401
 
1408
1402
    def new_orphan(self, trans_id, parent_id):
1409
1403
        conf = self._tree.get_config_stack()
1410
 
        handle_orphan = conf.get('bzr.transform.orphan_policy')
 
1404
        handle_orphan = conf.get('transform.orphan_policy')
1411
1405
        handle_orphan(self, trans_id, parent_id)
1412
1406
 
1413
1407
 
1477
1471
 
1478
1472
 
1479
1473
opt_transform_orphan = _mod_config.RegistryOption(
1480
 
    'bzr.transform.orphan_policy', orphaning_registry,
 
1474
    'transform.orphan_policy', orphaning_registry,
1481
1475
    help='Policy for orphaned files during transform operations.',
1482
1476
    invalid='warning')
1483
1477
 
1771
1765
                inventory_delta.append((path, None, file_id, None))
1772
1766
            new_path_file_ids = dict((t, self.final_file_id(t)) for p, t in
1773
1767
                                     new_paths)
1774
 
            entries = self._tree.iter_entries_by_dir(
1775
 
                viewvalues(new_path_file_ids))
1776
 
            old_paths = dict((e.file_id, p) for p, e in entries)
1777
1768
            final_kinds = {}
1778
1769
            for num, (path, trans_id) in enumerate(new_paths):
1779
1770
                if (num % 10) == 0:
1801
1792
                    new_entry = inventory.make_entry(kind,
1802
1793
                        self.final_name(trans_id),
1803
1794
                        parent_file_id, file_id)
1804
 
                old_path = old_paths.get(new_entry.file_id)
 
1795
                try:
 
1796
                    old_path = self._tree.id2path(new_entry.file_id)
 
1797
                except errors.NoSuchId:
 
1798
                    old_path = None
1805
1799
                new_executability = self._new_executability.get(trans_id)
1806
1800
                if new_executability is not None:
1807
1801
                    new_entry.executable = new_executability
1952
1946
            path = self._tree_id_paths[parent_id]
1953
1947
        except KeyError:
1954
1948
            return
1955
 
        file_id = self.tree_file_id(parent_id)
1956
 
        if file_id is None:
1957
 
            return
1958
 
        entry = self._tree.iter_entries_by_dir([file_id]).next()[1]
 
1949
        entry = self._tree.iter_entries_by_dir(
 
1950
                specific_files=[path]).next()[1]
1959
1951
        children = getattr(entry, 'children', {})
1960
1952
        for child in children:
1961
1953
            childpath = joinpath(path, child)
2011
2003
            vf.fallback_versionedfiles.append(base_vf)
2012
2004
        return tree_revision
2013
2005
 
2014
 
    def _stat_limbo_file(self, file_id=None, trans_id=None):
2015
 
        if trans_id is None:
2016
 
            trans_id = self._transform.trans_id_file_id(file_id)
 
2006
    def _stat_limbo_file(self, trans_id):
2017
2007
        name = self._transform._limbo_name(trans_id)
2018
2008
        return os.lstat(name)
2019
2009
 
2123
2113
        self._all_children_cache[trans_id] = children
2124
2114
        return children
2125
2115
 
2126
 
    def iter_children(self, file_id):
 
2116
    def _iter_children(self, file_id):
2127
2117
        trans_id = self._transform.trans_id_file_id(file_id)
2128
2118
        for child_trans_id in self._all_children(trans_id):
2129
2119
            yield self._transform.final_file_id(child_trans_id)
2137
2127
            if self._transform.final_file_id(trans_id) is None:
2138
2128
                yield self._final_paths._determine_path(trans_id)
2139
2129
 
2140
 
    def _make_inv_entries(self, ordered_entries, specific_file_ids=None,
 
2130
    def _make_inv_entries(self, ordered_entries, specific_files=None,
2141
2131
        yield_parents=False):
2142
2132
        for trans_id, parent_file_id in ordered_entries:
2143
2133
            file_id = self._transform.final_file_id(trans_id)
2144
2134
            if file_id is None:
2145
2135
                continue
2146
 
            if (specific_file_ids is not None
2147
 
                and file_id not in specific_file_ids):
 
2136
            if (specific_files is not None and
 
2137
                unicode(self._final_paths.get_path(trans_id)) not in specific_files):
2148
2138
                continue
2149
2139
            kind = self._transform.final_kind(trans_id)
2150
2140
            if kind is None:
2172
2162
        return ordered_ids
2173
2163
 
2174
2164
    def iter_child_entries(self, path, file_id=None):
2175
 
        if file_id is None:
2176
 
            file_id = self.path2id(path)
2177
 
        if file_id is None:
 
2165
        trans_id = self._path2trans_id(path)
 
2166
        if trans_id is None:
2178
2167
            raise errors.NoSuchFile(path)
2179
 
        trans_id = self._transform.trans_id_file_id(file_id)
2180
2168
        todo = [(child_trans_id, trans_id) for child_trans_id in
2181
2169
                self._all_children(trans_id)]
2182
2170
        for entry, trans_id in self._make_inv_entries(todo):
2183
2171
            yield entry
2184
2172
 
2185
 
    def iter_entries_by_dir(self, specific_file_ids=None, yield_parents=False):
 
2173
    def iter_entries_by_dir(self, specific_files=None, yield_parents=False):
2186
2174
        # This may not be a maximally efficient implementation, but it is
2187
2175
        # reasonably straightforward.  An implementation that grafts the
2188
2176
        # TreeTransform changes onto the tree's iter_entries_by_dir results
2190
2178
        # position.
2191
2179
        ordered_ids = self._list_files_by_dir()
2192
2180
        for entry, trans_id in self._make_inv_entries(ordered_ids,
2193
 
            specific_file_ids, yield_parents=yield_parents):
 
2181
            specific_files, yield_parents=yield_parents):
2194
2182
            yield unicode(self._final_paths.get_path(trans_id)), entry
2195
2183
 
2196
2184
    def _iter_entries_for_dir(self, dir_path):
2197
2185
        """Return path, entry for items in a directory without recursing down."""
2198
 
        dir_file_id = self.path2id(dir_path)
2199
2186
        ordered_ids = []
2200
 
        for file_id in self.iter_children(dir_file_id):
2201
 
            trans_id = self._transform.trans_id_file_id(file_id)
2202
 
            ordered_ids.append((trans_id, file_id))
 
2187
        dir_trans_id = self._path2trans_id(dir_path)
 
2188
        dir_id = self._transform.final_file_id(dir_trans_id)
 
2189
        for child_trans_id in self._all_children(dir_trans_id):
 
2190
            ordered_ids.append((child_trans_id, dir_id))
2203
2191
        for entry, trans_id in self._make_inv_entries(ordered_ids):
2204
2192
            yield unicode(self._final_paths.get_path(trans_id)), entry
2205
2193
 
2230
2218
                yield path, 'V', entry.kind, entry.file_id, entry
2231
2219
 
2232
2220
    def kind(self, path, file_id=None):
2233
 
        if file_id is None:
2234
 
            file_id = self.path2id(path)
2235
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2221
        trans_id = self._path2trans_id(path)
 
2222
        if trans_id is None:
 
2223
            raise errors.NoSuchFile(path)
2236
2224
        return self._transform.final_kind(trans_id)
2237
2225
 
2238
2226
    def stored_kind(self, path, file_id=None):
2239
 
        if file_id is None:
2240
 
            file_id = self.path2id(path)
2241
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2227
        trans_id = self._path2trans_id(path)
 
2228
        if trans_id is None:
 
2229
            raise errors.NoSuchFile(path)
2242
2230
        try:
2243
2231
            return self._transform._new_contents[trans_id]
2244
2232
        except KeyError:
2253
2241
        if not self._content_change(file_id):
2254
2242
            return self._transform._tree.get_file_mtime(
2255
2243
                    self._transform._tree.id2path(file_id), file_id)
2256
 
        return self._stat_limbo_file(file_id).st_mtime
2257
 
 
2258
 
    def _file_size(self, entry, stat_value):
2259
 
        path = self.id2path(entry.file_id)
2260
 
        return self.get_file_size(path, entry.file_id)
 
2244
        trans_id = self._path2trans_id(path)
 
2245
        return self._stat_limbo_file(trans_id).st_mtime
2261
2246
 
2262
2247
    def get_file_size(self, path, file_id=None):
2263
2248
        """See Tree.get_file_size"""
2264
 
        if file_id is None:
2265
 
            file_id = self.path2id(path)
2266
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2249
        trans_id = self._path2trans_id(path)
 
2250
        if trans_id is None:
 
2251
            raise errors.NoSuchFile(path)
2267
2252
        kind = self._transform.final_kind(trans_id)
2268
2253
        if kind != 'file':
2269
2254
            return None
2270
2255
        if trans_id in self._transform._new_contents:
2271
 
            return self._stat_limbo_file(trans_id=trans_id).st_size
 
2256
            return self._stat_limbo_file(trans_id).st_size
2272
2257
        if self.kind(path, file_id) == 'file':
2273
2258
            return self._transform._tree.get_file_size(path, file_id)
2274
2259
        else:
2275
2260
            return None
2276
2261
 
2277
2262
    def get_file_verifier(self, path, file_id=None, stat_value=None):
2278
 
        if file_id is None:
2279
 
            file_id = self.path2id(path)
2280
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2263
        trans_id = self._path2trans_id(path)
 
2264
        if trans_id is None:
 
2265
            raise errors.NoSuchFile(path)
2281
2266
        kind = self._transform._new_contents.get(trans_id)
2282
2267
        if kind is None:
2283
2268
            return self._transform._tree.get_file_verifier(path, file_id)
2289
2274
                fileobj.close()
2290
2275
 
2291
2276
    def get_file_sha1(self, path, file_id=None, stat_value=None):
2292
 
        if file_id is None:
2293
 
            file_id = self.path2id(path)
2294
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2277
        trans_id = self._path2trans_id(path)
 
2278
        if trans_id is None:
 
2279
            raise errors.NoSuchFile(path)
2295
2280
        kind = self._transform._new_contents.get(trans_id)
2296
2281
        if kind is None:
2297
2282
            return self._transform._tree.get_file_sha1(path, file_id)
2303
2288
                fileobj.close()
2304
2289
 
2305
2290
    def is_executable(self, path, file_id=None):
2306
 
        if file_id is None:
2307
 
            file_id = self.path2id(path)
2308
 
        if file_id is None:
 
2291
        trans_id = self._path2trans_id(path)
 
2292
        if trans_id is None:
2309
2293
            return False
2310
 
        trans_id = self._transform.trans_id_file_id(file_id)
2311
2294
        try:
2312
2295
            return self._transform._new_executability[trans_id]
2313
2296
        except KeyError:
2386
2369
            file_id = self.path2id(path)
2387
2370
        if not self._content_change(file_id):
2388
2371
            return self._transform._tree.get_file(path, file_id)
2389
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2372
        trans_id = self._path2trans_id(path)
2390
2373
        name = self._transform._limbo_name(trans_id)
2391
2374
        return open(name, 'rb')
2392
2375
 
2432
2415
            file_id = self.path2id(path)
2433
2416
        if not self._content_change(file_id):
2434
2417
            return self._transform._tree.get_symlink_target(path)
2435
 
        trans_id = self._transform.trans_id_file_id(file_id)
 
2418
        trans_id = self._path2trans_id(path)
2436
2419
        name = self._transform._limbo_name(trans_id)
2437
2420
        return osutils.readlink(name)
2438
2421
 
2584
2567
    divert = set()
2585
2568
    try:
2586
2569
        pp.next_phase()
2587
 
        file_trans_id[wt.get_root_id()] = \
2588
 
            tt.trans_id_tree_file_id(wt.get_root_id())
 
2570
        file_trans_id[wt.get_root_id()] = tt.trans_id_tree_path('')
2589
2571
        with ui.ui_factory.nested_progress_bar() as pb:
2590
2572
            deferred_contents = []
2591
2573
            num = 0
2623
2605
                        else:
2624
2606
                            divert.add(file_id)
2625
2607
                    if (file_id not in divert and
2626
 
                        _content_match(tree, entry, file_id, kind,
 
2608
                        _content_match(tree, entry, tree_path, file_id, kind,
2627
2609
                        target_path)):
2628
2610
                        tt.delete_contents(tt.trans_id_tree_path(tree_path))
2629
2611
                        if kind == 'directory':
2735
2717
    return by_parent[old_parent]
2736
2718
 
2737
2719
 
2738
 
def _content_match(tree, entry, file_id, kind, target_path):
 
2720
def _content_match(tree, entry, tree_path, file_id, kind, target_path):
2739
2721
    if entry.kind != kind:
2740
2722
        return False
2741
2723
    if entry.kind == "directory":
2742
2724
        return True
2743
 
    path = tree.id2path(file_id)
2744
2725
    if entry.kind == "file":
2745
2726
        f = file(target_path, 'rb')
2746
2727
        try:
2747
 
            if tree.get_file_text(path, file_id) == f.read():
 
2728
            if tree.get_file_text(tree_path, file_id) == f.read():
2748
2729
                return True
2749
2730
        finally:
2750
2731
            f.close()
2751
2732
    elif entry.kind == "symlink":
2752
 
        if tree.get_symlink_target(path, file_id) == os.readlink(target_path):
 
2733
        if tree.get_symlink_target(tree_path, file_id) == os.readlink(target_path):
2753
2734
            return True
2754
2735
    return False
2755
2736
 
2859
2840
            trace.warning(unicode(conflict))
2860
2841
        pp.next_phase()
2861
2842
        tt.apply()
2862
 
        try:
 
2843
        if working_tree.supports_merge_modified():
2863
2844
            working_tree.set_merge_modified(merge_modified)
2864
 
        except errors.UnsupportedOperation:
2865
 
            pass  # well, whatever.
2866
2845
    finally:
2867
2846
        target_tree.unlock()
2868
2847
        tt.finalize()
2925
2904
                        if basis_tree is None:
2926
2905
                            basis_tree = working_tree.basis_tree()
2927
2906
                            basis_tree.lock_read()
2928
 
                        try:
2929
 
                            basis_path = basis_tree.id2path(file_id)
2930
 
                        except errors.NoSuchId:
 
2907
                        basis_path = find_previous_path(working_tree, basis_tree, wt_path)
 
2908
                        if basis_path is None:
2931
2909
                            if target_kind is None and not target_versioned:
2932
2910
                                keep_content = True
2933
2911
                        else:
2964
2942
                        basis_tree = working_tree.basis_tree()
2965
2943
                        basis_tree.lock_read()
2966
2944
                    new_sha1 = target_tree.get_file_sha1(target_path, file_id)
2967
 
                    try:
2968
 
                        basis_path = basis_tree.id2path(file_id)
2969
 
                    except errors.NoSuchId:
2970
 
                        basis_path = None
 
2945
                    basis_path = find_previous_path(target_tree, basis_tree, target_path)
2971
2946
                    if (basis_path is not None and
2972
2947
                        new_sha1 == basis_tree.get_file_sha1(basis_path, file_id)):
2973
2948
                        if file_id in merge_modified:
3101
3076
                        if file_id is None:
3102
3077
                            file_id = tt.inactive_file_id(trans_id)
3103
3078
                        _, entry = next(path_tree.iter_entries_by_dir(
3104
 
                            [file_id]))
 
3079
                            specific_files=[path_tree.id2path(file_id)]))
3105
3080
                        # special-case the other tree root (move its
3106
3081
                        # children to current root)
3107
3082
                        if entry.parent_id is None:
3122
3097
        elif c_type == 'unversioned parent':
3123
3098
            file_id = tt.inactive_file_id(conflict[1])
3124
3099
            # special-case the other tree root (move its children instead)
3125
 
            if path_tree and path_tree.has_id(file_id):
3126
 
                if path_tree.path2id('') == file_id:
 
3100
            if path_tree and path_tree.path2id('') == file_id:
3127
3101
                    # This is the root entry, skip it
3128
3102
                    continue
3129
3103
            tt.version_file(file_id, conflict[1])
3237
3211
                continue
3238
3212
            if executable[0] != executable[1]:
3239
3213
                continue
3240
 
            trans_id = tt.trans_id_tree_file_id(file_id)
 
3214
            trans_id = tt.trans_id_tree_path(paths[1])
3241
3215
            tt.delete_contents(trans_id)
3242
 
            tt.create_hardlink(source_tree.id2abspath(file_id), trans_id)
 
3216
            tt.create_hardlink(source_tree.abspath(paths[0]), trans_id)
3243
3217
        tt.apply()
3244
3218
    finally:
3245
3219
        tt.finalize()