Merge lp:~jelmer/brz/renames into lp:brz/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/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
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
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'breezy/builtins.py'
--- breezy/builtins.py 2020-04-02 01:37:43 +0000
+++ breezy/builtins.py 2020-06-16 23:49:21 +0000
@@ -4233,7 +4233,7 @@
42334233
4234 try:4234 try:
4235 from . import tests4235 from . import tests
4236 except ImportError:4236 except ImportError as e:
4237 raise errors.BzrCommandError("tests not available. Install the "4237 raise errors.BzrCommandError("tests not available. Install the "
4238 "breezy tests to run the breezy testsuite.")4238 "breezy tests to run the breezy testsuite.")
42394239
42404240
=== modified file 'breezy/commit.py'
--- breezy/commit.py 2019-09-21 17:08:09 +0000
+++ breezy/commit.py 2020-06-16 23:49:21 +0000
@@ -440,8 +440,8 @@
440 # as updating its basis and unversioning paths that were missing.440 # as updating its basis and unversioning paths that were missing.
441 self.work_tree.unversion(self.deleted_paths)441 self.work_tree.unversion(self.deleted_paths)
442 self._set_progress_stage("Updating the working tree")442 self._set_progress_stage("Updating the working tree")
443 self.work_tree.update_basis_by_delta(self.rev_id,443 self.work_tree.update_basis_by_delta(
444 self.builder.get_basis_delta())444 self.rev_id, self.builder.get_basis_delta())
445 self.reporter.completed(new_revno, self.rev_id)445 self.reporter.completed(new_revno, self.rev_id)
446 self._process_post_hooks(old_revno, new_revno)446 self._process_post_hooks(old_revno, new_revno)
447 return self.rev_id447 return self.rev_id
448448
=== modified file 'breezy/git/commit.py'
--- breezy/git/commit.py 2020-01-30 15:48:47 +0000
+++ breezy/git/commit.py 2020-06-16 23:49:21 +0000
@@ -69,6 +69,7 @@
69 self.store = self.repository._git.object_store69 self.store = self.repository._git.object_store
70 self._blobs = {}70 self._blobs = {}
71 self._inv_delta = []71 self._inv_delta = []
72 self._deleted_paths = set()
72 self._any_changes = False73 self._any_changes = False
73 self._mapping = self.repository.get_mapping()74 self._mapping = self.repository.get_mapping()
7475
@@ -92,7 +93,7 @@
92 self._any_changes = True93 self._any_changes = True
93 if change.path[1] is None:94 if change.path[1] is None:
94 self._inv_delta.append((change.path[0], change.path[1], change.file_id, None))95 self._inv_delta.append((change.path[0], change.path[1], change.file_id, None))
95 self._blobs[change.path[0].encode("utf-8")] = None96 self._deleted_paths.add(change.path[0].encode("utf-8"))
96 continue97 continue
97 try:98 try:
98 entry_kls = entry_factory[change.kind[1]]99 entry_kls = entry_factory[change.kind[1]]
@@ -128,8 +129,9 @@
128 raise AssertionError("Unknown kind %r" % change.kind[1])129 raise AssertionError("Unknown kind %r" % change.kind[1])
129 mode = object_mode(change.kind[1], change.executable[1])130 mode = object_mode(change.kind[1], change.executable[1])
130 self._inv_delta.append((change.path[0], change.path[1], change.file_id, entry))131 self._inv_delta.append((change.path[0], change.path[1], change.file_id, entry))
131 encoded_new_path = change.path[1].encode("utf-8")132 if change.path[0] is not None:
132 self._blobs[encoded_new_path] = (mode, sha)133 self._deleted_paths.add(change.path[0].encode("utf-8"))
134 self._blobs[change.path[1].encode("utf-8")] = (mode, sha)
133 if st is not None:135 if st is not None:
134 yield change.path[1], (entry.text_sha1, st)136 yield change.path[1], (entry.text_sha1, st)
135 if not seen_root and len(self.parents) == 0:137 if not seen_root and len(self.parents) == 0:
@@ -146,6 +148,8 @@
146 for entry in basis_tree._iter_tree_contents(include_trees=False):148 for entry in basis_tree._iter_tree_contents(include_trees=False):
147 if entry.path in self._blobs:149 if entry.path in self._blobs:
148 continue150 continue
151 if entry.path in self._deleted_paths:
152 continue
149 self._blobs[entry.path] = (entry.mode, entry.sha)153 self._blobs[entry.path] = (entry.mode, entry.sha)
150 self.new_inventory = None154 self.new_inventory = None
151155
@@ -155,8 +159,7 @@
155159
156 def finish_inventory(self):160 def finish_inventory(self):
157 # eliminate blobs that were removed161 # eliminate blobs that were removed
158 self._blobs = {k: v for (k, v) in viewitems(162 self._blobs = {k: v for (k, v) in viewitems(self._blobs)}
159 self._blobs) if v is not None}
160163
161 def _iterblobs(self):164 def _iterblobs(self):
162 return ((path, sha, mode) for (path, (mode, sha))165 return ((path, sha, mode) for (path, (mode, sha))
163166
=== modified file 'breezy/git/tests/test_workingtree.py'
--- breezy/git/tests/test_workingtree.py 2020-01-19 15:14:16 +0000
+++ breezy/git/tests/test_workingtree.py 2020-06-16 23:49:21 +0000
@@ -22,6 +22,8 @@
22import os22import os
23import stat23import stat
2424
25from dulwich import __version__ as dulwich_version
26from dulwich.diff_tree import RenameDetector
25from dulwich.index import IndexEntry27from dulwich.index import IndexEntry
26from dulwich.objects import (28from dulwich.objects import (
27 S_IFGITLINK,29 S_IFGITLINK,
@@ -141,9 +143,15 @@
141143
142 def test_missing(self):144 def test_missing(self):
143 delta = TreeDelta()145 delta = TreeDelta()
144 delta.removed.append(TreeChange(b'git:a', ('a', 'a'), False, (True, True), (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', None), (True, False)))146 delta.removed.append(
145 changes = [((b'a', b'a'), (stat.S_IFREG | 0o755, 0),147 TreeChange(
146 (b'a' * 40, b'a' * 40))]148 b'git:a', ('a', 'a'), False, (True, True),
149 (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', None),
150 (True, False)))
151 changes = [
152 ('remove',
153 (b'a', stat.S_IFREG | 0o755, b'a' * 40),
154 (b'a', 0, b'a' * 40))]
147 self.assertEqual(155 self.assertEqual(
148 delta,156 delta,
149 tree_delta_from_git_changes(changes, (default_mapping, default_mapping)))157 tree_delta_from_git_changes(changes, (default_mapping, default_mapping)))
@@ -158,7 +166,7 @@
158166
159 def expectDelta(self, expected_changes,167 def expectDelta(self, expected_changes,
160 expected_extras=None, want_unversioned=False,168 expected_extras=None, want_unversioned=False,
161 tree_id=None):169 tree_id=None, rename_detector=None):
162 if tree_id is None:170 if tree_id is None:
163 try:171 try:
164 tree_id = self.store[self.wt.branch.repository._git.head()].tree172 tree_id = self.store[self.wt.branch.repository._git.head()].tree
@@ -166,7 +174,8 @@
166 tree_id = None174 tree_id = None
167 with self.wt.lock_read():175 with self.wt.lock_read():
168 changes, extras = changes_between_git_tree_and_working_copy(176 changes, extras = changes_between_git_tree_and_working_copy(
169 self.store, tree_id, self.wt, want_unversioned=want_unversioned)177 self.store, tree_id, self.wt, want_unversioned=want_unversioned,
178 rename_detector=rename_detector)
170 self.assertEqual(expected_changes, list(changes))179 self.assertEqual(expected_changes, list(changes))
171 if expected_extras is None:180 if expected_extras is None:
172 expected_extras = set()181 expected_extras = set()
@@ -174,7 +183,7 @@
174183
175 def test_empty(self):184 def test_empty(self):
176 self.expectDelta(185 self.expectDelta(
177 [((None, b''), (None, stat.S_IFDIR), (None, Tree().id))])186 [('add', (None, None, None), (b'', stat.S_IFDIR, Tree().id))])
178187
179 def test_added_file(self):188 def test_added_file(self):
180 self.build_tree(['a'])189 self.build_tree(['a'])
@@ -183,20 +192,74 @@
183 t = Tree()192 t = Tree()
184 t.add(b"a", stat.S_IFREG | 0o644, a.id)193 t.add(b"a", stat.S_IFREG | 0o644, a.id)
185 self.expectDelta(194 self.expectDelta(
186 [((None, b''), (None, stat.S_IFDIR), (None, t.id)),195 [('add', (None, None, None), (b'', stat.S_IFDIR, t.id)),
187 ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, a.id))])196 ('add', (None, None, None), (b'a', stat.S_IFREG | 0o644, a.id))])
197
198 def test_renamed_file(self):
199 self.build_tree(['a'])
200 self.wt.add(['a'])
201 self.wt.rename_one('a', 'b')
202 a = Blob.from_string(b'contents of a\n')
203 self.store.add_object(a)
204 oldt = Tree()
205 oldt.add(b"a", stat.S_IFREG | 0o644, a.id)
206 self.store.add_object(oldt)
207 newt = Tree()
208 newt.add(b"b", stat.S_IFREG | 0o644, a.id)
209 self.store.add_object(newt)
210 self.expectDelta(
211 [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)),
212 ('delete', (b'a', stat.S_IFREG | 0o644, a.id), (None, None, None)),
213 ('add', (None, None, None), (b'b', stat.S_IFREG | 0o644, a.id)),
214 ],
215 tree_id=oldt.id)
216 if dulwich_version >= (0, 19, 15):
217 self.expectDelta(
218 [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)),
219 ('rename', (b'a', stat.S_IFREG | 0o644, a.id), (b'b', stat.S_IFREG | 0o644, a.id))],
220 tree_id=oldt.id, rename_detector=RenameDetector(self.store))
221
222 def test_copied_file(self):
223 self.build_tree(['a'])
224 self.wt.add(['a'])
225 self.wt.copy_one('a', 'b')
226 a = Blob.from_string(b'contents of a\n')
227 self.store.add_object(a)
228 oldt = Tree()
229 oldt.add(b"a", stat.S_IFREG | 0o644, a.id)
230 self.store.add_object(oldt)
231 newt = Tree()
232 newt.add(b"a", stat.S_IFREG | 0o644, a.id)
233 newt.add(b"b", stat.S_IFREG | 0o644, a.id)
234 self.store.add_object(newt)
235 self.expectDelta(
236 [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)),
237 ('add', (None, None, None), (b'b', stat.S_IFREG | 0o644, a.id)),
238 ],
239 tree_id=oldt.id)
240
241 if dulwich_version >= (0, 19, 15):
242 self.expectDelta(
243 [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)),
244 ('copy', (b'a', stat.S_IFREG | 0o644, a.id), (b'b', stat.S_IFREG | 0o644, a.id))],
245 tree_id=oldt.id, rename_detector=RenameDetector(self.store, find_copies_harder=True))
246 self.expectDelta(
247 [('modify', (b'', stat.S_IFDIR, oldt.id), (b'', stat.S_IFDIR, newt.id)),
248 ('add', (None, None, None), (b'b', stat.S_IFREG | 0o644, a.id)),
249 ],
250 tree_id=oldt.id, rename_detector=RenameDetector(self.store, find_copies_harder=False))
188251
189 def test_added_unknown_file(self):252 def test_added_unknown_file(self):
190 self.build_tree(['a'])253 self.build_tree(['a'])
191 t = Tree()254 t = Tree()
192 self.expectDelta(255 self.expectDelta(
193 [((None, b''), (None, stat.S_IFDIR), (None, t.id))])256 [('add', (None, None, None), (b'', stat.S_IFDIR, t.id))])
194 a = Blob.from_string(b'contents of a\n')257 a = Blob.from_string(b'contents of a\n')
195 t = Tree()258 t = Tree()
196 t.add(b"a", stat.S_IFREG | 0o644, a.id)259 t.add(b"a", stat.S_IFREG | 0o644, a.id)
197 self.expectDelta(260 self.expectDelta(
198 [((None, b''), (None, stat.S_IFDIR), (None, t.id)),261 [('add', (None, None, None), (b'', stat.S_IFDIR, t.id)),
199 ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, a.id))],262 ('add', (None, None, None), (b'a', stat.S_IFREG | 0o644, a.id))],
200 [b'a'],263 [b'a'],
201 want_unversioned=True)264 want_unversioned=True)
202265
@@ -208,8 +271,8 @@
208 t = Tree()271 t = Tree()
209 t.add(b"a", 0, ZERO_SHA)272 t.add(b"a", 0, ZERO_SHA)
210 self.expectDelta(273 self.expectDelta(
211 [((None, b''), (None, stat.S_IFDIR), (None, t.id)),274 [('add', (None, None, None), (b'', stat.S_IFDIR, t.id)),
212 ((None, b'a'), (None, 0), (None, ZERO_SHA))],275 ('add', (None, None, None), (b'a', 0, ZERO_SHA))],
213 [])276 [])
214277
215 def test_missing_versioned_file(self):278 def test_missing_versioned_file(self):
@@ -223,8 +286,12 @@
223 newt = Tree()286 newt = Tree()
224 newt.add(b"a", 0, ZERO_SHA)287 newt.add(b"a", 0, ZERO_SHA)
225 self.expectDelta(288 self.expectDelta(
226 [((b'', b''), (stat.S_IFDIR, stat.S_IFDIR), (oldt.id, newt.id)),289 [('modify',
227 ((b'a', b'a'), (stat.S_IFREG | 0o644, 0), (a.id, ZERO_SHA))])290 (b'', stat.S_IFDIR, oldt.id),
291 (b'', stat.S_IFDIR, newt.id)),
292 ('modify',
293 (b'a', stat.S_IFREG | 0o644, a.id),
294 (b'a', 0, ZERO_SHA))])
228295
229 def test_versioned_replace_by_dir(self):296 def test_versioned_replace_by_dir(self):
230 self.build_tree(['a'])297 self.build_tree(['a'])
@@ -239,16 +306,20 @@
239 newa = Tree()306 newa = Tree()
240 newt.add(b"a", stat.S_IFDIR, newa.id)307 newt.add(b"a", stat.S_IFDIR, newa.id)
241 self.expectDelta([308 self.expectDelta([
242 ((b'', b''),309 ('modify',
243 (stat.S_IFDIR, stat.S_IFDIR),310 (b'', stat.S_IFDIR, oldt.id),
244 (oldt.id, newt.id)),311 (b'', stat.S_IFDIR, newt.id)),
245 ((b'a', b'a'), (stat.S_IFREG | 0o644, stat.S_IFDIR), (olda.id, newa.id))312 ('modify',
313 (b'a', stat.S_IFREG | 0o644, olda.id),
314 (b'a', stat.S_IFDIR, newa.id))
246 ], want_unversioned=False)315 ], want_unversioned=False)
247 self.expectDelta([316 self.expectDelta([
248 ((b'', b''),317 ('modify',
249 (stat.S_IFDIR, stat.S_IFDIR),318 (b'', stat.S_IFDIR, oldt.id),
250 (oldt.id, newt.id)),319 (b'', stat.S_IFDIR, newt.id)),
251 ((b'a', b'a'), (stat.S_IFREG | 0o644, stat.S_IFDIR), (olda.id, newa.id))320 ('modify',
321 (b'a', stat.S_IFREG | 0o644, olda.id),
322 (b'a', stat.S_IFDIR, newa.id)),
252 ], want_unversioned=True)323 ], want_unversioned=True)
253324
254 def test_extra(self):325 def test_extra(self):
@@ -257,10 +328,12 @@
257 newt = Tree()328 newt = Tree()
258 newt.add(b"a", stat.S_IFREG | 0o644, newa.id)329 newt.add(b"a", stat.S_IFREG | 0o644, newa.id)
259 self.expectDelta([330 self.expectDelta([
260 ((None, b''),331 ('add',
261 (None, stat.S_IFDIR),332 (None, None, None),
262 (None, newt.id)),333 (b'', stat.S_IFDIR, newt.id)),
263 ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, newa.id))334 ('add',
335 (None, None, None),
336 (b'a', stat.S_IFREG | 0o644, newa.id)),
264 ], [b'a'], want_unversioned=True)337 ], [b'a'], want_unversioned=True)
265338
266 def test_submodule(self):339 def test_submodule(self):
267340
=== modified file 'breezy/git/tree.py'
--- breezy/git/tree.py 2020-04-27 02:29:59 +0000
+++ breezy/git/tree.py 2020-06-16 23:49:21 +0000
@@ -28,7 +28,7 @@
28 parse_submodules,28 parse_submodules,
29 ConfigFile as GitConfigFile,29 ConfigFile as GitConfigFile,
30 )30 )
31from dulwich.diff_tree import tree_changes31from dulwich.diff_tree import tree_changes, RenameDetector
32from dulwich.errors import NotTreeError32from dulwich.errors import NotTreeError
33from dulwich.index import (33from dulwich.index import (
34 blob_from_path_and_stat,34 blob_from_path_and_stat,
@@ -737,7 +737,9 @@
737 target_extras = set()737 target_extras = set()
738 ret = delta.TreeDelta()738 ret = delta.TreeDelta()
739 added = []739 added = []
740 for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:740 for (change_type, old, new) in changes:
741 (oldpath, oldmode, oldsha) = old
742 (newpath, newmode, newsha) = new
741 if newpath == b'' and not include_root:743 if newpath == b'' and not include_root:
742 continue744 continue
743 if oldpath is not None:745 if oldpath is not None:
@@ -809,13 +811,17 @@
809 fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),811 fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
810 (oldversioned, newversioned),812 (oldversioned, newversioned),
811 (oldparent, newparent), (oldname, newname),813 (oldparent, newparent), (oldname, newname),
812 (oldkind, newkind), (oldexe, newexe))814 (oldkind, newkind), (oldexe, newexe),
815 copied=(change_type == 'copy'))
813 if oldpath is None:816 if oldpath is None:
814 added.append((newpath, newkind))817 added.append((newpath, newkind))
815 elif newpath is None or newmode == 0:818 elif newpath is None or newmode == 0:
816 ret.removed.append(change)819 ret.removed.append(change)
817 elif oldpath != newpath:820 elif oldpath != newpath:
818 ret.renamed.append(change)821 if change_type == 'copy':
822 ret.copied.append(change)
823 else:
824 ret.renamed.append(change)
819 elif mode_kind(oldmode) != mode_kind(newmode):825 elif mode_kind(oldmode) != mode_kind(newmode):
820 ret.kind_changed.append(change)826 ret.kind_changed.append(change)
821 elif oldsha != newsha or oldmode != newmode:827 elif oldsha != newsha or oldmode != newmode:
@@ -863,7 +869,9 @@
863 """869 """
864 if target_extras is None:870 if target_extras is None:
865 target_extras = set()871 target_extras = set()
866 for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:872 for (change_type, old, new) in changes:
873 (oldpath, oldmode, oldsha) = old
874 (newpath, newmode, newsha) = new
867 if oldpath is not None:875 if oldpath is not None:
868 oldpath_decoded = oldpath.decode('utf-8')876 oldpath_decoded = oldpath.decode('utf-8')
869 else:877 else:
@@ -934,7 +942,8 @@
934 fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),942 fileid, (oldpath_decoded, newpath_decoded), (oldsha != newsha),
935 (oldversioned, newversioned),943 (oldversioned, newversioned),
936 (oldparent, newparent), (oldname, newname),944 (oldparent, newparent), (oldname, newname),
937 (oldkind, newkind), (oldexe, newexe))945 (oldkind, newkind), (oldexe, newexe),
946 copied=(change_type == 'copy'))
938947
939948
940class InterGitTrees(_mod_tree.InterTree):949class InterGitTrees(_mod_tree.InterTree):
@@ -997,7 +1006,9 @@
997 paths = set(paths)1006 paths = set(paths)
998 ret = {}1007 ret = {}
999 changes = self._iter_git_changes(specific_files=paths)[0]1008 changes = self._iter_git_changes(specific_files=paths)[0]
1000 for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:1009 for (change_type, old, new) in changes:
1010 oldpath = old[0]
1011 newpath = new[0]
1001 if oldpath in paths:1012 if oldpath in paths:
1002 ret[oldpath] = newpath1013 ret[oldpath] = newpath
1003 for path in paths:1014 for path in paths:
@@ -1015,7 +1026,9 @@
1015 paths = set(paths)1026 paths = set(paths)
1016 ret = {}1027 ret = {}
1017 changes = self._iter_git_changes(specific_files=paths)[0]1028 changes = self._iter_git_changes(specific_files=paths)[0]
1018 for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in changes:1029 for (change_type, old, new) in changes:
1030 oldpath = old[0]
1031 newpath = new[0]
1019 if newpath in paths:1032 if newpath in paths:
1020 ret[newpath] = oldpath1033 ret[newpath] = oldpath
1021 for path in paths:1034 for path in paths:
@@ -1060,9 +1073,10 @@
1060 self.target._repository._git.object_store])1073 self.target._repository._git.object_store])
1061 else:1074 else:
1062 store = self.source._repository._git.object_store1075 store = self.source._repository._git.object_store
1063 return store.tree_changes(1076 rename_detector = RenameDetector(store)
1064 self.source.tree, self.target.tree, want_unchanged=want_unchanged,1077 return tree_changes(
1065 include_trees=True, change_type_same=True), set()1078 store, self.source.tree, self.target.tree, want_unchanged=want_unchanged,
1079 include_trees=True, change_type_same=True, rename_detector=rename_detector), set()
10661080
10671081
1068_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)1082_mod_tree.InterTree.register_optimiser(InterGitRevisionTrees)
@@ -1601,6 +1615,12 @@
1601 def __init__(self, source, target):1615 def __init__(self, source, target):
1602 super(InterIndexGitTree, self).__init__(source, target)1616 super(InterIndexGitTree, self).__init__(source, target)
1603 self._index = target.index1617 self._index = target.index
1618 if self.source.store == self.target.store:
1619 self.store = self.source.store
1620 else:
1621 self.store = OverlayObjectStore(
1622 [self.source.store, self.target.store])
1623 self.rename_detector = RenameDetector(self.store)
16041624
1605 @classmethod1625 @classmethod
1606 def is_compatible(cls, source, target):1626 def is_compatible(cls, source, target):
@@ -1622,15 +1642,17 @@
1622 return changes_between_git_tree_and_working_copy(1642 return changes_between_git_tree_and_working_copy(
1623 self.source.store, self.source.tree,1643 self.source.store, self.source.tree,
1624 self.target, want_unchanged=want_unchanged,1644 self.target, want_unchanged=want_unchanged,
1625 want_unversioned=want_unversioned)1645 want_unversioned=want_unversioned,
1646 rename_detector=self.rename_detector)
16261647
16271648
1628_mod_tree.InterTree.register_optimiser(InterIndexGitTree)1649_mod_tree.InterTree.register_optimiser(InterIndexGitTree)
16291650
16301651
1631def changes_between_git_tree_and_working_copy(store, from_tree_sha, target,1652def changes_between_git_tree_and_working_copy(source_store, from_tree_sha, target,
1632 want_unchanged=False,1653 want_unchanged=False,
1633 want_unversioned=False):1654 want_unversioned=False,
1655 rename_detector=None):
1634 """Determine the changes between a git tree and a working tree with index.1656 """Determine the changes between a git tree and a working tree with index.
16351657
1636 """1658 """
@@ -1657,7 +1679,7 @@
1657 blobs[path] = (index_entry.sha, index_entry.mode)1679 blobs[path] = (index_entry.sha, index_entry.mode)
1658 else:1680 else:
1659 dirified.append((path, Tree().id, stat.S_IFDIR))1681 dirified.append((path, Tree().id, stat.S_IFDIR))
1660 store.add_object(Tree())1682 target.store.add_object(Tree())
1661 else:1683 else:
1662 mode = live_entry.mode1684 mode = live_entry.mode
1663 if not trust_executable:1685 if not trust_executable:
@@ -1665,6 +1687,19 @@
1665 mode |= 0o1111687 mode |= 0o111
1666 else:1688 else:
1667 mode &= ~0o1111689 mode &= ~0o111
1690 if live_entry.sha != index_entry.sha:
1691 rp = path.decode('utf-8')
1692 if stat.S_ISREG(live_entry.mode):
1693 blob = Blob()
1694 with target.get_file(rp) as f:
1695 blob.data = f.read()
1696 elif stat.S_ISLNK(live_entry.mode):
1697 blob = Blob()
1698 blob.data = target.get_symlink_target(rp).encode(osutils._fs_enc)
1699 else:
1700 blob = None
1701 if blob is not None:
1702 target.store.add_object(blob)
1668 blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))1703 blobs[path] = (live_entry.sha, cleanup_mode(live_entry.mode))
1669 if want_unversioned:1704 if want_unversioned:
1670 for e in target.extras():1705 for e in target.extras():
@@ -1681,12 +1716,14 @@
1681 target.abspath(e).encode(osutils._fs_enc), st)1716 target.abspath(e).encode(osutils._fs_enc), st)
1682 else:1717 else:
1683 continue1718 continue
1684 store.add_object(blob)1719 target.store.add_object(blob)
1685 np = np.encode('utf-8')1720 np = np.encode('utf-8')
1686 blobs[np] = (blob.id, cleanup_mode(st.st_mode))1721 blobs[np] = (blob.id, cleanup_mode(st.st_mode))
1687 extras.add(np)1722 extras.add(np)
1688 to_tree_sha = commit_tree(1723 to_tree_sha = commit_tree(
1689 store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])1724 target.store, dirified + [(p, s, m) for (p, (s, m)) in blobs.items()])
1690 return store.tree_changes(1725 store = OverlayObjectStore([source_store, target.store])
1691 from_tree_sha, to_tree_sha, include_trees=True,1726 return tree_changes(
1727 store, from_tree_sha, to_tree_sha, include_trees=True,
1728 rename_detector=rename_detector,
1692 want_unchanged=want_unchanged, change_type_same=True), extras1729 want_unchanged=want_unchanged, change_type_same=True), extras
16931730
=== modified file 'breezy/tests/per_repository/test_commit_builder.py'
--- breezy/tests/per_repository/test_commit_builder.py 2019-06-29 13:16:26 +0000
+++ breezy/tests/per_repository/test_commit_builder.py 2020-06-16 23:49:21 +0000
@@ -498,11 +498,11 @@
498 builder.abort()498 builder.abort()
499 raise499 raise
500 delta = builder.get_basis_delta()500 delta = builder.get_basis_delta()
501 delta_dict = dict((change[2], change) for change in delta)501 delta_dict = dict((change[1], change) for change in delta)
502 if tree.branch.repository._format.records_per_file_revision:502 if tree.branch.repository._format.records_per_file_revision:
503 version_recorded = (file_id in delta_dict503 version_recorded = (new_name in delta_dict
504 and delta_dict[file_id][3] is not None504 and delta_dict[new_name][3] is not None
505 and delta_dict[file_id][3].revision == rev2)505 and delta_dict[new_name][3].revision == rev2)
506 if records_version:506 if records_version:
507 self.assertTrue(version_recorded)507 self.assertTrue(version_recorded)
508 else:508 else:
@@ -513,11 +513,24 @@
513 specific_files=[new_name]))[1]513 specific_files=[new_name]))[1]
514514
515 if delta_against_basis:515 if delta_against_basis:
516 if tree.supports_rename_tracking() or name == new_name:516 (delta_old_name, delta_new_name,
517 expected_delta = (name, new_name, file_id, new_entry)517 delta_file_id, delta_entry) = delta_dict[new_name]
518 self.assertEqual(delta_new_name, new_name)
519 if tree.supports_rename_tracking():
520 self.assertEqual(name, delta_old_name)
518 else:521 else:
519 expected_delta = (None, new_name, file_id, new_entry)522 self.assertIn(delta_old_name, (name, None))
520 self.assertEqual(expected_delta, delta_dict[file_id])523 if tree.supports_setting_file_ids():
524 self.assertEqual(delta_file_id, file_id)
525 self.assertEqual(delta_entry.file_id, file_id)
526 self.assertEqual(delta_entry.kind, new_entry.kind)
527 self.assertEqual(delta_entry.name, new_entry.name)
528 self.assertEqual(delta_entry.parent_id, new_entry.parent_id)
529 if delta_entry.kind == 'file':
530 self.assertEqual(delta_entry.text_size, new_entry.text_size)
531 self.assertEqual(delta_entry.text_sha1, new_entry.text_sha1)
532 elif delta_entry.kind == 'symlink':
533 self.assertEqual(delta_entry.symlink_target, new_entry.symlink_target)
521 else:534 else:
522 expected_delta = None535 expected_delta = None
523 if tree.branch.repository._format.records_per_file_revision:536 if tree.branch.repository._format.records_per_file_revision:
524537
=== modified file 'doc/en/release-notes/brz-3.1.txt'
--- doc/en/release-notes/brz-3.1.txt 2020-06-16 01:38:06 +0000
+++ doc/en/release-notes/brz-3.1.txt 2020-06-16 23:49:21 +0000
@@ -32,6 +32,9 @@
32 * Permission denied errors from GitLab during push are now properly32 * Permission denied errors from GitLab during push are now properly
33 recognized. (Jelmer Vernooij)33 recognized. (Jelmer Vernooij)
3434
35 * Support rename and copy tracking when accessing Git
36 repositories. (Jelmer Vernooij, #1760740)
37
35Bug Fixes38Bug Fixes
36*********39*********
3740
@@ -41,7 +44,6 @@
41 * Don't require ``ctypes.pythonapi`` to exist, as it's missing on newer44 * Don't require ``ctypes.pythonapi`` to exist, as it's missing on newer
42 versions of Pypy3. (Jelmer Vernooij)45 versions of Pypy3. (Jelmer Vernooij)
4346
44
45Documentation47Documentation
46*************48*************
4749
@@ -73,9 +75,6 @@
73 * Tests for most bzr-specific functionality has been moved to the75 * Tests for most bzr-specific functionality has been moved to the
74 ``breezy.bzr.tests`` module. (Jelmer Vernooij)76 ``breezy.bzr.tests`` module. (Jelmer Vernooij)
7577
76..
77 vim: tw=74 ft=rst ff=unix
78
79brz 3.1.078brz 3.1.0
80#########79#########
8180

Subscribers

People subscribed via source and target branches