1185
1188
todo = [(p, i) for (p, i) in self._recurse_index_entries() if p.startswith(from_path+'/')]
1186
1189
for child_path, child_value in todo:
1187
(child_to_index, child_to_index_path) = self._lookup_index(posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1190
(child_to_index, child_to_index_path) = self._lookup_index(
1191
posixpath.join(to_path, posixpath.relpath(child_path, from_path)))
1188
1192
child_to_index[child_to_index_path] = child_value
1189
1193
# TODO(jelmer): Mark individual index as dirty
1190
1194
self._index_dirty = True
1252
1256
return 'directory'
1260
def _live_entry(self, relpath):
1261
raise NotImplementedError(self._live_entry)
1264
class InterIndexGitTree(InterGitTrees):
1265
"""InterTree that works between a Git revision tree and an index."""
1267
def __init__(self, source, target):
1268
super(InterIndexGitTree, self).__init__(source, target)
1269
self._index = target.index
1272
def is_compatible(cls, source, target):
1273
return (isinstance(source, GitRevisionTree) and
1274
isinstance(target, MutableGitIndexTree))
1276
def _iter_git_changes(self, want_unchanged=False, specific_files=None,
1277
require_versioned=False, extra_trees=None,
1278
want_unversioned=False):
1279
trees = [self.source]
1280
if extra_trees is not None:
1281
trees.extend(extra_trees)
1282
if specific_files is not None:
1283
specific_files = self.target.find_related_paths_across_trees(
1284
specific_files, trees,
1285
require_versioned=require_versioned)
1286
# TODO(jelmer): Restrict to specific_files, for performance reasons.
1287
with self.lock_read():
1288
return changes_between_git_tree_and_working_copy(
1289
self.source.store, self.source.tree,
1290
self.target, want_unchanged=want_unchanged,
1291
want_unversioned=want_unversioned)
1294
_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
1297
def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,
1298
want_unchanged=False, want_unversioned=False):
1299
"""Determine the changes between a git tree and a working tree with index.
1304
# Report dirified directories to commit_tree first, so that they can be
1305
# replaced with non-empty directories if they have contents.
1307
for path, index_entry in target._recurse_index_entries():
1309
live_entry = target._live_entry(path)
1310
except EnvironmentError as e:
1311
if e.errno == errno.ENOENT:
1312
# Entry was removed; keep it listed, but mark it as gone.
1313
blobs[path] = (ZERO_SHA, 0)
1314
elif e.errno == errno.EISDIR:
1315
# Entry was turned into a directory
1316
dirified.append((path, Tree().id, stat.S_IFDIR))
1317
store.add_object(Tree())
1321
blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
1322
if want_unversioned:
1323
for e in target.extras():
1324
st = target._lstat(e)
1326
np, accessible = osutils.normalized_filename(e)
1327
except UnicodeDecodeError:
1328
raise errors.BadFilenameEncoding(
1330
if stat.S_ISDIR(st.st_mode):
1333
blob = blob_from_path_and_stat(target.abspath(e).encode(osutils._fs_enc), st)
1334
store.add_object(blob)
1335
np = np.encode('utf-8')
1336
blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1338
to_tree_sha = commit_tree(store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1339
return store.tree_changes(
1340
from_tree_sha, to_tree_sha, include_trees=True,
1341
want_unchanged=want_unchanged, change_type_same=True), extras