1
# Copyright (C) 2007-2011 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
29
29
from bzrlib.lazy_import import lazy_import
30
30
lazy_import(globals(), """
31
from bisect import bisect_left
33
from copy import deepcopy
34
42
from bzrlib import (
38
45
conflicts as _mod_conflicts,
42
filters as _mod_filters,
45
55
revision as _mod_revision,
66
from bzrlib.transport import get_transport
70
from bzrlib import symbol_versioning
53
71
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
55
from bzrlib.lock import LogicalLockResult
56
from bzrlib.lockable_files import LockableFiles
57
from bzrlib.lockdir import LockDir
72
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
73
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, entry_factory
74
import bzrlib.mutabletree
58
75
from bzrlib.mutabletree import needs_tree_write_lock
59
76
from bzrlib.osutils import (
86
from bzrlib.trace import mutter, note
66
87
from bzrlib.transport.local import LocalTransport
67
from bzrlib.tree import (
71
from bzrlib.workingtree import (
78
class DirStateWorkingTree(InventoryWorkingTree):
88
from bzrlib.tree import InterTree
89
from bzrlib.progress import DummyProgress, ProgressPhase
90
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
91
from bzrlib.rio import RioReader, rio_file, Stanza
92
from bzrlib.symbol_versioning import (deprecated_passed,
97
from bzrlib.tree import Tree
98
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
101
class DirStateWorkingTree(WorkingTree3):
80
102
def __init__(self, basedir,
82
104
_control_files=None,
92
114
self._format = _format
93
115
self.bzrdir = _bzrdir
94
116
basedir = safe_unicode(basedir)
95
trace.mutter("opening working tree %r", basedir)
117
mutter("opening working tree %r", basedir)
96
118
self._branch = branch
97
119
self.basedir = realpath(basedir)
98
120
# if branch is at our basedir and is a format 6 or less
132
154
state.add(f, file_id, kind, None, '')
133
155
self._make_dirty(reset_inventory=True)
135
def _get_check_refs(self):
136
"""Return the references needed to perform a check of this tree."""
137
return [('trees', self.last_revision())]
139
157
def _make_dirty(self, reset_inventory):
140
158
"""Make the tree state dirty.
194
212
def _comparison_data(self, entry, path):
195
213
kind, executable, stat_value = \
196
WorkingTree._comparison_data(self, entry, path)
214
WorkingTree3._comparison_data(self, entry, path)
197
215
# it looks like a plain directory, but it's really a reference -- see
199
217
if (self._repo_supports_tree_reference and kind == 'directory'
205
223
def commit(self, message=None, revprops=None, *args, **kwargs):
206
224
# mark the tree as dirty post commit - commit
207
225
# can change the current versioned list by doing deletes.
208
result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
226
result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
209
227
self._make_dirty(reset_inventory=True)
230
248
local_path = self.bzrdir.get_workingtree_transport(None
231
249
).local_abspath('dirstate')
232
250
self._dirstate = dirstate.DirState.on_file(local_path,
233
self._sha1_provider(), self._worth_saving_limit())
251
self._sha1_provider())
234
252
return self._dirstate
236
254
def _sha1_provider(self):
248
def _worth_saving_limit(self):
249
"""How many hash changes are ok before we must save the dirstate.
251
:return: an integer. -1 means never save.
253
# FIXME: We want a WorkingTreeStack here -- vila 20110812
254
conf = config.BranchStack(self.branch)
255
return conf.get('bzr.workingtree.worth_saving_limit')
257
266
def filter_unversioned_files(self, paths):
258
267
"""Filter out paths that are versioned.
455
464
return osutils.lexists(pathjoin(
456
465
self.basedir, row[0].decode('utf8'), row[1].decode('utf8')))
458
def has_or_had_id(self, file_id):
459
state = self.current_dirstate()
460
row, parents = self._get_entry(file_id=file_id)
461
return row is not None
464
468
def id2path(self, file_id):
465
469
"Convert a file-id to a path."
588
592
return _mod_revision.NULL_REVISION
590
594
def lock_read(self):
591
"""See Branch.lock_read, and WorkingTree.unlock.
593
:return: A bzrlib.lock.LogicalLockResult.
595
"""See Branch.lock_read, and WorkingTree.unlock."""
595
596
self.branch.lock_read()
597
598
self._control_files.lock_read()
632
632
self.branch.unlock()
634
return LogicalLockResult(self.unlock)
636
635
def lock_tree_write(self):
637
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
639
:return: A bzrlib.lock.LogicalLockResult.
636
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
641
637
self.branch.lock_read()
642
return self._lock_self_write()
638
self._lock_self_write()
644
640
def lock_write(self):
645
"""See MutableTree.lock_write, and WorkingTree.unlock.
647
:return: A bzrlib.lock.LogicalLockResult.
641
"""See MutableTree.lock_write, and WorkingTree.unlock."""
649
642
self.branch.lock_write()
650
return self._lock_self_write()
643
self._lock_self_write()
652
645
@needs_tree_write_lock
653
646
def move(self, from_paths, to_dir, after=False):
723
716
from_entry = self._get_entry(path=from_rel)
724
717
if from_entry == (None, None):
725
718
raise errors.BzrMoveFailedError(from_rel,to_dir,
726
errors.NotVersionedError(path=from_rel))
719
errors.NotVersionedError(path=str(from_rel)))
728
721
from_id = from_entry[0][2]
729
722
to_rel = pathjoin(to_dir, from_tail)
1058
1051
def set_last_revision(self, new_revision):
1059
1052
"""Change the last revision in the working tree."""
1060
1053
parents = self.get_parent_ids()
1061
if new_revision in (_mod_revision.NULL_REVISION, None):
1054
if new_revision in (NULL_REVISION, None):
1062
1055
if len(parents) >= 2:
1063
1056
raise AssertionError(
1064
1057
"setting the last parent to none with a pending merge is "
1133
1126
_mod_revision.NULL_REVISION)))
1134
1127
ghosts.append(rev_id)
1135
1128
accepted_revisions.add(rev_id)
1137
if (len(real_trees) == 1
1139
and self.branch.repository._format.fast_deltas
1140
and isinstance(real_trees[0][1],
1141
revisiontree.InventoryRevisionTree)
1142
and self.get_parent_ids()):
1143
rev_id, rev_tree = real_trees[0]
1144
basis_id = self.get_parent_ids()[0]
1145
# There are times when basis_tree won't be in
1146
# self.branch.repository, (switch, for example)
1148
basis_tree = self.branch.repository.revision_tree(basis_id)
1149
except errors.NoSuchRevision:
1150
# Fall back to the set_parent_trees(), since we can't use
1151
# _make_delta if we can't get the RevisionTree
1154
delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1155
dirstate.update_basis_by_delta(delta, rev_id)
1158
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1129
dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1159
1130
self._make_dirty(reset_inventory=False)
1161
1132
def _set_root_id(self, file_id):
1182
1153
def unlock(self):
1183
1154
"""Unlock in format 4 trees needs to write the entire dirstate."""
1155
# do non-implementation specific cleanup
1184
1158
if self._control_files._lock_count == 1:
1185
# do non-implementation specific cleanup
1188
1159
# eventually we should do signature checking during read locks for
1189
1160
# dirstate updates.
1190
1161
if self._control_files._lock_mode == 'w':
1253
1224
# just forget the whole block.
1254
1225
entry_index = 0
1255
1226
while entry_index < len(block[1]):
1227
# Mark this file id as having been removed
1256
1228
entry = block[1][entry_index]
1257
if entry[1][0][0] in 'ar':
1258
# don't remove absent or renamed entries
1229
ids_to_unversion.discard(entry[0][2])
1230
if (entry[1][0][0] in 'ar' # don't remove absent or renamed
1232
or not state._make_absent(entry)):
1259
1233
entry_index += 1
1261
# Mark this file id as having been removed
1262
ids_to_unversion.discard(entry[0][2])
1263
if not state._make_absent(entry):
1264
# The block has not shrunk.
1266
1234
# go to the next block. (At the moment we dont delete empty
1268
1236
block_index += 1
1289
1257
# have to change the legacy inventory too.
1290
1258
if self._inventory is not None:
1291
1259
for file_id in file_ids:
1292
if self._inventory.has_id(file_id):
1293
self._inventory.remove_recursive_id(file_id)
1260
self._inventory.remove_recursive_id(file_id)
1295
1262
@needs_tree_write_lock
1296
1263
def rename_one(self, from_rel, to_rel, after=False):
1297
1264
"""See WorkingTree.rename_one"""
1299
super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1266
WorkingTree.rename_one(self, from_rel, to_rel, after)
1301
1268
@needs_tree_write_lock
1302
1269
def apply_inventory_delta(self, changes):
1321
1288
if self._dirty:
1322
1289
raise AssertionError("attempting to write an inventory when the "
1323
1290
"dirstate is dirty will lose pending changes")
1324
had_inventory = self._inventory is not None
1325
# Setting self._inventory = None forces the dirstate to regenerate the
1326
# working inventory. We do this because self.inventory may be inv, or
1327
# may have been modified, and either case would prevent a clean delta
1329
self._inventory = None
1331
delta = inv._make_delta(self.inventory)
1333
self.apply_inventory_delta(delta)
1291
self.current_dirstate().set_state_from_inventory(inv)
1292
self._make_dirty(reset_inventory=False)
1293
if self._inventory is not None:
1335
1294
self._inventory = inv
1338
@needs_tree_write_lock
1339
def reset_state(self, revision_ids=None):
1340
"""Reset the state of the working tree.
1342
This does a hard-reset to a last-known-good state. This is a way to
1343
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1345
if revision_ids is None:
1346
revision_ids = self.get_parent_ids()
1347
if not revision_ids:
1348
base_tree = self.branch.repository.revision_tree(
1349
_mod_revision.NULL_REVISION)
1352
trees = zip(revision_ids,
1353
self.branch.repository.revision_trees(revision_ids))
1354
base_tree = trees[0][1]
1355
state = self.current_dirstate()
1356
# We don't support ghosts yet
1357
state.set_state_from_scratch(base_tree.inventory, trees, [])
1360
1298
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1366
1304
"""See dirstate.SHA1Provider.sha1()."""
1367
1305
filters = self.tree._content_filter_stack(
1368
1306
self.tree.relpath(osutils.safe_unicode(abspath)))
1369
return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1307
return internal_size_sha_file_byname(abspath, filters)[1]
1371
1309
def stat_and_sha1(self, abspath):
1372
1310
"""See dirstate.SHA1Provider.stat_and_sha1()."""
1377
1315
statvalue = os.fstat(file_obj.fileno())
1379
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1317
file_obj = filtered_input_file(file_obj, filters)
1380
1318
sha1 = osutils.size_sha_file(file_obj)[1]
1382
1320
file_obj.close()
1383
1321
return statvalue, sha1
1386
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1387
"""Dirstate working tree that supports content filtering.
1389
The dirstate holds the hash and size of the canonical form of the file,
1390
and most methods must return that.
1393
def _file_content_summary(self, path, stat_result):
1394
# This is to support the somewhat obsolete path_content_summary method
1395
# with content filtering: see
1396
# <https://bugs.launchpad.net/bzr/+bug/415508>.
1398
# If the dirstate cache is up to date and knows the hash and size,
1400
# Otherwise if there are no content filters, return the on-disk size
1401
# and leave the hash blank.
1402
# Otherwise, read and filter the on-disk file and use its size and
1405
# The dirstate doesn't store the size of the canonical form so we
1406
# can't trust it for content-filtered trees. We just return None.
1407
dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1408
executable = self._is_executable_from_path_and_stat(path, stat_result)
1409
return ('file', None, executable, dirstate_sha1)
1412
1324
class WorkingTree4(DirStateWorkingTree):
1413
1325
"""This is the Format 4 working tree.
1415
This differs from WorkingTree by:
1327
This differs from WorkingTree3 by:
1416
1328
- Having a consolidated internal dirstate, stored in a
1417
1329
randomly-accessible sorted file on disk.
1418
1330
- Not having a regular inventory attribute. One can be synthesized
1446
1358
return views.PathBasedViews(self)
1449
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1451
missing_parent_conflicts = True
1453
supports_versioned_directories = True
1455
_lock_class = LockDir
1456
_lock_file_name = 'lock'
1458
def _open_control_files(self, a_bzrdir):
1459
transport = a_bzrdir.get_workingtree_transport(None)
1460
return LockableFiles(transport, self._lock_file_name,
1361
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1463
1362
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1464
1363
accelerator_tree=None, hardlink=False):
1465
1364
"""See WorkingTreeFormat.initialize().
1467
1366
:param revision_id: allows creating a working tree at a different
1468
revision than the branch is at.
1367
revision than the branch is at.
1469
1368
:param accelerator_tree: A tree which can be used for retrieving file
1470
1369
contents more quickly than the revision tree, i.e. a workingtree.
1471
1370
The revision tree will be used for cases where accelerator_tree's
1504
1403
wt.lock_tree_write()
1506
1405
self._init_custom_control_files(wt)
1507
if revision_id in (None, _mod_revision.NULL_REVISION):
1406
if revision_id in (None, NULL_REVISION):
1508
1407
if branch.repository.supports_rich_root():
1509
1408
wt._set_root_id(generate_ids.gen_root_id())
1535
1434
if basis_root_id is not None:
1536
1435
wt._set_root_id(basis_root_id)
1437
# If content filtering is supported, do not use the accelerator
1438
# tree - the cost of transforming the content both ways and
1439
# checking for changed content can outweight the gains it gives.
1440
# Note: do NOT move this logic up higher - using the basis from
1441
# the accelerator tree is still desirable because that can save
1442
# a minute or more of processing on large trees!
1538
1443
if wt.supports_content_filtering():
1539
# The original tree may not have the same content filters
1540
# applied so we can't safely build the inventory delta from
1542
delta_from_tree = False
1544
delta_from_tree = True
1444
accelerator_tree = None
1545
1445
# delta_from_tree is safe even for DirStateRevisionTrees,
1546
1446
# because wt4.apply_inventory_delta does not mutate the input
1547
1447
# inventory entries.
1548
1448
transform.build_tree(basis, wt, accelerator_tree,
1550
delta_from_tree=delta_from_tree)
1449
hardlink=hardlink, delta_from_tree=True)
1564
1463
:param wt: the WorkingTree object
1567
def open(self, a_bzrdir, _found=False):
1568
"""Return the WorkingTree object for a_bzrdir
1570
_found is a private parameter, do not use it. It is used to indicate
1571
if format probing has already been done.
1574
# we are being called directly and must probe.
1575
raise NotImplementedError
1576
if not isinstance(a_bzrdir.transport, LocalTransport):
1577
raise errors.NotLocalUrl(a_bzrdir.transport.base)
1578
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1581
1466
def _open(self, a_bzrdir, control_files):
1582
1467
"""Open the tree itself.
1677
class DirStateRevisionTree(InventoryTree):
1678
"""A revision tree pulling the inventory from a dirstate.
1680
Note that this is one of the historical (ie revision) trees cached in the
1681
dirstate for easy access, not the workingtree.
1562
class DirStateRevisionTree(Tree):
1563
"""A revision tree pulling the inventory from a dirstate."""
1684
1565
def __init__(self, dirstate, revision_id, repository):
1685
1566
self._dirstate = dirstate
1699
1580
def annotate_iter(self, file_id,
1700
1581
default_revision=_mod_revision.CURRENT_REVISION):
1701
1582
"""See Tree.annotate_iter"""
1702
text_key = (file_id, self.get_file_revision(file_id))
1583
text_key = (file_id, self.inventory[file_id].revision)
1703
1584
annotations = self._repository.texts.annotate(text_key)
1704
1585
return [(key[-1], line) for (key, line) in annotations]
1587
def _get_ancestors(self, default_revision):
1588
return set(self._repository.get_ancestry(self._revision_id,
1706
1590
def _comparison_data(self, entry, path):
1707
1591
"""See Tree._comparison_data."""
1708
1592
if entry is None:
1824
1708
elif kind == 'directory':
1825
1709
parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1826
1710
elif kind == 'symlink':
1711
inv_entry.executable = False
1712
inv_entry.text_size = None
1827
1713
inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1828
1714
elif kind == 'tree-reference':
1829
1715
inv_entry.reference_revision = fingerprint or None
1853
1739
parent_index = self._get_parent_index()
1854
1740
last_changed_revision = entry[1][parent_index][4]
1856
rev = self._repository.get_revision(last_changed_revision)
1857
except errors.NoSuchRevision:
1858
raise errors.FileTimestampUnavailable(self.id2path(file_id))
1859
return rev.timestamp
1741
return self._repository.get_revision(last_changed_revision).timestamp
1861
1743
def get_file_sha1(self, file_id, path=None, stat_value=None):
1862
1744
entry = self._get_entry(file_id=file_id, path=path)
1866
1748
return parent_details[1]
1870
def get_file_revision(self, file_id):
1871
return self.inventory[file_id].revision
1873
1751
def get_file(self, file_id, path=None):
1874
1752
return StringIO(self.get_file_text(file_id))
1899
1777
return self._repository.iter_files_bytes(repo_desired_files)
1901
def get_symlink_target(self, file_id, path=None):
1779
def get_symlink_target(self, file_id):
1902
1780
entry = self._get_entry(file_id=file_id)
1903
1781
parent_index = self._get_parent_index()
1904
1782
if entry[1][parent_index][0] != 'l':
1933
1811
entry = self._get_entry(file_id=file_id)[1]
1934
1812
if entry is None:
1935
1813
raise errors.NoSuchId(tree=self, file_id=file_id)
1936
parent_index = self._get_parent_index()
1937
return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1814
return dirstate.DirState._minikind_to_kind[entry[1][0]]
1939
1816
def stored_kind(self, file_id):
1940
1817
"""See Tree.stored_kind"""
1957
1834
def is_executable(self, file_id, path=None):
1958
1835
ie = self.inventory[file_id]
1959
1836
if ie.kind != "file":
1961
1838
return ie.executable
1963
def is_locked(self):
1966
def list_files(self, include_root=False, from_dir=None, recursive=True):
1840
def list_files(self, include_root=False):
1967
1841
# We use a standard implementation, because DirStateRevisionTree is
1968
1842
# dealing with one of the parents of the current state
1969
1843
inv = self._get_inventory()
1970
if from_dir is None:
1973
from_dir_id = inv.path2id(from_dir)
1974
if from_dir_id is None:
1975
# Directory not versioned
1977
entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
1978
if inv.root is not None and not include_root and from_dir is None:
1844
entries = inv.iter_entries()
1845
if self.inventory.root is not None and not include_root:
1980
1847
for path, entry in entries:
1981
1848
yield path, 'V', entry.kind, entry.file_id, entry
1983
1850
def lock_read(self):
1984
"""Lock the tree for a set of operations.
1986
:return: A bzrlib.lock.LogicalLockResult.
1851
"""Lock the tree for a set of operations."""
1988
1852
if not self._locked:
1989
1853
self._repository.lock_read()
1990
1854
if self._dirstate._lock_token is None:
1991
1855
self._dirstate.lock_read()
1992
1856
self._dirstate_locked = True
1993
1857
self._locked += 1
1994
return LogicalLockResult(self.unlock)
1996
1859
def _must_be_locked(self):
1997
1860
if not self._locked:
2076
1939
def make_source_parent_tree(source, target):
2077
1940
"""Change the source tree into a parent of the target."""
2078
1941
revid = source.commit('record tree')
2079
target.branch.fetch(source.branch, revid)
1942
target.branch.repository.fetch(source.branch.repository, revid)
2080
1943
target.set_parent_ids([revid])
2081
1944
return target.basis_tree(), target
2090
def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
1953
def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2092
1954
from bzrlib.tests.test__dirstate_helpers import \
2093
compiled_dirstate_helpers_feature
2094
test_case.requireFeature(compiled_dirstate_helpers_feature)
2095
from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1955
CompiledDirstateHelpersFeature
1956
if not CompiledDirstateHelpersFeature.available():
1957
from bzrlib.tests import UnavailableFeature
1958
raise UnavailableFeature(CompiledDirstateHelpersFeature)
1959
from bzrlib._dirstate_helpers_c import ProcessEntryC
2096
1960
result = klass.make_source_parent_tree(source, target)
2097
1961
result[1]._iter_changes = ProcessEntryC
2128
1992
output. An unversioned file is defined as one with (False, False)
2129
1993
for the versioned pair.
1995
# NB: show_status depends on being able to pass in non-versioned files
1996
# and report them as unknown
2131
1997
# TODO: handle extra trees in the dirstate.
2132
1998
if (extra_trees or specific_files == []):
2133
1999
# we can't fast-path these cases (yet)
2136
2002
require_versioned, want_unversioned=want_unversioned)
2137
2003
parent_ids = self.target.get_parent_ids()
2138
2004
if not (self.source._revision_id in parent_ids
2139
or self.source._revision_id == _mod_revision.NULL_REVISION):
2005
or self.source._revision_id == NULL_REVISION):
2140
2006
raise AssertionError(
2141
2007
"revision {%s} is not stored in {%s}, but %s "
2142
2008
"can only be used for trees stored in the dirstate"
2143
2009
% (self.source._revision_id, self.target, self.iter_changes))
2144
2010
target_index = 0
2145
if self.source._revision_id == _mod_revision.NULL_REVISION:
2011
if self.source._revision_id == NULL_REVISION:
2146
2012
source_index = None
2147
2013
indices = (target_index,)
2169
2035
state._read_dirblocks_if_needed()
2170
2036
if require_versioned:
2171
2037
# -- check all supplied paths are versioned in a search tree. --
2038
all_versioned = True
2173
2039
for path in specific_files:
2174
2040
path_entries = state._entries_for_path(path)
2175
2041
if not path_entries:
2176
2042
# this specified path is not present at all: error
2177
not_versioned.append(path)
2043
all_versioned = False
2179
2045
found_versioned = False
2180
2046
# for each id at this path
2181
2047
for entry in path_entries:
2188
2054
if not found_versioned:
2189
2055
# none of the indexes was not 'absent' at all ids for this
2191
not_versioned.append(path)
2192
if len(not_versioned) > 0:
2193
raise errors.PathsNotVersionedError(not_versioned)
2057
all_versioned = False
2059
if not all_versioned:
2060
raise errors.PathsNotVersionedError(specific_files)
2194
2061
# -- remove redundancy in supplied specific_files to prevent over-scanning --
2195
2062
search_specific_files = osutils.minimum_path_selection(specific_files)
2210
2077
(revisiontree.RevisionTree, DirStateRevisionTree)):
2212
2079
# the source revid must be in the target dirstate
2213
if not (source._revision_id == _mod_revision.NULL_REVISION or
2080
if not (source._revision_id == NULL_REVISION or
2214
2081
source._revision_id in target.get_parent_ids()):
2215
2082
# TODO: what about ghosts? it may well need to
2216
2083
# check for them explicitly.