Merge lp:~jelmer/brz/iterobjectss into lp:brz/3.1
- iterobjectss
- Merge into 3.1
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~jelmer/brz/iterobjectss |
Merge into: | lp:brz/3.1 |
Diff against target: |
419 lines (+90/-198) 3 files modified
breezy/git/tests/test_workingtree.py (+20/-2) breezy/git/tree.py (+69/-195) breezy/git/workingtree.py (+1/-1) |
To merge this branch: | bzr merge lp:~jelmer/brz/iterobjectss |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+388958@code.launchpad.net |
Commit message
Simplify InterTree handling for Git trees.
Description of the change
Simplify InterTree handling for Git trees.
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/git/tests/test_workingtree.py' | |||
2 | --- breezy/git/tests/test_workingtree.py 2020-08-06 01:40:59 +0000 | |||
3 | +++ breezy/git/tests/test_workingtree.py 2020-08-08 18:37:30 +0000 | |||
4 | @@ -23,8 +23,11 @@ | |||
5 | 23 | import stat | 23 | import stat |
6 | 24 | 24 | ||
7 | 25 | from dulwich import __version__ as dulwich_version | 25 | from dulwich import __version__ as dulwich_version |
9 | 26 | from dulwich.diff_tree import RenameDetector | 26 | from dulwich.diff_tree import RenameDetector, tree_changes |
10 | 27 | from dulwich.index import IndexEntry | 27 | from dulwich.index import IndexEntry |
11 | 28 | from dulwich.object_store import ( | ||
12 | 29 | OverlayObjectStore, | ||
13 | 30 | ) | ||
14 | 28 | from dulwich.objects import ( | 31 | from dulwich.objects import ( |
15 | 29 | S_IFGITLINK, | 32 | S_IFGITLINK, |
16 | 30 | Blob, | 33 | Blob, |
17 | @@ -42,7 +45,6 @@ | |||
18 | 42 | default_mapping, | 45 | default_mapping, |
19 | 43 | ) | 46 | ) |
20 | 44 | from ..tree import ( | 47 | from ..tree import ( |
21 | 45 | changes_between_git_tree_and_working_copy, | ||
22 | 46 | tree_delta_from_git_changes, | 48 | tree_delta_from_git_changes, |
23 | 47 | ) | 49 | ) |
24 | 48 | from ..workingtree import ( | 50 | from ..workingtree import ( |
25 | @@ -54,6 +56,22 @@ | |||
26 | 54 | ) | 56 | ) |
27 | 55 | 57 | ||
28 | 56 | 58 | ||
29 | 59 | def changes_between_git_tree_and_working_copy(source_store, from_tree_sha, target, | ||
30 | 60 | want_unchanged=False, | ||
31 | 61 | want_unversioned=False, | ||
32 | 62 | rename_detector=None, | ||
33 | 63 | include_trees=True): | ||
34 | 64 | """Determine the changes between a git tree and a working tree with index. | ||
35 | 65 | |||
36 | 66 | """ | ||
37 | 67 | to_tree_sha, extras = target.git_snapshot(want_unversioned=want_unversioned) | ||
38 | 68 | store = OverlayObjectStore([source_store, target.store]) | ||
39 | 69 | return tree_changes( | ||
40 | 70 | store, from_tree_sha, to_tree_sha, include_trees=include_trees, | ||
41 | 71 | rename_detector=rename_detector, | ||
42 | 72 | want_unchanged=want_unchanged, change_type_same=True), extras | ||
43 | 73 | |||
44 | 74 | |||
45 | 57 | class GitWorkingTreeTests(TestCaseWithTransport): | 75 | class GitWorkingTreeTests(TestCaseWithTransport): |
46 | 58 | 76 | ||
47 | 59 | def setUp(self): | 77 | def setUp(self): |
48 | 60 | 78 | ||
49 | === modified file 'breezy/git/tree.py' | |||
50 | --- breezy/git/tree.py 2020-08-07 00:29:47 +0000 | |||
51 | +++ breezy/git/tree.py 2020-08-08 18:37:30 +0000 | |||
52 | @@ -264,7 +264,24 @@ | |||
53 | 264 | return path | 264 | return path |
54 | 265 | 265 | ||
55 | 266 | 266 | ||
57 | 267 | class GitRevisionTree(revisiontree.RevisionTree): | 267 | class GitTree(_mod_tree.Tree): |
58 | 268 | |||
59 | 269 | def iter_git_objects(self): | ||
60 | 270 | """Iterate over all the objects in the tree. | ||
61 | 271 | |||
62 | 272 | :return :Yields tuples with (path, sha, mode) | ||
63 | 273 | """ | ||
64 | 274 | raise NotImplementedError(self.iter_git_objects) | ||
65 | 275 | |||
66 | 276 | def git_snapshot(self): | ||
67 | 277 | """Snapshot a tree, and return tree object. | ||
68 | 278 | |||
69 | 279 | :return: Tree sha and set of extras | ||
70 | 280 | """ | ||
71 | 281 | raise NotImplementedError(self.snapshot) | ||
72 | 282 | |||
73 | 283 | |||
74 | 284 | class GitRevisionTree(revisiontree.RevisionTree, GitTree): | ||
75 | 268 | """Revision tree implementation based on Git objects.""" | 285 | """Revision tree implementation based on Git objects.""" |
76 | 269 | 286 | ||
77 | 270 | def __init__(self, repository, revision_id): | 287 | def __init__(self, repository, revision_id): |
78 | @@ -286,6 +303,9 @@ | |||
79 | 286 | raise errors.NoSuchRevision(repository, revision_id) | 303 | raise errors.NoSuchRevision(repository, revision_id) |
80 | 287 | self.tree = commit.tree | 304 | self.tree = commit.tree |
81 | 288 | 305 | ||
82 | 306 | def git_snapshot(self, want_unversioned=False): | ||
83 | 307 | return self.tree, set() | ||
84 | 308 | |||
85 | 289 | def _submodule_info(self): | 309 | def _submodule_info(self): |
86 | 290 | if self._submodules is None: | 310 | if self._submodules is None: |
87 | 291 | try: | 311 | try: |
88 | @@ -977,10 +997,18 @@ | |||
89 | 977 | _matching_to_tree_format = None | 997 | _matching_to_tree_format = None |
90 | 978 | _test_mutable_trees_to_test_trees = None | 998 | _test_mutable_trees_to_test_trees = None |
91 | 979 | 999 | ||
92 | 1000 | def __init__(self, source, target): | ||
93 | 1001 | super(InterGitTrees, self).__init__(source, target) | ||
94 | 1002 | if self.source.store == self.target.store: | ||
95 | 1003 | self.store = self.source.store | ||
96 | 1004 | else: | ||
97 | 1005 | self.store = OverlayObjectStore( | ||
98 | 1006 | [self.source.store, self.target.store]) | ||
99 | 1007 | self.rename_detector = RenameDetector(self.store) | ||
100 | 1008 | |||
101 | 980 | @classmethod | 1009 | @classmethod |
102 | 981 | def is_compatible(cls, source, target): | 1010 | def is_compatible(cls, source, target): |
105 | 982 | return (isinstance(source, GitRevisionTree) and | 1011 | return isinstance(source, GitTree) and isinstance(target, GitTree) |
104 | 983 | isinstance(target, GitRevisionTree)) | ||
106 | 984 | 1012 | ||
107 | 985 | def compare(self, want_unchanged=False, specific_files=None, | 1013 | def compare(self, want_unchanged=False, specific_files=None, |
108 | 986 | extra_trees=None, require_versioned=False, include_root=False, | 1014 | extra_trees=None, require_versioned=False, include_root=False, |
109 | @@ -1018,7 +1046,25 @@ | |||
110 | 1018 | def _iter_git_changes(self, want_unchanged=False, specific_files=None, | 1046 | def _iter_git_changes(self, want_unchanged=False, specific_files=None, |
111 | 1019 | require_versioned=False, extra_trees=None, | 1047 | require_versioned=False, extra_trees=None, |
112 | 1020 | want_unversioned=False, include_trees=True): | 1048 | want_unversioned=False, include_trees=True): |
114 | 1021 | raise NotImplementedError(self._iter_git_changes) | 1049 | trees = [self.source] |
115 | 1050 | if extra_trees is not None: | ||
116 | 1051 | trees.extend(extra_trees) | ||
117 | 1052 | if specific_files is not None: | ||
118 | 1053 | specific_files = self.target.find_related_paths_across_trees( | ||
119 | 1054 | specific_files, trees, | ||
120 | 1055 | require_versioned=require_versioned) | ||
121 | 1056 | # TODO(jelmer): Restrict to specific_files, for performance reasons. | ||
122 | 1057 | with self.lock_read(): | ||
123 | 1058 | from_tree_sha, from_extras = self.source.git_snapshot( | ||
124 | 1059 | want_unversioned=want_unversioned) | ||
125 | 1060 | to_tree_sha, to_extras = self.target.git_snapshot( | ||
126 | 1061 | want_unversioned=want_unversioned) | ||
127 | 1062 | changes = tree_changes( | ||
128 | 1063 | self.store, from_tree_sha, to_tree_sha, | ||
129 | 1064 | include_trees=include_trees, | ||
130 | 1065 | rename_detector=self.rename_detector, | ||
131 | 1066 | want_unchanged=want_unchanged, change_type_same=True) | ||
132 | 1067 | return changes, from_extras, to_extras | ||
133 | 1022 | 1068 | ||
134 | 1023 | def find_target_path(self, path, recurse='none'): | 1069 | def find_target_path(self, path, recurse='none'): |
135 | 1024 | ret = self.find_target_paths([path], recurse=recurse) | 1070 | ret = self.find_target_paths([path], recurse=recurse) |
136 | @@ -1073,48 +1119,10 @@ | |||
137 | 1073 | return ret | 1119 | return ret |
138 | 1074 | 1120 | ||
139 | 1075 | 1121 | ||
182 | 1076 | class InterGitRevisionTrees(InterGitTrees): | 1122 | _mod_tree.InterTree.register_optimiser(InterGitTrees) |
183 | 1077 | """InterTree that works between two git revision trees.""" | 1123 | |
184 | 1078 | 1124 | ||
185 | 1079 | _matching_from_tree_format = None | 1125 | class MutableGitIndexTree(mutabletree.MutableTree, GitTree): |
144 | 1080 | _matching_to_tree_format = None | ||
145 | 1081 | _test_mutable_trees_to_test_trees = None | ||
146 | 1082 | |||
147 | 1083 | @classmethod | ||
148 | 1084 | def is_compatible(cls, source, target): | ||
149 | 1085 | return (isinstance(source, GitRevisionTree) and | ||
150 | 1086 | isinstance(target, GitRevisionTree)) | ||
151 | 1087 | |||
152 | 1088 | def _iter_git_changes(self, want_unchanged=False, specific_files=None, | ||
153 | 1089 | require_versioned=True, extra_trees=None, | ||
154 | 1090 | want_unversioned=False, include_trees=True): | ||
155 | 1091 | trees = [self.source] | ||
156 | 1092 | if extra_trees is not None: | ||
157 | 1093 | trees.extend(extra_trees) | ||
158 | 1094 | if specific_files is not None: | ||
159 | 1095 | specific_files = self.target.find_related_paths_across_trees( | ||
160 | 1096 | specific_files, trees, | ||
161 | 1097 | require_versioned=require_versioned) | ||
162 | 1098 | |||
163 | 1099 | if (self.source._repository._git.object_store != | ||
164 | 1100 | self.target._repository._git.object_store): | ||
165 | 1101 | store = OverlayObjectStore( | ||
166 | 1102 | [self.source._repository._git.object_store, | ||
167 | 1103 | self.target._repository._git.object_store]) | ||
168 | 1104 | else: | ||
169 | 1105 | store = self.source._repository._git.object_store | ||
170 | 1106 | rename_detector = RenameDetector(store) | ||
171 | 1107 | changes = tree_changes( | ||
172 | 1108 | store, self.source.tree, self.target.tree, | ||
173 | 1109 | want_unchanged=want_unchanged, include_trees=include_trees, | ||
174 | 1110 | change_type_same=True, rename_detector=rename_detector) | ||
175 | 1111 | return changes, set(), set() | ||
176 | 1112 | |||
177 | 1113 | |||
178 | 1114 | _mod_tree.InterTree.register_optimiser(InterGitRevisionTrees) | ||
179 | 1115 | |||
180 | 1116 | |||
181 | 1117 | class MutableGitIndexTree(mutabletree.MutableTree): | ||
186 | 1118 | 1126 | ||
187 | 1119 | def __init__(self): | 1127 | def __init__(self): |
188 | 1120 | self._lock_mode = None | 1128 | self._lock_mode = None |
189 | @@ -1123,6 +1131,9 @@ | |||
190 | 1123 | self._index_dirty = False | 1131 | self._index_dirty = False |
191 | 1124 | self._submodules = None | 1132 | self._submodules = None |
192 | 1125 | 1133 | ||
193 | 1134 | def git_snapshot(self, want_unversioned=False): | ||
194 | 1135 | return snapshot_workingtree(self, want_unversioned=want_unversioned) | ||
195 | 1136 | |||
196 | 1126 | def is_versioned(self, path): | 1137 | def is_versioned(self, path): |
197 | 1127 | with self.lock_read(): | 1138 | with self.lock_read(): |
198 | 1128 | path = encode_git_path(path.rstrip('/')) | 1139 | path = encode_git_path(path.rstrip('/')) |
199 | @@ -1142,7 +1153,7 @@ | |||
200 | 1142 | if self._lock_mode is None: | 1153 | if self._lock_mode is None: |
201 | 1143 | raise errors.ObjectNotLocked(self) | 1154 | raise errors.ObjectNotLocked(self) |
202 | 1144 | self._versioned_dirs = set() | 1155 | self._versioned_dirs = set() |
204 | 1145 | for p, i in self._recurse_index_entries(): | 1156 | for p, sha, mode in self.iter_git_objects(): |
205 | 1146 | self._ensure_versioned_dir(posixpath.dirname(p)) | 1157 | self._ensure_versioned_dir(posixpath.dirname(p)) |
206 | 1147 | 1158 | ||
207 | 1148 | def _ensure_versioned_dir(self, dirname): | 1159 | def _ensure_versioned_dir(self, dirname): |
208 | @@ -1301,6 +1312,10 @@ | |||
209 | 1301 | if self._versioned_dirs is not None: | 1312 | if self._versioned_dirs is not None: |
210 | 1302 | self._ensure_versioned_dir(index_path) | 1313 | self._ensure_versioned_dir(index_path) |
211 | 1303 | 1314 | ||
212 | 1315 | def iter_git_objects(self): | ||
213 | 1316 | for p, entry in self._recurse_index_entries(): | ||
214 | 1317 | yield p, entry.sha, entry.mode | ||
215 | 1318 | |||
216 | 1304 | def _recurse_index_entries(self, index=None, basepath=b"", | 1319 | def _recurse_index_entries(self, index=None, basepath=b"", |
217 | 1305 | recurse_nested=False): | 1320 | recurse_nested=False): |
218 | 1306 | # Iterate over all index entries | 1321 | # Iterate over all index entries |
219 | @@ -1398,7 +1413,7 @@ | |||
220 | 1398 | if data is None: | 1413 | if data is None: |
221 | 1399 | data = self.branch.repository._git.object_store[sha].data | 1414 | data = self.branch.repository._git.object_store[sha].data |
222 | 1400 | ie.text_sha1 = osutils.sha_string(data) | 1415 | ie.text_sha1 = osutils.sha_string(data) |
224 | 1401 | ie.text_size = len(data) | 1416 | ie.text_size = size |
225 | 1402 | ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode) | 1417 | ie.executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode) |
226 | 1403 | return ie | 1418 | return ie |
227 | 1404 | 1419 | ||
228 | @@ -1687,131 +1702,6 @@ | |||
229 | 1687 | return True | 1702 | return True |
230 | 1688 | 1703 | ||
231 | 1689 | 1704 | ||
232 | 1690 | class InterToIndexGitTree(InterGitTrees): | ||
233 | 1691 | """InterTree that works between a Git revision tree and an index.""" | ||
234 | 1692 | |||
235 | 1693 | def __init__(self, source, target): | ||
236 | 1694 | super(InterToIndexGitTree, self).__init__(source, target) | ||
237 | 1695 | if self.source.store == self.target.store: | ||
238 | 1696 | self.store = self.source.store | ||
239 | 1697 | else: | ||
240 | 1698 | self.store = OverlayObjectStore( | ||
241 | 1699 | [self.source.store, self.target.store]) | ||
242 | 1700 | self.rename_detector = RenameDetector(self.store) | ||
243 | 1701 | |||
244 | 1702 | @classmethod | ||
245 | 1703 | def is_compatible(cls, source, target): | ||
246 | 1704 | return (isinstance(source, GitRevisionTree) and | ||
247 | 1705 | isinstance(target, MutableGitIndexTree)) | ||
248 | 1706 | |||
249 | 1707 | def _iter_git_changes(self, want_unchanged=False, specific_files=None, | ||
250 | 1708 | require_versioned=False, extra_trees=None, | ||
251 | 1709 | want_unversioned=False, include_trees=True): | ||
252 | 1710 | trees = [self.source] | ||
253 | 1711 | if extra_trees is not None: | ||
254 | 1712 | trees.extend(extra_trees) | ||
255 | 1713 | if specific_files is not None: | ||
256 | 1714 | specific_files = self.target.find_related_paths_across_trees( | ||
257 | 1715 | specific_files, trees, | ||
258 | 1716 | require_versioned=require_versioned) | ||
259 | 1717 | # TODO(jelmer): Restrict to specific_files, for performance reasons. | ||
260 | 1718 | with self.lock_read(): | ||
261 | 1719 | changes, target_extras = changes_between_git_tree_and_working_copy( | ||
262 | 1720 | self.source.store, self.source.tree, | ||
263 | 1721 | self.target, want_unchanged=want_unchanged, | ||
264 | 1722 | want_unversioned=want_unversioned, | ||
265 | 1723 | rename_detector=self.rename_detector, | ||
266 | 1724 | include_trees=include_trees) | ||
267 | 1725 | return changes, set(), target_extras | ||
268 | 1726 | |||
269 | 1727 | |||
270 | 1728 | _mod_tree.InterTree.register_optimiser(InterToIndexGitTree) | ||
271 | 1729 | |||
272 | 1730 | |||
273 | 1731 | class InterFromIndexGitTree(InterGitTrees): | ||
274 | 1732 | """InterTree that works between a Git revision tree and an index.""" | ||
275 | 1733 | |||
276 | 1734 | def __init__(self, source, target): | ||
277 | 1735 | super(InterFromIndexGitTree, self).__init__(source, target) | ||
278 | 1736 | if self.source.store == self.target.store: | ||
279 | 1737 | self.store = self.source.store | ||
280 | 1738 | else: | ||
281 | 1739 | self.store = OverlayObjectStore( | ||
282 | 1740 | [self.source.store, self.target.store]) | ||
283 | 1741 | self.rename_detector = RenameDetector(self.store) | ||
284 | 1742 | |||
285 | 1743 | @classmethod | ||
286 | 1744 | def is_compatible(cls, source, target): | ||
287 | 1745 | return (isinstance(target, GitRevisionTree) and | ||
288 | 1746 | isinstance(source, MutableGitIndexTree)) | ||
289 | 1747 | |||
290 | 1748 | def _iter_git_changes(self, want_unchanged=False, specific_files=None, | ||
291 | 1749 | require_versioned=False, extra_trees=None, | ||
292 | 1750 | want_unversioned=False, include_trees=True): | ||
293 | 1751 | trees = [self.source] | ||
294 | 1752 | if extra_trees is not None: | ||
295 | 1753 | trees.extend(extra_trees) | ||
296 | 1754 | if specific_files is not None: | ||
297 | 1755 | specific_files = self.target.find_related_paths_across_trees( | ||
298 | 1756 | specific_files, trees, | ||
299 | 1757 | require_versioned=require_versioned) | ||
300 | 1758 | # TODO(jelmer): Restrict to specific_files, for performance reasons. | ||
301 | 1759 | with self.lock_read(): | ||
302 | 1760 | from_tree_sha, extras = snapshot_workingtree(self.source, want_unversioned=want_unversioned) | ||
303 | 1761 | return tree_changes( | ||
304 | 1762 | self.store, from_tree_sha, self.target.tree, | ||
305 | 1763 | include_trees=include_trees, | ||
306 | 1764 | rename_detector=self.rename_detector, | ||
307 | 1765 | want_unchanged=want_unchanged, change_type_same=True), extras | ||
308 | 1766 | |||
309 | 1767 | |||
310 | 1768 | _mod_tree.InterTree.register_optimiser(InterFromIndexGitTree) | ||
311 | 1769 | |||
312 | 1770 | |||
313 | 1771 | class InterIndexGitTree(InterGitTrees): | ||
314 | 1772 | """InterTree that works between a Git revision tree and an index.""" | ||
315 | 1773 | |||
316 | 1774 | def __init__(self, source, target): | ||
317 | 1775 | super(InterIndexGitTree, self).__init__(source, target) | ||
318 | 1776 | if self.source.store == self.target.store: | ||
319 | 1777 | self.store = self.source.store | ||
320 | 1778 | else: | ||
321 | 1779 | self.store = OverlayObjectStore( | ||
322 | 1780 | [self.source.store, self.target.store]) | ||
323 | 1781 | self.rename_detector = RenameDetector(self.store) | ||
324 | 1782 | |||
325 | 1783 | @classmethod | ||
326 | 1784 | def is_compatible(cls, source, target): | ||
327 | 1785 | return (isinstance(target, MutableGitIndexTree) and | ||
328 | 1786 | isinstance(source, MutableGitIndexTree)) | ||
329 | 1787 | |||
330 | 1788 | def _iter_git_changes(self, want_unchanged=False, specific_files=None, | ||
331 | 1789 | require_versioned=False, extra_trees=None, | ||
332 | 1790 | want_unversioned=False, include_trees=True): | ||
333 | 1791 | trees = [self.source] | ||
334 | 1792 | if extra_trees is not None: | ||
335 | 1793 | trees.extend(extra_trees) | ||
336 | 1794 | if specific_files is not None: | ||
337 | 1795 | specific_files = self.target.find_related_paths_across_trees( | ||
338 | 1796 | specific_files, trees, | ||
339 | 1797 | require_versioned=require_versioned) | ||
340 | 1798 | # TODO(jelmer): Restrict to specific_files, for performance reasons. | ||
341 | 1799 | with self.lock_read(): | ||
342 | 1800 | from_tree_sha, from_extras = snapshot_workingtree( | ||
343 | 1801 | self.source, want_unversioned=want_unversioned) | ||
344 | 1802 | to_tree_sha, to_extras = snapshot_workingtree( | ||
345 | 1803 | self.target, want_unversioned=want_unversioned) | ||
346 | 1804 | changes = tree_changes( | ||
347 | 1805 | self.store, from_tree_sha, to_tree_sha, | ||
348 | 1806 | include_trees=include_trees, | ||
349 | 1807 | rename_detector=self.rename_detector, | ||
350 | 1808 | want_unchanged=want_unchanged, change_type_same=True) | ||
351 | 1809 | return changes, from_extras, to_extras | ||
352 | 1810 | |||
353 | 1811 | |||
354 | 1812 | _mod_tree.InterTree.register_optimiser(InterIndexGitTree) | ||
355 | 1813 | |||
356 | 1814 | |||
357 | 1815 | def snapshot_workingtree(target, want_unversioned=False): | 1705 | def snapshot_workingtree(target, want_unversioned=False): |
358 | 1816 | extras = set() | 1706 | extras = set() |
359 | 1817 | blobs = {} | 1707 | blobs = {} |
360 | @@ -1859,21 +1749,21 @@ | |||
361 | 1859 | target.store.add_object(blob) | 1749 | target.store.add_object(blob) |
362 | 1860 | blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode)) | 1750 | blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode)) |
363 | 1861 | if want_unversioned: | 1751 | if want_unversioned: |
365 | 1862 | for e in target._iter_files_recursive(include_dirs=False): | 1752 | for extra in target._iter_files_recursive(include_dirs=False): |
366 | 1863 | try: | 1753 | try: |
368 | 1864 | e, accessible = osutils.normalized_filename(e) | 1754 | extra, accessible = osutils.normalized_filename(extra) |
369 | 1865 | except UnicodeDecodeError: | 1755 | except UnicodeDecodeError: |
370 | 1866 | raise errors.BadFilenameEncoding( | 1756 | raise errors.BadFilenameEncoding( |
373 | 1867 | e, osutils._fs_enc) | 1757 | extra, osutils._fs_enc) |
374 | 1868 | np = encode_git_path(e) | 1758 | np = encode_git_path(extra) |
375 | 1869 | if np in blobs: | 1759 | if np in blobs: |
376 | 1870 | continue | 1760 | continue |
378 | 1871 | st = target._lstat(e) | 1761 | st = target._lstat(extra) |
379 | 1872 | if stat.S_ISDIR(st.st_mode): | 1762 | if stat.S_ISDIR(st.st_mode): |
380 | 1873 | blob = Tree() | 1763 | blob = Tree() |
381 | 1874 | elif stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode): | 1764 | elif stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode): |
382 | 1875 | blob = blob_from_path_and_stat( | 1765 | blob = blob_from_path_and_stat( |
384 | 1876 | target.abspath(e).encode(osutils._fs_enc), st) | 1766 | target.abspath(extra).encode(osutils._fs_enc), st) |
385 | 1877 | else: | 1767 | else: |
386 | 1878 | continue | 1768 | continue |
387 | 1879 | target.store.add_object(blob) | 1769 | target.store.add_object(blob) |
388 | @@ -1881,19 +1771,3 @@ | |||
389 | 1881 | extras.add(np) | 1771 | extras.add(np) |
390 | 1882 | return commit_tree( | 1772 | return commit_tree( |
391 | 1883 | target.store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()]), extras | 1773 | target.store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()]), extras |
392 | 1884 | |||
393 | 1885 | |||
394 | 1886 | def changes_between_git_tree_and_working_copy(source_store, from_tree_sha, target, | ||
395 | 1887 | want_unchanged=False, | ||
396 | 1888 | want_unversioned=False, | ||
397 | 1889 | rename_detector=None, | ||
398 | 1890 | include_trees=True): | ||
399 | 1891 | """Determine the changes between a git tree and a working tree with index. | ||
400 | 1892 | |||
401 | 1893 | """ | ||
402 | 1894 | to_tree_sha, extras = snapshot_workingtree(target, want_unversioned=want_unversioned) | ||
403 | 1895 | store = OverlayObjectStore([source_store, target.store]) | ||
404 | 1896 | return tree_changes( | ||
405 | 1897 | store, from_tree_sha, to_tree_sha, include_trees=include_trees, | ||
406 | 1898 | rename_detector=rename_detector, | ||
407 | 1899 | want_unchanged=want_unchanged, change_type_same=True), extras | ||
408 | 1900 | 1774 | ||
409 | === modified file 'breezy/git/workingtree.py' | |||
410 | --- breezy/git/workingtree.py 2020-08-06 22:01:46 +0000 | |||
411 | +++ breezy/git/workingtree.py 2020-08-08 18:37:30 +0000 | |||
412 | @@ -572,7 +572,7 @@ | |||
413 | 572 | """ | 572 | """ |
414 | 573 | with self.lock_read(): | 573 | with self.lock_read(): |
415 | 574 | index_paths = set( | 574 | index_paths = set( |
417 | 575 | [decode_git_path(p) for p, i in self._recurse_index_entries()]) | 575 | [decode_git_path(p) for p, sha, mode in self.iter_git_objects()]) |
418 | 576 | all_paths = set(self._iter_files_recursive(include_dirs=False)) | 576 | all_paths = set(self._iter_files_recursive(include_dirs=False)) |
419 | 577 | return iter(all_paths - index_paths) | 577 | return iter(all_paths - index_paths) |
420 | 578 | 578 |