100
86
IGNORE_FILENAME = ".gitignore"
103
class GitWorkingTree(MutableGitIndexTree,workingtree.WorkingTree):
89
class GitWorkingTree(MutableGitIndexTree, workingtree.WorkingTree):
104
90
"""A Git working tree."""
106
92
def __init__(self, controldir, repo, branch):
150
136
self._lock_mode = 'w'
151
137
self._lock_count = 1
153
self._index_file = GitFile(self.control_transport.local_abspath('index'), 'wb')
139
self._index_file = GitFile(
140
self.control_transport.local_abspath('index'), 'wb')
154
141
except FileLocked:
155
142
raise errors.LockContention('index')
156
143
self._read_index()
157
144
elif self._lock_mode == 'r':
158
145
raise errors.ReadOnlyError(self)
147
self._lock_count += 1
162
149
def lock_tree_write(self):
163
150
self.branch.lock_read()
165
152
self._lock_write_tree()
166
153
return lock.LogicalLockResult(self.unlock)
154
except BaseException:
168
155
self.branch.unlock()
236
223
def _set_merges_from_parent_ids(self, rhs_parent_ids):
238
merges = [self.branch.lookup_bzr_revision_id(revid)[0] for revid in rhs_parent_ids]
225
merges = [self.branch.lookup_bzr_revision_id(
226
revid)[0] for revid in rhs_parent_ids]
239
227
except errors.NoSuchRevision as e:
240
228
raise errors.GhostRevisionUnusableHere(e.revision)
242
self.control_transport.put_bytes('MERGE_HEAD', b'\n'.join(merges),
230
self.control_transport.put_bytes(
231
'MERGE_HEAD', b'\n'.join(merges),
243
232
mode=self.controldir._get_file_mode())
260
249
working tree. Any of these may be ghosts.
262
251
with self.lock_tree_write():
263
self._check_parents_for_ghosts(revision_ids,
264
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
252
self._check_parents_for_ghosts(
253
revision_ids, allow_leftmost_as_ghost=allow_leftmost_as_ghost)
265
254
for revision_id in revision_ids:
266
255
_mod_revision.check_not_reserved_id(revision_id)
302
292
def remove(self, files, verbose=False, to_file=None, keep_files=True,
304
294
"""Remove nominated files from the working tree metadata.
306
296
:param files: File paths relative to the basedir.
317
307
def backup(file_to_backup):
318
308
abs_path = self.abspath(file_to_backup)
319
backup_name = self.controldir._available_backup_name(file_to_backup)
309
backup_name = self.controldir._available_backup_name(
320
311
osutils.rename(abs_path, self.abspath(backup_name))
321
312
return "removed %s (but kept a copy: %s)" % (
322
313
file_to_backup, backup_name)
353
344
files = list(all_files)
355
346
if len(files) == 0:
356
return # nothing to do
347
return # nothing to do
358
# Sort needed to first handle directory content before the directory
349
# Sort needed to first handle directory content before the
359
351
files.sort(reverse=True)
361
353
# Bail out if we are going to delete files we shouldn't
362
354
if not keep_files and not force:
363
355
for (file_id, path, content_change, versioned, parent_id, name,
364
kind, executable) in self.iter_changes(self.basis_tree(),
365
include_unchanged=True, require_versioned=False,
366
want_unversioned=True, specific_files=files):
367
if versioned[0] == False:
356
kind, executable) in self.iter_changes(
357
self.basis_tree(), include_unchanged=True,
358
require_versioned=False, want_unversioned=True,
359
specific_files=files):
360
if versioned[0] is False:
368
361
# The record is unknown or newly added
369
362
files_to_backup.append(path[1])
370
files_to_backup.extend(osutils.parent_directories(path[1]))
371
elif (content_change and (kind[1] is not None) and
372
osutils.is_inside_any(files, path[1])):
363
files_to_backup.extend(
364
osutils.parent_directories(path[1]))
365
elif (content_change and (kind[1] is not None)
366
and osutils.is_inside_any(files, path[1])):
373
367
# Versioned and changed, but not deleted, and still
374
368
# in one of the dirs to be deleted.
375
369
files_to_backup.append(path[1])
376
files_to_backup.extend(osutils.parent_directories(path[1]))
370
files_to_backup.extend(
371
osutils.parent_directories(path[1]))
441
439
raise workingtree.SettingFileIdUnsupported()
443
441
with self.lock_tree_write():
444
for filepath in osutils.canonical_relpaths(self.basedir, file_list):
442
for filepath in osutils.canonical_relpaths(
443
self.basedir, file_list):
445
444
filepath, can_access = osutils.normalized_filename(filepath)
446
445
if not can_access:
447
446
raise errors.InvalidNormalization(filepath)
449
448
abspath = self.abspath(filepath)
450
449
kind = osutils.file_kind(abspath)
451
450
if kind in ("file", "symlink"):
452
(index, subpath) = self._lookup_index(filepath.encode('utf-8'))
451
(index, subpath) = self._lookup_index(
452
filepath.encode('utf-8'))
453
453
if subpath in index:
454
454
# Already present
458
458
self._index_add_entry(filepath, kind)
459
459
added.append(filepath)
460
460
elif kind == "directory":
461
(index, subpath) = self._lookup_index(filepath.encode('utf-8'))
461
(index, subpath) = self._lookup_index(
462
filepath.encode('utf-8'))
462
463
if subpath not in index:
463
464
call_action(filepath, kind)
469
470
abs_user_dir = self.abspath(user_dir)
470
471
if user_dir != '':
472
transport = _mod_transport.get_transport_from_path(abs_user_dir)
473
transport = _mod_transport.get_transport_from_path(
473
475
_mod_controldir.ControlDirFormat.find_format(transport)
475
477
except errors.NotBranchError:
485
487
for name in os.listdir(abs_user_dir):
486
488
subp = os.path.join(user_dir, name)
487
if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
489
if (self.is_control_filename(subp) or
490
self.mapping.is_special_file(subp)):
489
492
ignore_glob = self.is_ignored(subp)
490
493
if ignore_glob is not None:
495
498
if kind == "directory":
496
499
user_dirs.append(subp)
498
(index, subpath) = self._lookup_index(subp.encode('utf-8'))
501
(index, subpath) = self._lookup_index(
502
subp.encode('utf-8'))
499
503
if subpath in index:
500
504
# Already present
502
506
if subp in conflicts_related:
504
call_action(filepath, kind)
508
call_action(subp, kind)
506
510
self._index_add_entry(subp, kind)
507
511
added.append(subp)
513
517
def _iter_files_recursive(self, from_dir=None, include_dirs=False):
514
518
if from_dir is None:
516
for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir).encode(osutils._fs_enc)):
520
encoded_from_dir = self.abspath(from_dir).encode(osutils._fs_enc)
521
for (dirpath, dirnames, filenames) in os.walk(encoded_from_dir):
517
522
dir_relpath = dirpath[len(self.basedir):].strip(b"/")
518
if self.controldir.is_control_filename(dir_relpath.decode(osutils._fs_enc)):
523
if self.controldir.is_control_filename(
524
dir_relpath.decode(osutils._fs_enc)):
520
526
for name in list(dirnames):
521
if self.controldir.is_control_filename(name.decode(osutils._fs_enc)):
527
if self.controldir.is_control_filename(
528
name.decode(osutils._fs_enc)):
522
529
dirnames.remove(name)
524
531
relpath = os.path.join(dir_relpath, name)
543
550
"""Yield all unversioned files in this WorkingTree.
545
552
with self.lock_read():
546
index_paths = set([p.decode('utf-8') for p, i in self._recurse_index_entries()])
553
index_paths = set([p.decode('utf-8')
554
for p, i in self._recurse_index_entries()])
547
555
all_paths = set(self._iter_files_recursive(include_dirs=True))
548
556
for p in (all_paths - index_paths):
549
557
if not self._has_dir(p.encode('utf-8')):
556
564
if kinds[pos] is None:
557
565
fullpath = osutils.normpath(self.abspath(f))
559
kind = osutils.file_kind(fullpath)
567
kind = osutils.file_kind(fullpath)
560
568
except OSError as e:
561
569
if e.errno == errno.ENOENT:
562
570
raise errors.NoSuchFile(fullpath)
563
if kind == 'directory' and f != '' and os.path.exists(os.path.join(fullpath, '.git')):
571
if (kind == 'directory' and f != '' and
572
os.path.exists(os.path.join(fullpath, '.git'))):
564
573
kind = 'tree-reference'
565
574
kinds[pos] = kind
568
577
if self._lock_mode != 'w':
569
578
raise errors.NotWriteLocked(self)
570
579
# TODO(jelmer): This shouldn't be writing in-place, but index.lock is
571
# already in use and GitFile doesn't allow overriding the lock file name :(
580
# already in use and GitFile doesn't allow overriding the lock file
572
582
f = open(self.control_transport.local_abspath('index'), 'wb')
573
583
# Note that _flush will close the file
605
tree_lookup_path(self.store.__getitem__, root_tree, path.encode('utf-8'))
615
tree_lookup_path(self.store.__getitem__,
616
root_tree, path.encode('utf-8'))
611
def get_file_mtime(self, path, file_id=None):
622
def get_file_mtime(self, path):
612
623
"""See Tree.get_file_mtime."""
614
625
return self._lstat(path).st_mtime
627
638
ignore_globs = set()
628
639
ignore_globs.update(ignores.get_runtime_ignores())
629
640
ignore_globs.update(ignores.get_user_ignores())
630
self._global_ignoreglobster = globbing.ExceptionGlobster(ignore_globs)
641
self._global_ignoreglobster = globbing.ExceptionGlobster(
631
643
match = self._global_ignoreglobster.match(filename)
632
644
if match is not None:
677
689
self.store.__getitem__, self.store[head].tree)
678
690
self._fileid_map = self._basis_fileid_map.copy()
680
def get_file_verifier(self, path, file_id=None, stat_value=None):
692
def get_file_verifier(self, path, stat_value=None):
681
693
with self.lock_read():
682
694
(index, subpath) = self._lookup_index(path.encode('utf-8'))
687
699
return ("GIT", None)
688
700
raise errors.NoSuchFile(path)
690
def get_file_sha1(self, path, file_id=None, stat_value=None):
702
def get_file_sha1(self, path, stat_value=None):
691
703
with self.lock_read():
692
704
if not self.is_versioned(path):
693
705
raise errors.NoSuchFile(path)
709
721
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
710
722
return self.basis_tree().is_executable(path)
712
def stored_kind(self, path, file_id=None):
724
def stored_kind(self, path):
713
725
with self.lock_read():
714
726
encoded_path = path.encode('utf-8')
715
727
(index, subpath) = self._lookup_index(encoded_path)
725
737
return os.lstat(self.abspath(path))
727
739
def _live_entry(self, path):
728
return index_entry_from_path(self.abspath(path.decode('utf-8')).encode(osutils._fs_enc))
740
encoded_path = self.abspath(path.decode('utf-8')).encode(
742
return index_entry_from_path(encoded_path)
730
def is_executable(self, path, file_id=None):
744
def is_executable(self, path):
731
745
with self.lock_read():
732
if getattr(self, "_supports_executable", osutils.supports_executable)():
746
if getattr(self, "_supports_executable",
747
osutils.supports_executable)():
733
748
mode = self._lstat(path).st_mode
735
750
(index, subpath) = self._lookup_index(path.encode('utf-8'))
740
755
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
742
757
def _is_executable_from_path_and_stat(self, path, stat_result):
743
if getattr(self, "_supports_executable", osutils.supports_executable)():
744
return self._is_executable_from_path_and_stat_from_stat(path, stat_result)
758
if getattr(self, "_supports_executable",
759
osutils.supports_executable)():
760
return self._is_executable_from_path_and_stat_from_stat(
746
return self._is_executable_from_path_and_stat_from_basis(path, stat_result)
763
return self._is_executable_from_path_and_stat_from_basis(
748
766
def list_files(self, include_root=False, from_dir=None, recursive=True):
767
if from_dir is None or from_dir == '.':
752
770
fk_entries = {'directory': tree.TreeDirectory,
759
777
yield "", "V", root_ie.kind, root_ie.file_id, root_ie
760
778
dir_ids[u""] = root_ie.file_id
762
path_iterator = sorted(self._iter_files_recursive(from_dir, include_dirs=True))
780
path_iterator = sorted(
781
self._iter_files_recursive(from_dir, include_dirs=True))
764
path_iterator = sorted([os.path.join(from_dir, name.decode(osutils._fs_enc)) for name in
765
os.listdir(self.abspath(from_dir).encode(osutils._fs_enc))
766
if not self.controldir.is_control_filename(name.decode(osutils._fs_enc))
767
and not self.mapping.is_special_file(name.decode(osutils._fs_enc))])
783
encoded_from_dir = self.abspath(from_dir).encode(
785
path_iterator = sorted(
786
[os.path.join(from_dir, name.decode(osutils._fs_enc))
787
for name in os.listdir(encoded_from_dir)
788
if not self.controldir.is_control_filename(
789
name.decode(osutils._fs_enc)) and
790
not self.mapping.is_special_file(
791
name.decode(osutils._fs_enc))])
768
792
for path in path_iterator:
770
794
encoded_path = path.encode("utf-8")
779
803
kind = self.kind(path)
780
804
parent, name = posixpath.split(path)
781
for dir_path, dir_ie in self._add_missing_parent_ids(parent, dir_ids):
805
for dir_path, dir_ie in self._add_missing_parent_ids(
783
808
if kind in ('directory', 'tree-reference'):
784
809
if path != from_dir:
795
820
ie = fk_entries[kind]()
797
yield posixpath.relpath(path, from_dir), status, kind, file_id, ie
823
posixpath.relpath(path, from_dir), status, kind,
799
826
if value is not None:
800
827
ie = self._get_file_ie(name, path, value, dir_ids[parent])
801
yield posixpath.relpath(path, from_dir), "V", ie.kind, ie.file_id, ie
828
yield (posixpath.relpath(path, from_dir), "V", ie.kind,
803
831
ie = fk_entries[kind]()
804
yield posixpath.relpath(path, from_dir), ("I" if self.is_ignored(path) else "?"), kind, None, ie
832
yield (posixpath.relpath(path, from_dir), ("I" if
833
self.is_ignored(path) else "?"), kind, None, ie)
806
835
def all_file_ids(self):
807
with self.lock_read():
808
ids = {u"": self.path2id("")}
809
for path in self.index:
810
if self.mapping.is_special_file(path):
812
path = path.decode("utf-8")
813
parent = posixpath.dirname(path).strip("/")
814
for e in self._add_missing_parent_ids(parent, ids):
816
ids[path] = self.path2id(path)
817
return set(ids.values())
836
raise errors.UnsupportedOperation(self.all_file_ids, self)
819
838
def all_versioned_paths(self):
820
839
with self.lock_read():
834
def iter_child_entries(self, path, file_id=None):
853
def iter_child_entries(self, path):
835
854
encoded_path = path.encode('utf-8')
836
855
with self.lock_read():
837
856
parent_id = self.path2id(path)
838
857
found_any = False
839
seen_children = set()
840
858
for item_path, value in self.index.iteritems():
841
859
decoded_item_path = item_path.decode('utf-8')
842
860
if self.mapping.is_special_file(item_path):
847
865
subpath = posixpath.relpath(decoded_item_path, path)
848
866
if '/' in subpath:
849
867
dirname = subpath.split('/', 1)[0]
850
file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
868
file_ie = self._get_dir_ie(
869
posixpath.join(path, dirname), parent_id)
852
871
(unused_parent, name) = posixpath.split(decoded_item_path)
853
872
file_ie = self._get_file_ie(
861
880
conflicts = _mod_conflicts.ConflictList()
862
881
for item_path, value in self.index.iteritems():
863
882
if value.flags & FLAG_STAGEMASK:
864
conflicts.append(_mod_conflicts.TextConflict(item_path.decode('utf-8')))
883
conflicts.append(_mod_conflicts.TextConflict(
884
item_path.decode('utf-8')))
867
887
def set_conflicts(self, conflicts):
883
903
self.index[path] = (value[:9] + (value[9] | FLAG_STAGEMASK, ))
885
self.index[path] = (value[:9] + (value[9] &~ FLAG_STAGEMASK, ))
905
self.index[path] = (value[:9] + (value[9] & ~ FLAG_STAGEMASK, ))
887
907
def add_conflicts(self, new_conflicts):
888
908
with self.lock_tree_write():
889
909
for conflict in new_conflicts:
890
if conflict.typestring in ('text conflict', 'contents conflict'):
910
if conflict.typestring in ('text conflict',
911
'contents conflict'):
892
self._set_conflicted(conflict.path.encode('utf-8'), True)
913
self._set_conflicted(
914
conflict.path.encode('utf-8'), True)
894
raise errors.UnsupportedOperation(self.add_conflicts, self)
916
raise errors.UnsupportedOperation(
917
self.add_conflicts, self)
896
919
raise errors.UnsupportedOperation(self.add_conflicts, self)
921
944
current_disk = next(disk_iterator)
922
945
disk_finished = False
923
946
except OSError as e:
924
if not (e.errno == errno.ENOENT or
925
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
947
if not (e.errno == errno.ENOENT
948
or (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
927
950
current_disk = None
928
951
disk_finished = True
941
964
cur_disk_dir_content) = ((None, None), None)
942
965
if not disk_finished:
943
966
# strip out .bzr dirs
944
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
945
len(cur_disk_dir_content) > 0):
967
if (cur_disk_dir_path_from_top[top_strip_len:] == ''
968
and len(cur_disk_dir_content) > 0):
946
969
# osutils.walkdirs can be made nicer -
947
970
# yield the path-from-prefix rather than the pathjoined
949
972
bzrdir_loc = bisect_left(cur_disk_dir_content,
951
if (bzrdir_loc < len(cur_disk_dir_content)
952
and self.controldir.is_control_filename(
974
if (bzrdir_loc < len(cur_disk_dir_content) and
975
self.controldir.is_control_filename(
953
976
cur_disk_dir_content[bzrdir_loc][0])):
954
977
# we dont yield the contents of, or, .bzr itself.
955
978
del cur_disk_dir_content[bzrdir_loc]
960
983
# everything is missing
963
direction = ((current_inv[0][0] > cur_disk_dir_relpath) -
964
(current_inv[0][0] < cur_disk_dir_relpath))
986
direction = ((current_inv[0][0] > cur_disk_dir_relpath)
987
- (current_inv[0][0] < cur_disk_dir_relpath))
965
988
if direction > 0:
966
989
# disk is before inventory - unknown
967
990
dirblock = [(relpath, basename, kind, stat, None, None) for
968
relpath, basename, kind, stat, top_path in
969
cur_disk_dir_content]
991
relpath, basename, kind, stat, top_path in
992
cur_disk_dir_content]
970
993
yield (cur_disk_dir_relpath, None), dirblock
972
995
current_disk = next(disk_iterator)
975
998
elif direction < 0:
976
999
# inventory is before disk - missing.
977
1000
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
978
for relpath, basename, dkind, stat, fileid, kind in
1001
for relpath, basename, dkind, stat, fileid, kind in
980
1003
yield (current_inv[0][0], current_inv[0][1]), dirblock
982
1005
current_inv = next(inventory_iterator)
987
1010
# merge the inventory and disk data together
989
1012
for relpath, subiterator in itertools.groupby(sorted(
990
current_inv[1] + cur_disk_dir_content,
991
key=operator.itemgetter(0)), operator.itemgetter(1)):
1013
current_inv[1] + cur_disk_dir_content,
1014
key=operator.itemgetter(0)), operator.itemgetter(1)):
992
1015
path_elements = list(subiterator)
993
1016
if len(path_elements) == 2:
994
1017
inv_row, disk_row = path_elements
995
1018
# versioned, present file
996
1019
dirblock.append((inv_row[0],
997
inv_row[1], disk_row[2],
998
disk_row[3], inv_row[4],
1020
inv_row[1], disk_row[2],
1021
disk_row[3], inv_row[4],
1000
1023
elif len(path_elements[0]) == 5:
1001
1024
# unknown disk file
1002
dirblock.append((path_elements[0][0],
1003
path_elements[0][1], path_elements[0][2],
1004
path_elements[0][3], None, None))
1026
(path_elements[0][0], path_elements[0][1],
1027
path_elements[0][2], path_elements[0][3],
1005
1029
elif len(path_elements[0]) == 6:
1006
1030
# versioned, absent file.
1007
dirblock.append((path_elements[0][0],
1008
path_elements[0][1], 'unknown', None,
1009
path_elements[0][4], path_elements[0][5]))
1032
(path_elements[0][0], path_elements[0][1],
1033
'unknown', None, path_elements[0][4],
1034
path_elements[0][5]))
1011
1036
raise NotImplementedError('unreachable code')
1012
1037
yield current_inv[0], dirblock
1026
1051
per_dir = defaultdict(set)
1027
1052
if prefix == b"":
1028
1053
per_dir[(u'', self.get_root_id())] = set()
1029
1055
def add_entry(path, kind):
1030
1056
if path == b'' or not path.startswith(prefix):
1037
1063
raise ValueError(value)
1038
1064
per_dir[(dirname, dir_file_id)].add(
1039
1065
(path.decode("utf-8"), child_name.decode("utf-8"),
1041
self.path2id(path.decode("utf-8")),
1067
self.path2id(path.decode("utf-8")),
1043
1069
with self.lock_read():
1044
1070
for path, value in self.index.iteritems():
1045
1071
if self.mapping.is_special_file(path):
1058
1084
def apply_inventory_delta(self, changes):
1059
1085
for (old_path, new_path, file_id, ie) in changes:
1060
1086
if old_path is not None:
1061
(index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
1087
(index, old_subpath) = self._lookup_index(
1088
old_path.encode('utf-8'))
1063
1090
self._index_del_entry(index, old_subpath)
1064
1091
except KeyError:
1068
1095
if new_path is not None and ie.kind != 'directory':
1069
1096
if ie.kind == 'tree-reference':
1070
1097
self._index_add_entry(
1072
reference_revision=ie.reference_revision)
1099
reference_revision=ie.reference_revision)
1074
1101
self._index_add_entry(new_path, ie.kind)
1077
def annotate_iter(self, path, file_id=None,
1104
def annotate_iter(self, path,
1078
1105
default_revision=_mod_revision.CURRENT_REVISION):
1079
1106
"""See Tree.annotate_iter
1092
1119
parent_tree = self.revision_tree(parent_id)
1093
1120
except errors.NoSuchRevisionInTree:
1094
1121
parent_tree = self.branch.repository.revision_tree(
1096
1123
with parent_tree.lock_read():
1097
# TODO(jelmer): Use rename/copy tracker to find path name in parent
1124
# TODO(jelmer): Use rename/copy tracker to find path name
1098
1126
parent_path = path
1100
1128
kind = parent_tree.kind(parent_path)
1101
1129
except errors.NoSuchFile:
1103
1131
if kind != 'file':
1104
# Note: this is slightly unnecessary, because symlinks and
1105
# directories have a "text" which is the empty text, and we
1106
# know that won't mess up annotations. But it seems cleaner
1132
# Note: this is slightly unnecessary, because symlinks
1133
# and directories have a "text" which is the empty
1134
# text, and we know that won't mess up annotations. But
1108
1137
parent_text_key = (
1140
1169
self.user_transport.local_abspath('.'),
1141
1170
self.control_transport.local_abspath("index"),
1143
None if self.branch.head is None else self.store[self.branch.head].tree)
1173
if self.branch.head is None
1174
else self.store[self.branch.head].tree)
1145
1176
def reset_state(self, revision_ids=None):
1146
1177
"""Reset the state of the working tree.
1154
1185
self.index.clear()
1155
1186
self._index_dirty = True
1156
1187
if self.branch.head is not None:
1157
for entry in self.store.iter_tree_contents(self.store[self.branch.head].tree):
1188
for entry in self.store.iter_tree_contents(
1189
self.store[self.branch.head].tree):
1158
1190
if not validate_path(entry.path):
1161
1193
if S_ISGITLINK(entry.mode):
1162
pass # TODO(jelmer): record and return submodule paths
1194
pass # TODO(jelmer): record and return submodule paths
1164
1196
# Let's at least try to use the working tree file:
1166
st = self._lstat(self.abspath(entry.path.decode('utf-8')))
1198
st = self._lstat(self.abspath(
1199
entry.path.decode('utf-8')))
1167
1200
except OSError:
1168
1201
# But if it doesn't exist, we'll make something up.
1169
1202
obj = self.store[entry.sha]
1170
1203
st = os.stat_result((entry.mode, 0, 0, 0,
1171
0, 0, len(obj.as_raw_string()), 0,
1205
obj.as_raw_string()), 0,
1173
1207
(index, subpath) = self._lookup_index(entry.path)
1174
1208
index[subpath] = index_entry_from_stat(st, entry.sha, 0)
1187
1221
with basis_tree.lock_read():
1188
1222
new_basis_tree = self.branch.basis_tree()
1189
1223
merge.merge_inner(
1194
change_reporter=change_reporter,
1195
show_base=show_base)
1228
change_reporter=change_reporter,
1229
show_base=show_base)
1198
1232
def add_reference(self, sub_tree):
1205
1239
sub_tree_path = self.relpath(sub_tree.basedir)
1206
1240
except errors.PathNotChild:
1207
1241
raise BadReferenceTarget(
1208
self, sub_tree, 'Target not inside tree.')
1242
self, sub_tree, 'Target not inside tree.')
1210
1244
self._add([sub_tree_path], [None], ['tree-reference'])
1212
1246
def _read_submodule_head(self, path):
1213
1247
return read_submodule_head(self.abspath(path))
1215
def get_reference_revision(self, path, file_id=None):
1249
def get_reference_revision(self, path):
1216
1250
hexsha = self._read_submodule_head(path)
1217
1251
if hexsha is None:
1218
1252
return _mod_revision.NULL_REVISION
1219
1253
return self.branch.lookup_foreign_revision_id(hexsha)
1221
def get_nested_tree(self, path, file_id=None):
1255
def get_nested_tree(self, path):
1222
1256
return workingtree.WorkingTree.open(self.abspath(path))
1224
1258
def _directory_is_tree_reference(self, relpath):
1226
1260
# it's a tree reference, except that the root of the tree is not
1227
1261
return relpath and osutils.lexists(self.abspath(relpath) + u"/.git")
1229
def extract(self, sub_path, file_id=None, format=None):
1263
def extract(self, sub_path, format=None):
1230
1264
"""Extract a subtree from this tree.
1232
1266
A new branch will be created, relative to the path for this tree.
1288
1322
other_tree = self.revision_tree(revision_id)
1289
1323
except errors.NoSuchRevision:
1290
1324
other_tree = self.branch.repository.revision_tree(
1293
1327
merge.transform_tree(tree, other_tree)
1294
1328
if revision_id == _mod_revision.NULL_REVISION:
1333
1367
if revision_id is not None:
1334
1368
branch.set_last_revision(revision_id)
1335
1369
wt = GitWorkingTree(
1336
a_controldir, a_controldir.open_repository(), branch)
1370
a_controldir, a_controldir.open_repository(), branch)
1337
1371
for hook in MutableTree.hooks['post_build_tree']: