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/renames | ||||
Merge into: | lp:brz/3.1 | ||||
Diff against target: |
554 lines (+191/-66) 7 files modified
breezy/builtins.py (+1/-1) breezy/commit.py (+2/-2) breezy/git/commit.py (+8/-5) breezy/git/tests/test_workingtree.py (+100/-27) breezy/git/tree.py (+56/-19) breezy/tests/per_repository/test_commit_builder.py (+21/-8) doc/en/release-notes/brz-3.1.txt (+3/-4) |
||||
To merge this branch: | bzr merge lp:~jelmer/brz/renames | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jelmer Vernooij | Approve | ||
Review via email: mp+381006@code.launchpad.net |
This proposal supersedes a proposal from 2020-01-26.
Commit message
Support Git rename tracking.
Description of the change
Support Git rename tracking.
To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) : Posted in a previous version of this proposal | # |
review:
Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : Posted in a previous version of this proposal | # |
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : Posted in a previous version of this proposal | # |
Merging failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Voting criteria not met
https:/
Revision history for this message
Jelmer Vernooij (jelmer) : | # |
review:
Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/builtins.py' |
2 | --- breezy/builtins.py 2020-04-02 01:37:43 +0000 |
3 | +++ breezy/builtins.py 2020-06-16 23:49:21 +0000 |
4 | @@ -4233,7 +4233,7 @@ |
5 | |
6 | try: |
7 | from . import tests |
8 | - except ImportError: |
9 | + except ImportError as e: |
10 | raise errors.BzrCommandError("tests not available. Install the " |
11 | "breezy tests to run the breezy testsuite.") |
12 | |
13 | |
14 | === modified file 'breezy/commit.py' |
15 | --- breezy/commit.py 2019-09-21 17:08:09 +0000 |
16 | +++ breezy/commit.py 2020-06-16 23:49:21 +0000 |
17 | @@ -440,8 +440,8 @@ |
18 | # as updating its basis and unversioning paths that were missing. |
19 | self.work_tree.unversion(self.deleted_paths) |
20 | self._set_progress_stage("Updating the working tree") |
21 | - self.work_tree.update_basis_by_delta(self.rev_id, |
22 | - self.builder.get_basis_delta()) |
23 | + self.work_tree.update_basis_by_delta( |
24 | + self.rev_id, self.builder.get_basis_delta()) |
25 | self.reporter.completed(new_revno, self.rev_id) |
26 | self._process_post_hooks(old_revno, new_revno) |
27 | return self.rev_id |
28 | |
29 | === modified file 'breezy/git/commit.py' |
30 | --- breezy/git/commit.py 2020-01-30 15:48:47 +0000 |
31 | +++ breezy/git/commit.py 2020-06-16 23:49:21 +0000 |
32 | @@ -69,6 +69,7 @@ |
33 | self.store = self.repository._git.object_store |
34 | self._blobs = {} |
35 | self._inv_delta = [] |
36 | + self._deleted_paths = set() |
37 | self._any_changes = False |
38 | self._mapping = self.repository.get_mapping() |
39 | |
40 | @@ -92,7 +93,7 @@ |
41 | self._any_changes = True |
42 | if change.path[1] is None: |
43 | self._inv_delta.append((change.path[0], change.path[1], change.file_id, None)) |
44 | - self._blobs[change.path[0].encode("utf-8")] = None |
45 | + self._deleted_paths.add(change.path[0].encode("utf-8")) |
46 | continue |
47 | try: |
48 | entry_kls = entry_factory[change.kind[1]] |
49 | @@ -128,8 +129,9 @@ |
50 | raise AssertionError("Unknown kind %r" % change.kind[1]) |
51 | mode = object_mode(change.kind[1], change.executable[1]) |
52 | self._inv_delta.append((change.path[0], change.path[1], change.file_id, entry)) |
53 | - encoded_new_path = change.path[1].encode("utf-8") |
54 | - self._blobs[encoded_new_path] = (mode, sha) |
55 | + if change.path[0] is not None: |
56 | + self._deleted_paths.add(change.path[0].encode("utf-8")) |
57 | + self._blobs[change.path[1].encode("utf-8")] = (mode, sha) |
58 | if st is not None: |
59 | yield change.path[1], (entry.text_sha1, st) |
60 | if not seen_root and len(self.parents) == 0: |
61 | @@ -146,6 +148,8 @@ |
62 | for entry in basis_tree._iter_tree_contents(include_trees=False): |
63 | if entry.path in self._blobs: |
64 | continue |
65 | + if entry.path in self._deleted_paths: |
66 | + continue |
67 | self._blobs[entry.path] = (entry.mode, entry.sha) |
68 | self.new_inventory = None |
69 | |
70 | @@ -155,8 +159,7 @@ |
71 | |
72 | def finish_inventory(self): |
73 | # eliminate blobs that were removed |
74 | - self._blobs = {k: v for (k, v) in viewitems( |
75 | - self._blobs) if v is not None} |
76 | + self._blobs = {k: v for (k, v) in viewitems(self._blobs)} |
77 | |
78 | def _iterblobs(self): |
79 | return ((path, sha, mode) for (path, (mode, sha)) |
80 | |
81 | === modified file 'breezy/git/tests/test_workingtree.py' |
82 | --- breezy/git/tests/test_workingtree.py 2020-01-19 15:14:16 +0000 |
83 | +++ breezy/git/tests/test_workingtree.py 2020-06-16 23:49:21 +0000 |
84 | @@ -22,6 +22,8 @@ |
85 | import os |
86 | import stat |
87 | |
88 | +from dulwich import __version__ as dulwich_version |
89 | +from dulwich.diff_tree import RenameDetector |
90 | from dulwich.index import IndexEntry |
91 | from dulwich.objects import ( |
92 | S_IFGITLINK, |
93 | @@ -141,9 +143,15 @@ |
94 | |
95 | def test_missing(self): |
96 | delta = TreeDelta() |
97 | - delta.removed.append(TreeChange(b'git:a', ('a', 'a'), False, (True, True), (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', None), (True, False))) |
98 | - changes = [((b'a', b'a'), (stat.S_IFREG | 0o755, 0), |
99 | - (b'a' * 40, b'a' * 40))] |
100 | + delta.removed.append( |
101 | + TreeChange( |
102 | + b'git:a', ('a', 'a'), False, (True, True), |
103 | + (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', None), |
104 | + (True, False))) |
105 | + changes = [ |
106 | + ('remove', |
107 | + (b'a', stat.S_IFREG | 0o755, b'a' * 40), |
108 | + (b'a', 0, b'a' * 40))] |
109 | self.assertEqual( |
110 | delta, |
111 | tree_delta_from_git_changes(changes, (default_mapping, default_mapping))) |
112 | @@ -158,7 +166,7 @@ |
113 | |
114 | def expectDelta(self, expected_changes, |
115 | expected_extras=None, want_unversioned=False, |
116 | - tree_id=None): |
117 | + tree_id=None, rename_detector=None): |
118 | if tree_id is None: |
119 | try: |
120 | tree_id = self.store[self.wt.branch.repository._git.head()].tree |
121 | @@ -166,7 +174,8 @@ |
122 | tree_id = None |
123 | with self.wt.lock_read(): |
124 | changes, extras = changes_between_git_tree_and_working_copy( |
125 | - self.store, tree_id, self.wt, want_unversioned=want_unversioned) |
126 | + self.store, tree_id, self.wt, want_unversioned=want_unversioned, |
127 | + rename_detector=rename_detector) |
128 | self.assertEqual(expected_changes, list(changes)) |
129 | if expected_extras is None: |
130 | expected_extras = set() |
131 | @@ -174,7 +183,7 @@ |
132 | |
133 | def test_empty(self): |
134 | self.expectDelta( |
135 | - [((None, b''), (None, stat.S_IFDIR), (None, Tree().id))]) |
136 | + [('add', (None, None, None), (b'', stat.S_IFDIR, Tree().id))]) |
137 | |
138 | def test_added_file(self): |
139 | self.build_tree(['a']) |
140 | @@ -183,20 +192,74 @@ |
141 | t = Tree() |
142 | t.add(b"a", stat.S_IFREG | 0o644, a.id) |
143 | self.expectDelta( |
144 | - [((None, b''), (None, stat.S_IFDIR), (None, t.id)), |
145 | - ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, a.id))]) |
146 | + [('add', (None, None, None), (b'', stat.S_IFDIR, t.id)), |
147 | + ('add', (None, None, None), (b'a', stat.S_IFREG | 0o644, a.id))]) |
148 | + |
149 | + def test_renamed_file(self): |
150 | + self.build_tree(['a']) |
151 | + self.wt.add(['a']) |
152 | + self.wt.rename_one('a', 'b') |
153 | + a = Blob.from_string(b'contents of a\n') |
154 | + self.store.add_object(a) |
155 | + oldt = Tree() |
156 | + oldt.add(b"a", stat.S_IFREG | 0o644, a.id) |
157 | + self.store.add_object(oldt) |
158 | + newt = Tree() |
159 | + newt.add(b"b", stat.S_IFREG | 0o644, a.id) |
160 | + self.store.add_object(newt) |
161 | + self.expectDelta( |
162 | + [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)), |
163 | + ('delete', (b'a', stat.S_IFREG | 0o644, a.id), (None, None, None)), |
164 | + ('add', (None, None, None), (b'b', stat.S_IFREG | 0o644, a.id)), |
165 | + ], |
166 | + tree_id=oldt.id) |
167 | + if dulwich_version >= (0, 19, 15): |
168 | + self.expectDelta( |
169 | + [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)), |
170 | + ('rename', (b'a', stat.S_IFREG | 0o644, a.id), (b'b', stat.S_IFREG | 0o644, a.id))], |
171 | + tree_id=oldt.id, rename_detector=RenameDetector(self.store)) |
172 | + |
173 | + def test_copied_file(self): |
174 | + self.build_tree(['a']) |
175 | + self.wt.add(['a']) |
176 | + self.wt.copy_one('a', 'b') |
177 | + a = Blob.from_string(b'contents of a\n') |
178 | + self.store.add_object(a) |
179 | + oldt = Tree() |
180 | + oldt.add(b"a", stat.S_IFREG | 0o644, a.id) |
181 | + self.store.add_object(oldt) |
182 | + newt = Tree() |
183 | + newt.add(b"a", stat.S_IFREG | 0o644, a.id) |
184 | + newt.add(b"b", stat.S_IFREG | 0o644, a.id) |
185 | + self.store.add_object(newt) |
186 | + self.expectDelta( |
187 | + [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)), |
188 | + ('add', (None, None, None), (b'b', stat.S_IFREG | 0o644, a.id)), |
189 | + ], |
190 | + tree_id=oldt.id) |
191 | + |
192 | + if dulwich_version >= (0, 19, 15): |
193 | + self.expectDelta( |
194 | + [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)), |
195 | + ('copy', (b'a', stat.S_IFREG | 0o644, a.id), (b'b', stat.S_IFREG | 0o644, a.id))], |
196 | + tree_id=oldt.id, rename_detector=RenameDetector(self.store, find_copies_harder=True)) |
197 | + self.expectDelta( |
198 | + [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)), |
199 | + ('add', (None, None, None), (b'b', stat.S_IFREG | 0o644, a.id)), |
200 | + ], |
201 | + tree_id=oldt.id, rename_detector=RenameDetector(self.store, find_copies_harder=False)) |
202 | |
203 | def test_added_unknown_file(self): |
204 | self.build_tree(['a']) |
205 | t = Tree() |
206 | self.expectDelta( |
207 | - [((None, b''), (None, stat.S_IFDIR), (None, t.id))]) |
208 | + [('add', (None, None, None), (b'', stat.S_IFDIR, t.id))]) |
209 | a = Blob.from_string(b'contents of a\n') |
210 | t = Tree() |
211 | t.add(b"a", stat.S_IFREG | 0o644, a.id) |
212 | self.expectDelta( |
213 | - [((None, b''), (None, stat.S_IFDIR), (None, t.id)), |
214 | - ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, a.id))], |
215 | + [('add', (None, None, None), (b'', stat.S_IFDIR, t.id)), |
216 | + ('add', (None, None, None), (b'a', stat.S_IFREG | 0o644, a.id))], |
217 | [b'a'], |
218 | want_unversioned=True) |
219 | |
220 | @@ -208,8 +271,8 @@ |
221 | t = Tree() |
222 | t.add(b"a", 0, ZERO_SHA) |
223 | self.expectDelta( |
224 | - [((None, b''), (None, stat.S_IFDIR), (None, t.id)), |
225 | - ((None, b'a'), (None, 0), (None, ZERO_SHA))], |
226 | + [('add', (None, None, None), (b'', stat.S_IFDIR, t.id)), |
227 | + ('add', (None, None, None), (b'a', 0, ZERO_SHA))], |
228 | []) |
229 | |
230 | def test_missing_versioned_file(self): |
231 | @@ -223,8 +286,12 @@ |
232 | newt = Tree() |
233 | newt.add(b"a", 0, ZERO_SHA) |
234 | self.expectDelta( |
235 | - [((b'', b''), (stat.S_IFDIR, stat.S_IFDIR), (oldt.id, newt.id)), |
236 | - ((b'a', b'a'), (stat.S_IFREG | 0o644, 0), (a.id, ZERO_SHA))]) |
237 | + [('modify', |
238 | + (b'', stat.S_IFDIR, oldt.id), |
239 | + (b'', stat.S_IFDIR, newt.id)), |
240 | + ('modify', |
241 | + (b'a', stat.S_IFREG | 0o644, a.id), |
242 | + (b'a', 0, ZERO_SHA))]) |
243 | |
244 | def test_versioned_replace_by_dir(self): |
245 | self.build_tree(['a']) |
246 | @@ -239,16 +306,20 @@ |
247 | newa = Tree() |
248 | newt.add(b"a", stat.S_IFDIR, newa.id) |
249 | self.expectDelta([ |
250 | - ((b'', b''), |
251 | - (stat.S_IFDIR, stat.S_IFDIR), |
252 | - (oldt.id, newt.id)), |
253 | - ((b'a', b'a'), (stat.S_IFREG | 0o644, stat.S_IFDIR), (olda.id, newa.id)) |
254 | + ('modify', |
255 | + (b'', stat.S_IFDIR, oldt.id), |
256 | + (b'', stat.S_IFDIR, newt.id)), |
257 | + ('modify', |
258 | + (b'a', stat.S_IFREG | 0o644, olda.id), |
259 | + (b'a', stat.S_IFDIR, newa.id)) |
260 | ], want_unversioned=False) |
261 | self.expectDelta([ |
262 | - ((b'', b''), |
263 | - (stat.S_IFDIR, stat.S_IFDIR), |
264 | - (oldt.id, newt.id)), |
265 | - ((b'a', b'a'), (stat.S_IFREG | 0o644, stat.S_IFDIR), (olda.id, newa.id)) |
266 | + ('modify', |
267 | + (b'', stat.S_IFDIR, oldt.id), |
268 | + (b'', stat.S_IFDIR, newt.id)), |
269 | + ('modify', |
270 | + (b'a', stat.S_IFREG | 0o644, olda.id), |
271 | + (b'a', stat.S_IFDIR, newa.id)), |
272 | ], want_unversioned=True) |
273 | |
274 | def test_extra(self): |
275 | @@ -257,10 +328,12 @@ |
276 | newt = Tree() |
277 | newt.add(b"a", stat.S_IFREG | 0o644, newa.id) |
278 | self.expectDelta([ |
279 | - ((None, b''), |
280 | - (None, stat.S_IFDIR), |
281 | - (None, newt.id)), |
282 | - ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, newa.id)) |
283 | + ('add', |
284 | + (None, None, None), |
285 | + (b'', stat.S_IFDIR, newt.id)), |
286 | + ('add', |
287 | + (None, None, None), |
288 | + (b'a', stat.S_IFREG | 0o644, newa.id)), |
289 | ], [b'a'], want_unversioned=True) |
290 | |
291 | def test_submodule(self): |
292 | |
293 | === modified file 'breezy/git/tree.py' |
294 | --- breezy/git/tree.py 2020-04-27 02:29:59 +0000 |
295 | +++ breezy/git/tree.py 2020-06-16 23:49:21 +0000 |
296 | @@ -28,7 +28,7 @@ |
297 | parse_submodules, |
298 | ConfigFile as GitConfigFile, |
299 | ) |
300 | -from dulwich.diff_tree import tree_changes |
301 | +from dulwich.diff_tree import tree_changes, RenameDetector |
302 | from dulwich.errors import NotTreeError |
303 | from dulwich.index import ( |
304 | blob_from_path_and_stat, |
305 | @@ -737,7 +737,9 @@ |
306 | target_extras = set() |
307 | ret = delta.TreeDelta() |
308 | added = [] |
309 | - for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes: |
310 | + for (change_type, old, new) in changes: |
311 | + (oldpath, oldmode, oldsha) = old |
312 | + (newpath, newmode, newsha) = new |
313 | if newpath == b'' and not include_root: |
314 | continue |
315 | if oldpath is not None: |
316 | @@ -809,13 +811,17 @@ |
317 | fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha), |
318 | (oldversioned, newversioned), |
319 | (oldparent, newparent), (oldname, newname), |
320 | - (oldkind, newkind), (oldexe, newexe)) |
321 | + (oldkind, newkind), (oldexe, newexe), |
322 | + copied=(change_type == 'copy')) |
323 | if oldpath is None: |
324 | added.append((newpath, newkind)) |
325 | elif newpath is None or newmode == 0: |
326 | ret.removed.append(change) |
327 | elif oldpath != newpath: |
328 | - ret.renamed.append(change) |
329 | + if change_type == 'copy': |
330 | + ret.copied.append(change) |
331 | + else: |
332 | + ret.renamed.append(change) |
333 | elif mode_kind(oldmode) != mode_kind(newmode): |
334 | ret.kind_changed.append(change) |
335 | elif oldsha != newsha or oldmode != newmode: |
336 | @@ -863,7 +869,9 @@ |
337 | """ |
338 | if target_extras is None: |
339 | target_extras = set() |
340 | - for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes: |
341 | + for (change_type, old, new) in changes: |
342 | + (oldpath, oldmode, oldsha) = old |
343 | + (newpath, newmode, newsha) = new |
344 | if oldpath is not None: |
345 | oldpath_decoded = oldpath.decode('utf-8') |
346 | else: |
347 | @@ -934,7 +942,8 @@ |
348 | fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha), |
349 | (oldversioned, newversioned), |
350 | (oldparent, newparent), (oldname, newname), |
351 | - (oldkind, newkind), (oldexe, newexe)) |
352 | + (oldkind, newkind), (oldexe, newexe), |
353 | + copied=(change_type == 'copy')) |
354 | |
355 | |
356 | class InterGitTrees(_mod_tree.InterTree): |
357 | @@ -997,7 +1006,9 @@ |
358 | paths = set(paths) |
359 | ret = {} |
360 | changes = self._iter_git_changes(specific_files=paths)[0] |
361 | - for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes: |
362 | + for (change_type, old, new) in changes: |
363 | + oldpath = old[0] |
364 | + newpath = new[0] |
365 | if oldpath in paths: |
366 | ret[oldpath] = newpath |
367 | for path in paths: |
368 | @@ -1015,7 +1026,9 @@ |
369 | paths = set(paths) |
370 | ret = {} |
371 | changes = self._iter_git_changes(specific_files=paths)[0] |
372 | - for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes: |
373 | + for (change_type, old, new) in changes: |
374 | + oldpath = old[0] |
375 | + newpath = new[0] |
376 | if newpath in paths: |
377 | ret[newpath] = oldpath |
378 | for path in paths: |
379 | @@ -1060,9 +1073,10 @@ |
380 | self.target._repository._git.object_store]) |
381 | else: |
382 | store = self.source._repository._git.object_store |
383 | - return store.tree_changes( |
384 | - self.source.tree, self.target.tree, want_unchanged=want_unchanged, |
385 | - include_trees=True, change_type_same=True), set() |
386 | + rename_detector = RenameDetector(store) |
387 | + return tree_changes( |
388 | + store, self.source.tree, self.target.tree, want_unchanged=want_unchanged, |
389 | + include_trees=True, change_type_same=True, rename_detector=rename_detector), set() |
390 | |
391 | |
392 | _mod_tree.InterTree.register_optimiser(InterGitRevisionTrees) |
393 | @@ -1601,6 +1615,12 @@ |
394 | def __init__(self, source, target): |
395 | super(InterIndexGitTree, self).__init__(source, target) |
396 | self._index = target.index |
397 | + if self.source.store == self.target.store: |
398 | + self.store = self.source.store |
399 | + else: |
400 | + self.store = OverlayObjectStore( |
401 | + [self.source.store, self.target.store]) |
402 | + self.rename_detector = RenameDetector(self.store) |
403 | |
404 | @classmethod |
405 | def is_compatible(cls, source, target): |
406 | @@ -1622,15 +1642,17 @@ |
407 | return changes_between_git_tree_and_working_copy( |
408 | self.source.store, self.source.tree, |
409 | self.target, want_unchanged=want_unchanged, |
410 | - want_unversioned=want_unversioned) |
411 | + want_unversioned=want_unversioned, |
412 | + rename_detector=self.rename_detector) |
413 | |
414 | |
415 | _mod_tree.InterTree.register_optimiser(InterIndexGitTree) |
416 | |
417 | |
418 | -def changes_between_git_tree_and_working_copy(store, from_tree_sha, target, |
419 | +def changes_between_git_tree_and_working_copy(source_store, from_tree_sha, target, |
420 | want_unchanged=False, |
421 | - want_unversioned=False): |
422 | + want_unversioned=False, |
423 | + rename_detector=None): |
424 | """Determine the changes between a git tree and a working tree with index. |
425 | |
426 | """ |
427 | @@ -1657,7 +1679,7 @@ |
428 | blobs[path] = (index_entry.sha, index_entry.mode) |
429 | else: |
430 | dirified.append((path, Tree().id, stat.S_IFDIR)) |
431 | - store.add_object(Tree()) |
432 | + target.store.add_object(Tree()) |
433 | else: |
434 | mode = live_entry.mode |
435 | if not trust_executable: |
436 | @@ -1665,6 +1687,19 @@ |
437 | mode |= 0o111 |
438 | else: |
439 | mode &= ~0o111 |
440 | + if live_entry.sha != index_entry.sha: |
441 | + rp = path.decode('utf-8') |
442 | + if stat.S_ISREG(live_entry.mode): |
443 | + blob = Blob() |
444 | + with target.get_file(rp) as f: |
445 | + blob.data = f.read() |
446 | + elif stat.S_ISLNK(live_entry.mode): |
447 | + blob = Blob() |
448 | + blob.data = target.get_symlink_target(rp).encode(osutils._fs_enc) |
449 | + else: |
450 | + blob = None |
451 | + if blob is not None: |
452 | + target.store.add_object(blob) |
453 | blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode)) |
454 | if want_unversioned: |
455 | for e in target.extras(): |
456 | @@ -1681,12 +1716,14 @@ |
457 | target.abspath(e).encode(osutils._fs_enc), st) |
458 | else: |
459 | continue |
460 | - store.add_object(blob) |
461 | + target.store.add_object(blob) |
462 | np = np.encode('utf-8') |
463 | blobs[np] = (blob.id, cleanup_mode(st.st_mode)) |
464 | extras.add(np) |
465 | to_tree_sha = commit_tree( |
466 | - store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()]) |
467 | - return store.tree_changes( |
468 | - from_tree_sha, to_tree_sha, include_trees=True, |
469 | + target.store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()]) |
470 | + store = OverlayObjectStore([source_store, target.store]) |
471 | + return tree_changes( |
472 | + store, from_tree_sha, to_tree_sha, include_trees=True, |
473 | + rename_detector=rename_detector, |
474 | want_unchanged=want_unchanged, change_type_same=True), extras |
475 | |
476 | === modified file 'breezy/tests/per_repository/test_commit_builder.py' |
477 | --- breezy/tests/per_repository/test_commit_builder.py 2019-06-29 13:16:26 +0000 |
478 | +++ breezy/tests/per_repository/test_commit_builder.py 2020-06-16 23:49:21 +0000 |
479 | @@ -498,11 +498,11 @@ |
480 | builder.abort() |
481 | raise |
482 | delta = builder.get_basis_delta() |
483 | - delta_dict = dict((change[2], change) for change in delta) |
484 | + delta_dict = dict((change[1], change) for change in delta) |
485 | if tree.branch.repository._format.records_per_file_revision: |
486 | - version_recorded = (file_id in delta_dict |
487 | - and delta_dict[file_id][3] is not None |
488 | - and delta_dict[file_id][3].revision == rev2) |
489 | + version_recorded = (new_name in delta_dict |
490 | + and delta_dict[new_name][3] is not None |
491 | + and delta_dict[new_name][3].revision == rev2) |
492 | if records_version: |
493 | self.assertTrue(version_recorded) |
494 | else: |
495 | @@ -513,11 +513,24 @@ |
496 | specific_files=[new_name]))[1] |
497 | |
498 | if delta_against_basis: |
499 | - if tree.supports_rename_tracking() or name == new_name: |
500 | - expected_delta = (name, new_name, file_id, new_entry) |
501 | + (delta_old_name, delta_new_name, |
502 | + delta_file_id, delta_entry) = delta_dict[new_name] |
503 | + self.assertEqual(delta_new_name, new_name) |
504 | + if tree.supports_rename_tracking(): |
505 | + self.assertEqual(name, delta_old_name) |
506 | else: |
507 | - expected_delta = (None, new_name, file_id, new_entry) |
508 | - self.assertEqual(expected_delta, delta_dict[file_id]) |
509 | + self.assertIn(delta_old_name, (name, None)) |
510 | + if tree.supports_setting_file_ids(): |
511 | + self.assertEqual(delta_file_id, file_id) |
512 | + self.assertEqual(delta_entry.file_id, file_id) |
513 | + self.assertEqual(delta_entry.kind, new_entry.kind) |
514 | + self.assertEqual(delta_entry.name, new_entry.name) |
515 | + self.assertEqual(delta_entry.parent_id, new_entry.parent_id) |
516 | + if delta_entry.kind == 'file': |
517 | + self.assertEqual(delta_entry.text_size, new_entry.text_size) |
518 | + self.assertEqual(delta_entry.text_sha1, new_entry.text_sha1) |
519 | + elif delta_entry.kind == 'symlink': |
520 | + self.assertEqual(delta_entry.symlink_target, new_entry.symlink_target) |
521 | else: |
522 | expected_delta = None |
523 | if tree.branch.repository._format.records_per_file_revision: |
524 | |
525 | === modified file 'doc/en/release-notes/brz-3.1.txt' |
526 | --- doc/en/release-notes/brz-3.1.txt 2020-06-16 01:38:06 +0000 |
527 | +++ doc/en/release-notes/brz-3.1.txt 2020-06-16 23:49:21 +0000 |
528 | @@ -32,6 +32,9 @@ |
529 | * Permission denied errors from GitLab during push are now properly |
530 | recognized. (Jelmer Vernooij) |
531 | |
532 | + * Support rename and copy tracking when accessing Git |
533 | + repositories. (Jelmer Vernooij, #1760740) |
534 | + |
535 | Bug Fixes |
536 | ********* |
537 | |
538 | @@ -41,7 +44,6 @@ |
539 | * Don't require ``ctypes.pythonapi`` to exist, as it's missing on newer |
540 | versions of Pypy3. (Jelmer Vernooij) |
541 | |
542 | - |
543 | Documentation |
544 | ************* |
545 | |
546 | @@ -73,9 +75,6 @@ |
547 | * Tests for most bzr-specific functionality has been moved to the |
548 | ``breezy.bzr.tests`` module. (Jelmer Vernooij) |
549 | |
550 | -.. |
551 | - vim: tw=74 ft=rst ff=unix |
552 | - |
553 | brz 3.1.0 |
554 | ######### |
555 |
Running landing tests failed /ci.breezy- vcs.org/ job/brz/ job/brz- land/666/
https:/