~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

(jelmer) Deprecate Repository.iter_reverse_revision_history(). (Jelmer
 Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
    generate_ids,
55
55
    globbing,
56
56
    graph as _mod_graph,
 
57
    hashcache,
57
58
    ignores,
58
59
    inventory,
59
60
    merge,
71
72
 
72
73
from bzrlib import symbol_versioning
73
74
from bzrlib.decorators import needs_read_lock, needs_write_lock
74
 
from bzrlib.i18n import gettext
75
75
from bzrlib.lock import LogicalLockResult
76
76
import bzrlib.mutabletree
77
77
from bzrlib.mutabletree import needs_tree_write_lock
172
172
 
173
173
    def __init__(self, basedir='.',
174
174
                 branch=DEPRECATED_PARAMETER,
 
175
                 _control_files=None,
175
176
                 _internal=False,
176
 
                 _transport=None,
177
177
                 _format=None,
178
178
                 _bzrdir=None):
179
179
        """Construct a WorkingTree instance. This is not a public API.
192
192
        else:
193
193
            self._branch = self.bzrdir.open_branch()
194
194
        self.basedir = realpath(basedir)
195
 
        self._transport = _transport
 
195
        self._control_files = _control_files
 
196
        self._transport = self._control_files._transport
 
197
        # update the whole cache up front and write to disk if anything changed;
 
198
        # in the future we might want to do this more selectively
 
199
        # two possible ways offer themselves : in self._unlock, write the cache
 
200
        # if needed, or, when the cache sees a change, append it to the hash
 
201
        # cache file, and have the parser take the most recent entry for a
 
202
        # given path only.
 
203
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
204
        cache_filename = wt_trans.local_abspath('stat-cache')
 
205
        self._hashcache = hashcache.HashCache(basedir, cache_filename,
 
206
            self.bzrdir._get_file_mode(),
 
207
            self._content_filter_stack_provider())
 
208
        hc = self._hashcache
 
209
        hc.read()
 
210
        # is this scan needed ? it makes things kinda slow.
 
211
        #hc.scan()
 
212
 
 
213
        if hc.needs_write:
 
214
            mutter("write hc")
 
215
            hc.write()
 
216
 
 
217
        self._detect_case_handling()
196
218
        self._rules_searcher = None
197
219
        self.views = self._make_views()
198
220
 
216
238
        """
217
239
        return self.bzrdir.is_control_filename(filename)
218
240
 
 
241
    def _detect_case_handling(self):
 
242
        wt_trans = self.bzrdir.get_workingtree_transport(None)
 
243
        try:
 
244
            wt_trans.stat(self._format.case_sensitive_filename)
 
245
        except errors.NoSuchFile:
 
246
            self.case_sensitive = True
 
247
        else:
 
248
            self.case_sensitive = False
 
249
 
 
250
        self._setup_directory_is_tree_reference()
 
251
 
219
252
    branch = property(
220
253
        fget=lambda self: self._branch,
221
254
        doc="""The branch this WorkingTree is connected to.
224
257
            the working tree has been constructed from.
225
258
            """)
226
259
 
227
 
    def has_versioned_directories(self):
228
 
        """See `Tree.has_versioned_directories`."""
229
 
        return self._format.supports_versioned_directories
230
 
 
231
260
    def break_lock(self):
232
261
        """Break a lock if one is present from another instance.
233
262
 
236
265
 
237
266
        This will probe the repository for its lock as well.
238
267
        """
239
 
        raise NotImplementedError(self.break_lock)
 
268
        self._control_files.break_lock()
 
269
        self.branch.break_lock()
240
270
 
241
271
    def requires_rich_root(self):
242
272
        return self._format.requires_rich_root
257
287
        """
258
288
        if path is None:
259
289
            path = osutils.getcwd()
260
 
        control = controldir.ControlDir.open(path, _unsupported)
 
290
        control = bzrdir.BzrDir.open(path, _unsupported)
261
291
        return control.open_workingtree(_unsupported)
262
292
 
263
293
    @staticmethod
275
305
        """
276
306
        if path is None:
277
307
            path = osutils.getcwd()
278
 
        control, relpath = controldir.ControlDir.open_containing(path)
 
308
        control, relpath = bzrdir.BzrDir.open_containing(path)
279
309
        return control.open_workingtree(), relpath
280
310
 
281
311
    @staticmethod
301
331
                if view_files:
302
332
                    file_list = view_files
303
333
                    view_str = views.view_display_str(view_files)
304
 
                    note(gettext("Ignoring files outside view. View is %s") % view_str)
 
334
                    note("Ignoring files outside view. View is %s" % view_str)
305
335
            return tree, file_list
306
336
        if default_directory == u'.':
307
337
            seed = file_list[0]
364
394
            else:
365
395
                return True, tree
366
396
        t = transport.get_transport(location)
367
 
        iterator = controldir.ControlDir.find_bzrdirs(t, evaluate=evaluate,
 
397
        iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
368
398
                                              list_current=list_current)
369
399
        return [tr for tr in iterator if tr is not None]
370
400
 
466
496
        finally:
467
497
            file.close()
468
498
 
 
499
    def _get_ancestors(self, default_revision):
 
500
        ancestors = set([default_revision])
 
501
        for parent_id in self.get_parent_ids():
 
502
            ancestors.update(self.branch.repository.get_ancestry(
 
503
                             parent_id, topo_sorted=False))
 
504
        return ancestors
 
505
 
469
506
    def get_parent_ids(self):
470
507
        """See Tree.get_parent_ids.
471
508
 
492
529
        raise NotImplementedError(self.get_root_id)
493
530
 
494
531
    @needs_read_lock
495
 
    def clone(self, to_controldir, revision_id=None):
 
532
    def clone(self, to_bzrdir, revision_id=None):
496
533
        """Duplicate this working tree into to_bzr, including all state.
497
534
 
498
535
        Specifically modified files are kept as modified, but
499
536
        ignored and unknown files are discarded.
500
537
 
501
 
        If you want to make a new line of development, see ControlDir.sprout()
 
538
        If you want to make a new line of development, see bzrdir.sprout()
502
539
 
503
540
        revision
504
541
            If not None, the cloned tree will have its last revision set to
506
543
            and this one merged in.
507
544
        """
508
545
        # assumes the target bzr dir format is compatible.
509
 
        result = to_controldir.create_workingtree()
 
546
        result = to_bzrdir.create_workingtree()
510
547
        self.copy_content_into(result, revision_id)
511
548
        return result
512
549
 
520
557
            # TODO now merge from tree.last_revision to revision (to preserve
521
558
            # user local changes)
522
559
            merge.transform_tree(tree, self)
523
 
            if revision_id == _mod_revision.NULL_REVISION:
524
 
                new_parents = []
525
 
            else:
526
 
                new_parents = [revision_id]
527
 
            tree.set_parent_ids(new_parents)
 
560
            tree.set_parent_ids([revision_id])
528
561
 
529
562
    def id2abspath(self, file_id):
530
563
        return self.abspath(self.id2path(file_id))
569
602
            else:
570
603
                return None
571
604
 
 
605
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
606
        # FIXME: Shouldn't this be in Tree?
 
607
        raise NotImplementedError(self.get_file_sha1)
 
608
 
572
609
    @needs_tree_write_lock
573
610
    def _gather_kinds(self, files, kinds):
574
611
        """See MutableTree._gather_kinds."""
739
776
 
740
777
    @needs_tree_write_lock
741
778
    def set_merge_modified(self, modified_hashes):
742
 
        """Set the merge modified hashes."""
743
 
        raise NotImplementedError(self.set_merge_modified)
 
779
        def iter_stanzas():
 
780
            for file_id, hash in modified_hashes.iteritems():
 
781
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
 
782
                    hash=hash)
 
783
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
744
784
 
745
785
    def _sha_from_stat(self, path, stat_result):
746
786
        """Get a sha digest from the tree's stat cache.
752
792
        """
753
793
        return None
754
794
 
 
795
    def _put_rio(self, filename, stanzas, header):
 
796
        self._must_be_locked()
 
797
        my_file = _mod_rio.rio_file(stanzas, header)
 
798
        self._transport.put_file(filename, my_file,
 
799
            mode=self.bzrdir._get_file_mode())
 
800
 
755
801
    @needs_write_lock # because merge pulls data into the branch.
756
802
    def merge_from_branch(self, branch, to_revision=None, from_revision=None,
757
803
                          merge_type=None, force=False):
997
1043
                                show_base=show_base)
998
1044
                    basis_root_id = basis_tree.get_root_id()
999
1045
                    new_root_id = new_basis_tree.get_root_id()
1000
 
                    if new_root_id is not None and basis_root_id != new_root_id:
 
1046
                    if basis_root_id != new_root_id:
1001
1047
                        self.set_root_id(new_root_id)
1002
1048
                finally:
1003
1049
                    basis_tree.unlock()
1004
1050
                # TODO - dedup parents list with things merged by pull ?
1005
1051
                # reuse the revisiontree we merged against to set the new
1006
1052
                # tree data.
1007
 
                parent_trees = []
1008
 
                if self.branch.last_revision() != _mod_revision.NULL_REVISION:
1009
 
                    parent_trees.append(
1010
 
                        (self.branch.last_revision(), new_basis_tree))
 
1053
                parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1011
1054
                # we have to pull the merge trees out again, because
1012
1055
                # merge_inner has set the ids. - this corner is not yet
1013
1056
                # layered well enough to prevent double handling.
1030
1073
            stream.write(bytes)
1031
1074
        finally:
1032
1075
            stream.close()
 
1076
        # TODO: update the hashcache here ?
1033
1077
 
1034
1078
    def extras(self):
1035
1079
        """Yield all unversioned files in this WorkingTree.
1137
1181
        return _mod_revision.ensure_null(self.branch.last_revision())
1138
1182
 
1139
1183
    def is_locked(self):
1140
 
        """Check if this tree is locked."""
1141
 
        raise NotImplementedError(self.is_locked)
 
1184
        return self._control_files.is_locked()
 
1185
 
 
1186
    def _must_be_locked(self):
 
1187
        if not self.is_locked():
 
1188
            raise errors.ObjectNotLocked(self)
1142
1189
 
1143
1190
    def lock_read(self):
1144
1191
        """Lock the tree for reading.
1147
1194
 
1148
1195
        :return: A bzrlib.lock.LogicalLockResult.
1149
1196
        """
1150
 
        raise NotImplementedError(self.lock_read)
 
1197
        if not self.is_locked():
 
1198
            self._reset_data()
 
1199
        self.branch.lock_read()
 
1200
        try:
 
1201
            self._control_files.lock_read()
 
1202
            return LogicalLockResult(self.unlock)
 
1203
        except:
 
1204
            self.branch.unlock()
 
1205
            raise
1151
1206
 
1152
1207
    def lock_tree_write(self):
1153
1208
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1154
1209
 
1155
1210
        :return: A bzrlib.lock.LogicalLockResult.
1156
1211
        """
1157
 
        raise NotImplementedError(self.lock_tree_write)
 
1212
        if not self.is_locked():
 
1213
            self._reset_data()
 
1214
        self.branch.lock_read()
 
1215
        try:
 
1216
            self._control_files.lock_write()
 
1217
            return LogicalLockResult(self.unlock)
 
1218
        except:
 
1219
            self.branch.unlock()
 
1220
            raise
1158
1221
 
1159
1222
    def lock_write(self):
1160
1223
        """See MutableTree.lock_write, and WorkingTree.unlock.
1161
1224
 
1162
1225
        :return: A bzrlib.lock.LogicalLockResult.
1163
1226
        """
1164
 
        raise NotImplementedError(self.lock_write)
 
1227
        if not self.is_locked():
 
1228
            self._reset_data()
 
1229
        self.branch.lock_write()
 
1230
        try:
 
1231
            self._control_files.lock_write()
 
1232
            return LogicalLockResult(self.unlock)
 
1233
        except:
 
1234
            self.branch.unlock()
 
1235
            raise
1165
1236
 
1166
1237
    def get_physical_lock_status(self):
1167
 
        raise NotImplementedError(self.get_physical_lock_status)
 
1238
        return self._control_files.get_physical_lock_status()
 
1239
 
 
1240
    def _reset_data(self):
 
1241
        """Reset transient data that cannot be revalidated."""
 
1242
        raise NotImplementedError(self._reset_data)
1168
1243
 
1169
1244
    def set_last_revision(self, new_revision):
1170
1245
        """Change the last revision in the working tree."""
1464
1539
                                             show_base=show_base)
1465
1540
            if nb_conflicts:
1466
1541
                self.add_parent_tree((old_tip, other_tree))
1467
 
                note(gettext('Rerun update after fixing the conflicts.'))
 
1542
                note('Rerun update after fixing the conflicts.')
1468
1543
                return nb_conflicts
1469
1544
 
1470
1545
        if last_rev != _mod_revision.ensure_null(revision):
1512
1587
            last_rev = parent_trees[0][0]
1513
1588
        return nb_conflicts
1514
1589
 
 
1590
    def _write_hashcache_if_dirty(self):
 
1591
        """Write out the hashcache if it is dirty."""
 
1592
        if self._hashcache.needs_write:
 
1593
            try:
 
1594
                self._hashcache.write()
 
1595
            except OSError, e:
 
1596
                if e.errno not in (errno.EPERM, errno.EACCES):
 
1597
                    raise
 
1598
                # TODO: jam 20061219 Should this be a warning? A single line
 
1599
                #       warning might be sufficient to let the user know what
 
1600
                #       is going on.
 
1601
                mutter('Could not write hashcache for %s\nError: %s',
 
1602
                              self._hashcache.cache_file_name(), e)
 
1603
 
1515
1604
    def set_conflicts(self, arg):
1516
1605
        raise errors.UnsupportedOperation(self.set_conflicts, self)
1517
1606
 
1746
1835
        :param branch: A branch to override probing for the branch.
1747
1836
        """
1748
1837
        super(InventoryWorkingTree, self).__init__(basedir=basedir,
1749
 
            branch=branch, _transport=_control_files._transport,
1750
 
            _internal=_internal, _format=_format, _bzrdir=_bzrdir)
1751
 
 
1752
 
        self._control_files = _control_files
1753
 
        self._detect_case_handling()
 
1838
            branch=branch, _control_files=_control_files, _internal=_internal,
 
1839
            _format=_format, _bzrdir=_bzrdir)
1754
1840
 
1755
1841
        if _inventory is None:
1756
1842
            # This will be acquired on lock_read() or lock_write()
1776
1862
        self._inventory = inv
1777
1863
        self._inventory_is_modified = dirty
1778
1864
 
1779
 
    def _detect_case_handling(self):
1780
 
        wt_trans = self.bzrdir.get_workingtree_transport(None)
1781
 
        try:
1782
 
            wt_trans.stat(self._format.case_sensitive_filename)
1783
 
        except errors.NoSuchFile:
1784
 
            self.case_sensitive = True
1785
 
        else:
1786
 
            self.case_sensitive = False
1787
 
 
1788
 
        self._setup_directory_is_tree_reference()
1789
 
 
1790
1865
    def _serialize(self, inventory, out_file):
1791
1866
        xml5.serializer_v5.write_inventory(self._inventory, out_file,
1792
1867
            working=True)
1794
1869
    def _deserialize(selt, in_file):
1795
1870
        return xml5.serializer_v5.read_inventory(in_file)
1796
1871
 
1797
 
    def break_lock(self):
1798
 
        """Break a lock if one is present from another instance.
1799
 
 
1800
 
        Uses the ui factory to ask for confirmation if the lock may be from
1801
 
        an active process.
1802
 
 
1803
 
        This will probe the repository for its lock as well.
1804
 
        """
1805
 
        self._control_files.break_lock()
1806
 
        self.branch.break_lock()
1807
 
 
1808
 
    def is_locked(self):
1809
 
        return self._control_files.is_locked()
1810
 
 
1811
 
    def _must_be_locked(self):
1812
 
        if not self.is_locked():
1813
 
            raise errors.ObjectNotLocked(self)
1814
 
 
1815
 
    def lock_read(self):
1816
 
        """Lock the tree for reading.
1817
 
 
1818
 
        This also locks the branch, and can be unlocked via self.unlock().
1819
 
 
1820
 
        :return: A bzrlib.lock.LogicalLockResult.
1821
 
        """
1822
 
        if not self.is_locked():
1823
 
            self._reset_data()
1824
 
        self.branch.lock_read()
1825
 
        try:
1826
 
            self._control_files.lock_read()
1827
 
            return LogicalLockResult(self.unlock)
1828
 
        except:
1829
 
            self.branch.unlock()
1830
 
            raise
1831
 
 
1832
 
    def lock_tree_write(self):
1833
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
1834
 
 
1835
 
        :return: A bzrlib.lock.LogicalLockResult.
1836
 
        """
1837
 
        if not self.is_locked():
1838
 
            self._reset_data()
1839
 
        self.branch.lock_read()
1840
 
        try:
1841
 
            self._control_files.lock_write()
1842
 
            return LogicalLockResult(self.unlock)
1843
 
        except:
1844
 
            self.branch.unlock()
1845
 
            raise
1846
 
 
1847
 
    def lock_write(self):
1848
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
1849
 
 
1850
 
        :return: A bzrlib.lock.LogicalLockResult.
1851
 
        """
1852
 
        if not self.is_locked():
1853
 
            self._reset_data()
1854
 
        self.branch.lock_write()
1855
 
        try:
1856
 
            self._control_files.lock_write()
1857
 
            return LogicalLockResult(self.unlock)
1858
 
        except:
1859
 
            self.branch.unlock()
1860
 
            raise
1861
 
 
1862
 
    def get_physical_lock_status(self):
1863
 
        return self._control_files.get_physical_lock_status()
1864
 
 
1865
1872
    @needs_tree_write_lock
1866
1873
    def _write_inventory(self, inv):
1867
1874
        """Write inventory as the current inventory."""
2077
2084
            return True
2078
2085
        return self.inventory.has_id(file_id)
2079
2086
 
 
2087
    __contains__ = has_id
 
2088
 
2080
2089
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2081
2090
    def __iter__(self):
2082
2091
        """Iterate through file_ids for this tree.
2164
2173
            mode=self.bzrdir._get_file_mode())
2165
2174
        self._inventory_is_modified = False
2166
2175
 
 
2176
    @needs_read_lock
 
2177
    def get_file_sha1(self, file_id, path=None, stat_value=None):
 
2178
        if not path:
 
2179
            path = self._inventory.id2path(file_id)
 
2180
        return self._hashcache.get_sha1(path, stat_value)
 
2181
 
2167
2182
    def get_file_mtime(self, file_id, path=None):
2168
2183
        """See Tree.get_file_mtime."""
2169
2184
        if not path:
2170
2185
            path = self.inventory.id2path(file_id)
2171
 
        try:
2172
 
            return os.lstat(self.abspath(path)).st_mtime
2173
 
        except OSError, e:
2174
 
            if e.errno == errno.ENOENT:
2175
 
                raise errors.FileTimestampUnavailable(path)
2176
 
            raise
 
2186
        return os.lstat(self.abspath(path)).st_mtime
2177
2187
 
2178
2188
    def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
2179
2189
        file_id = self.path2id(path)
2257
2267
                parent_tree = self.branch.repository.revision_tree(parent_id)
2258
2268
            parent_tree.lock_read()
2259
2269
            try:
2260
 
                if not parent_tree.has_id(file_id):
 
2270
                if file_id not in parent_tree:
2261
2271
                    continue
2262
2272
                ie = parent_tree.inventory[file_id]
2263
2273
                if ie.kind != 'file':
2286
2296
                       for key, line in annotator.annotate_flat(this_key)]
2287
2297
        return annotations
2288
2298
 
2289
 
    def _put_rio(self, filename, stanzas, header):
2290
 
        self._must_be_locked()
2291
 
        my_file = _mod_rio.rio_file(stanzas, header)
2292
 
        self._transport.put_file(filename, my_file,
2293
 
            mode=self.bzrdir._get_file_mode())
2294
 
 
2295
 
    @needs_tree_write_lock
2296
 
    def set_merge_modified(self, modified_hashes):
2297
 
        def iter_stanzas():
2298
 
            for file_id, hash in modified_hashes.iteritems():
2299
 
                yield _mod_rio.Stanza(file_id=file_id.decode('utf8'),
2300
 
                    hash=hash)
2301
 
        self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
2302
 
 
2303
2299
    @needs_read_lock
2304
2300
    def merge_modified(self):
2305
2301
        """Return a dictionary of files modified by a merge.
2325
2321
            for s in _mod_rio.RioReader(hashfile):
2326
2322
                # RioReader reads in Unicode, so convert file_ids back to utf8
2327
2323
                file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
2328
 
                if not self.inventory.has_id(file_id):
 
2324
                if file_id not in self.inventory:
2329
2325
                    continue
2330
2326
                text_hash = s.get("hash")
2331
2327
                if text_hash == self.get_file_sha1(file_id):
2866
2862
        :raises: NoSuchId if any fileid is not currently versioned.
2867
2863
        """
2868
2864
        for file_id in file_ids:
2869
 
            if not self._inventory.has_id(file_id):
 
2865
            if file_id not in self._inventory:
2870
2866
                raise errors.NoSuchId(self, file_id)
2871
2867
        for file_id in file_ids:
2872
2868
            if self._inventory.has_id(file_id):
3027
3023
    missing_parent_conflicts = False
3028
3024
    """If this format supports missing parent conflicts."""
3029
3025
 
3030
 
    supports_versioned_directories = None
3031
 
 
3032
3026
    @classmethod
3033
 
    def find_format_string(klass, controldir):
3034
 
        """Return format name for the working tree object in controldir."""
 
3027
    def find_format_string(klass, a_bzrdir):
 
3028
        """Return format name for the working tree object in a_bzrdir."""
3035
3029
        try:
3036
 
            transport = controldir.get_workingtree_transport(None)
 
3030
            transport = a_bzrdir.get_workingtree_transport(None)
3037
3031
            return transport.get_bytes("format")
3038
3032
        except errors.NoSuchFile:
3039
3033
            raise errors.NoWorkingTree(base=transport.base)
3040
3034
 
3041
3035
    @classmethod
3042
 
    def find_format(klass, controldir):
3043
 
        """Return the format for the working tree object in controldir."""
 
3036
    def find_format(klass, a_bzrdir):
 
3037
        """Return the format for the working tree object in a_bzrdir."""
3044
3038
        try:
3045
 
            format_string = klass.find_format_string(controldir)
 
3039
            format_string = klass.find_format_string(a_bzrdir)
3046
3040
            return format_registry.get(format_string)
3047
3041
        except KeyError:
3048
3042
            raise errors.UnknownFormatError(format=format_string,
3049
3043
                                            kind="working tree")
3050
3044
 
3051
 
    def initialize(self, controldir, revision_id=None, from_branch=None,
 
3045
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3052
3046
                   accelerator_tree=None, hardlink=False):
3053
 
        """Initialize a new working tree in controldir.
 
3047
        """Initialize a new working tree in a_bzrdir.
3054
3048
 
3055
 
        :param controldir: ControlDir to initialize the working tree in.
 
3049
        :param a_bzrdir: BzrDir to initialize the working tree in.
3056
3050
        :param revision_id: allows creating a working tree at a different
3057
3051
            revision than the branch is at.
3058
3052
        :param from_branch: Branch to checkout
3139
3133
    def unregister_format(klass, format):
3140
3134
        format_registry.remove(format)
3141
3135
 
3142
 
    def get_controldir_for_branch(self):
3143
 
        """Get the control directory format for creating branches.
3144
 
 
3145
 
        This is to support testing of working tree formats that can not exist
3146
 
        in the same control directory as a branch.
3147
 
        """
3148
 
        return self._matchingbzrdir
3149
 
 
3150
3136
 
3151
3137
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
3152
3138
    "bzrlib.workingtree_4", "WorkingTreeFormat4")