100
IGNORE_FILENAME = ".gitignore"
103
class GitWorkingTree(MutableGitIndexTree,workingtree.WorkingTree):
87
class GitWorkingTree(MutableGitIndexTree, workingtree.WorkingTree):
104
88
"""A Git working tree."""
106
90
def __init__(self, controldir, repo, branch):
150
134
self._lock_mode = 'w'
151
135
self._lock_count = 1
153
self._index_file = GitFile(self.control_transport.local_abspath('index'), 'wb')
137
self._index_file = GitFile(
138
self.control_transport.local_abspath('index'), 'wb')
154
139
except FileLocked:
155
140
raise errors.LockContention('index')
156
141
self._read_index()
157
142
elif self._lock_mode == 'r':
158
143
raise errors.ReadOnlyError(self)
145
self._lock_count += 1
162
147
def lock_tree_write(self):
163
148
self.branch.lock_read()
165
150
self._lock_write_tree()
166
151
return lock.LogicalLockResult(self.unlock)
152
except BaseException:
168
153
self.branch.unlock()
236
221
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]
223
merges = [self.branch.lookup_bzr_revision_id(
224
revid)[0] for revid in rhs_parent_ids]
239
225
except errors.NoSuchRevision as e:
240
226
raise errors.GhostRevisionUnusableHere(e.revision)
242
self.control_transport.put_bytes('MERGE_HEAD', b'\n'.join(merges),
228
self.control_transport.put_bytes(
229
'MERGE_HEAD', b'\n'.join(merges),
243
230
mode=self.controldir._get_file_mode())
260
247
working tree. Any of these may be ghosts.
262
249
with self.lock_tree_write():
263
self._check_parents_for_ghosts(revision_ids,
264
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
250
self._check_parents_for_ghosts(
251
revision_ids, allow_leftmost_as_ghost=allow_leftmost_as_ghost)
265
252
for revision_id in revision_ids:
266
253
_mod_revision.check_not_reserved_id(revision_id)
302
290
def remove(self, files, verbose=False, to_file=None, keep_files=True,
304
292
"""Remove nominated files from the working tree metadata.
306
294
:param files: File paths relative to the basedir.
317
305
def backup(file_to_backup):
318
306
abs_path = self.abspath(file_to_backup)
319
backup_name = self.controldir._available_backup_name(file_to_backup)
307
backup_name = self.controldir._available_backup_name(
320
309
osutils.rename(abs_path, self.abspath(backup_name))
321
310
return "removed %s (but kept a copy: %s)" % (
322
311
file_to_backup, backup_name)
353
342
files = list(all_files)
355
344
if len(files) == 0:
356
return # nothing to do
345
return # nothing to do
358
# Sort needed to first handle directory content before the directory
347
# Sort needed to first handle directory content before the
359
349
files.sort(reverse=True)
361
351
# Bail out if we are going to delete files we shouldn't
362
352
if not keep_files and not force:
363
353
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:
354
kind, executable) in self.iter_changes(
355
self.basis_tree(), include_unchanged=True,
356
require_versioned=False, want_unversioned=True,
357
specific_files=files):
358
if versioned[0] is False:
368
359
# The record is unknown or newly added
369
360
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])):
361
files_to_backup.extend(
362
osutils.parent_directories(path[1]))
363
elif (content_change and (kind[1] is not None)
364
and osutils.is_inside_any(files, path[1])):
373
365
# Versioned and changed, but not deleted, and still
374
366
# in one of the dirs to be deleted.
375
367
files_to_backup.append(path[1])
376
files_to_backup.extend(osutils.parent_directories(path[1]))
368
files_to_backup.extend(
369
osutils.parent_directories(path[1]))
441
437
raise workingtree.SettingFileIdUnsupported()
443
439
with self.lock_tree_write():
444
for filepath in osutils.canonical_relpaths(self.basedir, file_list):
440
for filepath in osutils.canonical_relpaths(
441
self.basedir, file_list):
445
442
filepath, can_access = osutils.normalized_filename(filepath)
446
443
if not can_access:
447
444
raise errors.InvalidNormalization(filepath)
449
446
abspath = self.abspath(filepath)
450
447
kind = osutils.file_kind(abspath)
451
448
if kind in ("file", "symlink"):
452
(index, subpath) = self._lookup_index(filepath.encode('utf-8'))
449
(index, subpath) = self._lookup_index(
450
filepath.encode('utf-8'))
453
451
if subpath in index:
454
452
# Already present
458
456
self._index_add_entry(filepath, kind)
459
457
added.append(filepath)
460
458
elif kind == "directory":
461
(index, subpath) = self._lookup_index(filepath.encode('utf-8'))
459
(index, subpath) = self._lookup_index(
460
filepath.encode('utf-8'))
462
461
if subpath not in index:
463
462
call_action(filepath, kind)
469
468
abs_user_dir = self.abspath(user_dir)
470
469
if user_dir != '':
472
transport = _mod_transport.get_transport_from_path(abs_user_dir)
471
transport = _mod_transport.get_transport_from_path(
473
473
_mod_controldir.ControlDirFormat.find_format(transport)
475
475
except errors.NotBranchError:
485
485
for name in os.listdir(abs_user_dir):
486
486
subp = os.path.join(user_dir, name)
487
if self.is_control_filename(subp) or self.mapping.is_special_file(subp):
487
if (self.is_control_filename(subp) or
488
self.mapping.is_special_file(subp)):
489
490
ignore_glob = self.is_ignored(subp)
490
491
if ignore_glob is not None:
495
496
if kind == "directory":
496
497
user_dirs.append(subp)
498
(index, subpath) = self._lookup_index(subp.encode('utf-8'))
499
(index, subpath) = self._lookup_index(
500
subp.encode('utf-8'))
499
501
if subpath in index:
500
502
# Already present
502
504
if subp in conflicts_related:
504
call_action(filepath, kind)
506
call_action(subp, kind)
506
508
self._index_add_entry(subp, kind)
507
509
added.append(subp)
513
515
def _iter_files_recursive(self, from_dir=None, include_dirs=False):
514
516
if from_dir is None:
516
for (dirpath, dirnames, filenames) in os.walk(self.abspath(from_dir).encode(osutils._fs_enc)):
518
encoded_from_dir = self.abspath(from_dir).encode(osutils._fs_enc)
519
for (dirpath, dirnames, filenames) in os.walk(encoded_from_dir):
517
520
dir_relpath = dirpath[len(self.basedir):].strip(b"/")
518
if self.controldir.is_control_filename(dir_relpath.decode(osutils._fs_enc)):
521
if self.controldir.is_control_filename(
522
dir_relpath.decode(osutils._fs_enc)):
520
524
for name in list(dirnames):
521
if self.controldir.is_control_filename(name.decode(osutils._fs_enc)):
525
if self.controldir.is_control_filename(
526
name.decode(osutils._fs_enc)):
522
527
dirnames.remove(name)
524
529
relpath = os.path.join(dir_relpath, name)
528
533
except UnicodeDecodeError:
529
534
raise errors.BadFilenameEncoding(
530
535
relpath, osutils._fs_enc)
531
if not self._has_dir(relpath):
532
dirnames.remove(name)
536
if not self._has_dir(relpath):
537
dirnames.remove(name)
533
538
for name in filenames:
534
if not self.mapping.is_special_file(name):
535
yp = os.path.join(dir_relpath, name)
537
yield yp.decode(osutils._fs_enc)
538
except UnicodeDecodeError:
539
raise errors.BadFilenameEncoding(
539
if self.mapping.is_special_file(name):
541
if self.controldir.is_control_filename(
542
name.decode(osutils._fs_enc, 'replace')):
544
yp = os.path.join(dir_relpath, name)
546
yield yp.decode(osutils._fs_enc)
547
except UnicodeDecodeError:
548
raise errors.BadFilenameEncoding(
542
551
def extras(self):
543
552
"""Yield all unversioned files in this WorkingTree.
545
554
with self.lock_read():
546
index_paths = set([p.decode('utf-8') for p, i in self._recurse_index_entries()])
547
all_paths = set(self._iter_files_recursive(include_dirs=True))
548
for p in (all_paths - index_paths):
549
if not self._has_dir(p.encode('utf-8')):
556
[p.decode('utf-8') for p, i in self._recurse_index_entries()])
557
all_paths = set(self._iter_files_recursive(include_dirs=False))
558
return iter(all_paths - index_paths)
552
560
def _gather_kinds(self, files, kinds):
553
561
"""See MutableTree._gather_kinds."""
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,
756
774
with self.lock_read():
757
775
root_ie = self._get_dir_ie(u"", None)
758
776
if include_root and not from_dir:
759
yield "", "V", root_ie.kind, root_ie.file_id, root_ie
777
yield "", "V", root_ie.kind, 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:
785
810
if self._has_dir(encoded_path):
786
811
ie = self._get_dir_ie(path, self.path2id(path))
789
813
elif self.is_ignored(path):
791
815
ie = fk_entries[kind]()
795
818
ie = fk_entries[kind]()
797
yield posixpath.relpath(path, from_dir), status, kind, file_id, ie
819
yield (posixpath.relpath(path, from_dir), status, kind,
799
822
if value is not None:
800
823
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
824
yield (posixpath.relpath(path, from_dir), "V", ie.kind, ie)
803
826
ie = fk_entries[kind]()
804
yield posixpath.relpath(path, from_dir), ("I" if self.is_ignored(path) else "?"), kind, None, ie
827
yield (posixpath.relpath(path, from_dir),
828
("I" if self.is_ignored(path) else "?"), kind, ie)
806
830
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())
831
raise errors.UnsupportedOperation(self.all_file_ids, self)
819
833
def all_versioned_paths(self):
820
834
with self.lock_read():
834
def iter_child_entries(self, path, file_id=None):
848
def iter_child_entries(self, path):
835
849
encoded_path = path.encode('utf-8')
836
850
with self.lock_read():
837
851
parent_id = self.path2id(path)
838
852
found_any = False
839
seen_children = set()
840
853
for item_path, value in self.index.iteritems():
841
854
decoded_item_path = item_path.decode('utf-8')
842
855
if self.mapping.is_special_file(item_path):
847
860
subpath = posixpath.relpath(decoded_item_path, path)
848
861
if '/' in subpath:
849
862
dirname = subpath.split('/', 1)[0]
850
file_ie = self._get_dir_ie(posixpath.join(path, dirname), parent_id)
863
file_ie = self._get_dir_ie(
864
posixpath.join(path, dirname), parent_id)
852
866
(unused_parent, name) = posixpath.split(decoded_item_path)
853
867
file_ie = self._get_file_ie(
861
875
conflicts = _mod_conflicts.ConflictList()
862
876
for item_path, value in self.index.iteritems():
863
877
if value.flags & FLAG_STAGEMASK:
864
conflicts.append(_mod_conflicts.TextConflict(item_path.decode('utf-8')))
878
conflicts.append(_mod_conflicts.TextConflict(
879
item_path.decode('utf-8')))
867
882
def set_conflicts(self, conflicts):
883
898
self.index[path] = (value[:9] + (value[9] | FLAG_STAGEMASK, ))
885
self.index[path] = (value[:9] + (value[9] &~ FLAG_STAGEMASK, ))
900
self.index[path] = (value[:9] + (value[9] & ~ FLAG_STAGEMASK, ))
887
902
def add_conflicts(self, new_conflicts):
888
903
with self.lock_tree_write():
889
904
for conflict in new_conflicts:
890
if conflict.typestring in ('text conflict', 'contents conflict'):
905
if conflict.typestring in ('text conflict',
906
'contents conflict'):
892
self._set_conflicted(conflict.path.encode('utf-8'), True)
908
self._set_conflicted(
909
conflict.path.encode('utf-8'), True)
894
raise errors.UnsupportedOperation(self.add_conflicts, self)
911
raise errors.UnsupportedOperation(
912
self.add_conflicts, self)
896
914
raise errors.UnsupportedOperation(self.add_conflicts, self)
921
939
current_disk = next(disk_iterator)
922
940
disk_finished = False
923
941
except OSError as e:
924
if not (e.errno == errno.ENOENT or
925
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
942
if not (e.errno == errno.ENOENT
943
or (sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
927
945
current_disk = None
928
946
disk_finished = True
941
959
cur_disk_dir_content) = ((None, None), None)
942
960
if not disk_finished:
943
961
# strip out .bzr dirs
944
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
945
len(cur_disk_dir_content) > 0):
962
if (cur_disk_dir_path_from_top[top_strip_len:] == ''
963
and len(cur_disk_dir_content) > 0):
946
964
# osutils.walkdirs can be made nicer -
947
965
# yield the path-from-prefix rather than the pathjoined
949
967
bzrdir_loc = bisect_left(cur_disk_dir_content,
951
if (bzrdir_loc < len(cur_disk_dir_content)
952
and self.controldir.is_control_filename(
969
if (bzrdir_loc < len(cur_disk_dir_content) and
970
self.controldir.is_control_filename(
953
971
cur_disk_dir_content[bzrdir_loc][0])):
954
972
# we dont yield the contents of, or, .bzr itself.
955
973
del cur_disk_dir_content[bzrdir_loc]
960
978
# everything is missing
963
direction = ((current_inv[0][0] > cur_disk_dir_relpath) -
964
(current_inv[0][0] < cur_disk_dir_relpath))
981
direction = ((current_inv[0][0] > cur_disk_dir_relpath)
982
- (current_inv[0][0] < cur_disk_dir_relpath))
965
983
if direction > 0:
966
984
# disk is before inventory - unknown
967
985
dirblock = [(relpath, basename, kind, stat, None, None) for
968
relpath, basename, kind, stat, top_path in
969
cur_disk_dir_content]
986
relpath, basename, kind, stat, top_path in
987
cur_disk_dir_content]
970
988
yield (cur_disk_dir_relpath, None), dirblock
972
990
current_disk = next(disk_iterator)
975
993
elif direction < 0:
976
994
# inventory is before disk - missing.
977
995
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
978
for relpath, basename, dkind, stat, fileid, kind in
996
for relpath, basename, dkind, stat, fileid, kind in
980
998
yield (current_inv[0][0], current_inv[0][1]), dirblock
982
1000
current_inv = next(inventory_iterator)
987
1005
# merge the inventory and disk data together
989
1007
for relpath, subiterator in itertools.groupby(sorted(
990
current_inv[1] + cur_disk_dir_content,
991
key=operator.itemgetter(0)), operator.itemgetter(1)):
1008
current_inv[1] + cur_disk_dir_content,
1009
key=operator.itemgetter(0)), operator.itemgetter(1)):
992
1010
path_elements = list(subiterator)
993
1011
if len(path_elements) == 2:
994
1012
inv_row, disk_row = path_elements
995
1013
# versioned, present file
996
1014
dirblock.append((inv_row[0],
997
inv_row[1], disk_row[2],
998
disk_row[3], inv_row[4],
1015
inv_row[1], disk_row[2],
1016
disk_row[3], inv_row[4],
1000
1018
elif len(path_elements[0]) == 5:
1001
1019
# 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))
1021
(path_elements[0][0], path_elements[0][1],
1022
path_elements[0][2], path_elements[0][3],
1005
1024
elif len(path_elements[0]) == 6:
1006
1025
# 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]))
1027
(path_elements[0][0], path_elements[0][1],
1028
'unknown', None, path_elements[0][4],
1029
path_elements[0][5]))
1011
1031
raise NotImplementedError('unreachable code')
1012
1032
yield current_inv[0], dirblock
1026
1046
per_dir = defaultdict(set)
1027
1047
if prefix == b"":
1028
1048
per_dir[(u'', self.get_root_id())] = set()
1029
1050
def add_entry(path, kind):
1030
1051
if path == b'' or not path.startswith(prefix):
1037
1058
raise ValueError(value)
1038
1059
per_dir[(dirname, dir_file_id)].add(
1039
1060
(path.decode("utf-8"), child_name.decode("utf-8"),
1041
self.path2id(path.decode("utf-8")),
1062
self.path2id(path.decode("utf-8")),
1043
1064
with self.lock_read():
1044
1065
for path, value in self.index.iteritems():
1045
1066
if self.mapping.is_special_file(path):
1058
1079
def apply_inventory_delta(self, changes):
1059
1080
for (old_path, new_path, file_id, ie) in changes:
1060
1081
if old_path is not None:
1061
(index, old_subpath) = self._lookup_index(old_path.encode('utf-8'))
1082
(index, old_subpath) = self._lookup_index(
1083
old_path.encode('utf-8'))
1063
1085
self._index_del_entry(index, old_subpath)
1064
1086
except KeyError:
1068
1090
if new_path is not None and ie.kind != 'directory':
1069
1091
if ie.kind == 'tree-reference':
1070
1092
self._index_add_entry(
1072
reference_revision=ie.reference_revision)
1094
reference_revision=ie.reference_revision)
1074
1096
self._index_add_entry(new_path, ie.kind)
1077
def annotate_iter(self, path, file_id=None,
1099
def annotate_iter(self, path,
1078
1100
default_revision=_mod_revision.CURRENT_REVISION):
1079
1101
"""See Tree.annotate_iter
1092
1114
parent_tree = self.revision_tree(parent_id)
1093
1115
except errors.NoSuchRevisionInTree:
1094
1116
parent_tree = self.branch.repository.revision_tree(
1096
1118
with parent_tree.lock_read():
1097
# TODO(jelmer): Use rename/copy tracker to find path name in parent
1119
# TODO(jelmer): Use rename/copy tracker to find path name
1098
1121
parent_path = path
1100
1123
kind = parent_tree.kind(parent_path)
1101
1124
except errors.NoSuchFile:
1103
1126
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
1127
# Note: this is slightly unnecessary, because symlinks
1128
# and directories have a "text" which is the empty
1129
# text, and we know that won't mess up annotations. But
1108
1132
parent_text_key = (
1140
1164
self.user_transport.local_abspath('.'),
1141
1165
self.control_transport.local_abspath("index"),
1143
None if self.branch.head is None else self.store[self.branch.head].tree)
1168
if self.branch.head is None
1169
else self.store[self.branch.head].tree)
1145
1171
def reset_state(self, revision_ids=None):
1146
1172
"""Reset the state of the working tree.
1154
1180
self.index.clear()
1155
1181
self._index_dirty = True
1156
1182
if self.branch.head is not None:
1157
for entry in self.store.iter_tree_contents(self.store[self.branch.head].tree):
1183
for entry in self.store.iter_tree_contents(
1184
self.store[self.branch.head].tree):
1158
1185
if not validate_path(entry.path):
1161
1188
if S_ISGITLINK(entry.mode):
1162
pass # TODO(jelmer): record and return submodule paths
1189
pass # TODO(jelmer): record and return submodule paths
1164
1191
# Let's at least try to use the working tree file:
1166
st = self._lstat(self.abspath(entry.path.decode('utf-8')))
1193
st = self._lstat(self.abspath(
1194
entry.path.decode('utf-8')))
1167
1195
except OSError:
1168
1196
# But if it doesn't exist, we'll make something up.
1169
1197
obj = self.store[entry.sha]
1170
1198
st = os.stat_result((entry.mode, 0, 0, 0,
1171
0, 0, len(obj.as_raw_string()), 0,
1200
obj.as_raw_string()), 0,
1173
1202
(index, subpath) = self._lookup_index(entry.path)
1174
1203
index[subpath] = index_entry_from_stat(st, entry.sha, 0)
1187
1216
with basis_tree.lock_read():
1188
1217
new_basis_tree = self.branch.basis_tree()
1189
1218
merge.merge_inner(
1194
change_reporter=change_reporter,
1195
show_base=show_base)
1223
change_reporter=change_reporter,
1224
show_base=show_base)
1198
1227
def add_reference(self, sub_tree):
1205
1234
sub_tree_path = self.relpath(sub_tree.basedir)
1206
1235
except errors.PathNotChild:
1207
1236
raise BadReferenceTarget(
1208
self, sub_tree, 'Target not inside tree.')
1237
self, sub_tree, 'Target not inside tree.')
1210
1239
self._add([sub_tree_path], [None], ['tree-reference'])
1212
1241
def _read_submodule_head(self, path):
1213
1242
return read_submodule_head(self.abspath(path))
1215
def get_reference_revision(self, path, file_id=None):
1244
def get_reference_revision(self, path):
1216
1245
hexsha = self._read_submodule_head(path)
1217
1246
if hexsha is None:
1218
1247
return _mod_revision.NULL_REVISION
1219
1248
return self.branch.lookup_foreign_revision_id(hexsha)
1221
def get_nested_tree(self, path, file_id=None):
1250
def get_nested_tree(self, path):
1222
1251
return workingtree.WorkingTree.open(self.abspath(path))
1224
1253
def _directory_is_tree_reference(self, relpath):
1226
1255
# it's a tree reference, except that the root of the tree is not
1227
1256
return relpath and osutils.lexists(self.abspath(relpath) + u"/.git")
1229
def extract(self, sub_path, file_id=None, format=None):
1258
def extract(self, sub_path, format=None):
1230
1259
"""Extract a subtree from this tree.
1232
1261
A new branch will be created, relative to the path for this tree.
1288
1317
other_tree = self.revision_tree(revision_id)
1289
1318
except errors.NoSuchRevision:
1290
1319
other_tree = self.branch.repository.revision_tree(
1293
1322
merge.transform_tree(tree, other_tree)
1294
1323
if revision_id == _mod_revision.NULL_REVISION:
1333
1364
if revision_id is not None:
1334
1365
branch.set_last_revision(revision_id)
1335
1366
wt = GitWorkingTree(
1336
a_controldir, a_controldir.open_repository(), branch)
1367
a_controldir, a_controldir.open_repository(), branch)
1337
1368
for hook in MutableTree.hooks['post_build_tree']: