Mercurial > hg
comparison mercurial/copies.py @ 45640:2693659c2b34
copies: directly pass a changes object to the copy tracing code
The object contains all the data we need. For example, the `is_merged` callback
can now use the associated precomputed data.
This will be useful again soon when the `salvaged` set will be introduce to
solve the issue with delete file reverted during a merge. See 4b582a93316a and
14be07d5603c for details.
Differential Revision: https://phab.mercurial-scm.org/D9117
author | Pierre-Yves David <pierre-yves.david@octobus.net> |
---|---|
date | Fri, 25 Sep 2020 15:05:08 +0200 |
parents | 7a757e893532 |
children | a8fb29b05f92 |
comparison
equal
deleted
inserted
replaced
45639:7a757e893532 | 45640:2693659c2b34 |
---|---|
169 ) | 169 ) |
170 return cm | 170 return cm |
171 | 171 |
172 | 172 |
173 def _revinfo_getter(repo): | 173 def _revinfo_getter(repo): |
174 """return a function that return multiple data given a <rev>"i | 174 """returns a function that returns the following data given a <rev>" |
175 | 175 |
176 * p1: revision number of first parent | 176 * p1: revision number of first parent |
177 * p2: revision number of first parent | 177 * p2: revision number of first parent |
178 * p1copies: mapping of copies from p1 | 178 * changes: a ChangingFiles object |
179 * p2copies: mapping of copies from p2 | |
180 * removed: a list of removed files | |
181 * ismerged: a callback to know if file was merged in that revision | |
182 """ | 179 """ |
183 cl = repo.changelog | 180 cl = repo.changelog |
184 parents = cl.parentrevs | 181 parents = cl.parentrevs |
185 | |
186 def get_ismerged(rev): | |
187 ctx = repo[rev] | |
188 | |
189 def ismerged(path): | |
190 if path not in ctx.files(): | |
191 return False | |
192 fctx = ctx[path] | |
193 parents = fctx._filelog.parents(fctx._filenode) | |
194 nb_parents = 0 | |
195 for n in parents: | |
196 if n != node.nullid: | |
197 nb_parents += 1 | |
198 return nb_parents >= 2 | |
199 | |
200 return ismerged | |
201 | 182 |
202 changelogrevision = cl.changelogrevision | 183 changelogrevision = cl.changelogrevision |
203 | 184 |
204 # A small cache to avoid doing the work twice for merges | 185 # A small cache to avoid doing the work twice for merges |
205 # | 186 # |
230 p1, p2 = parents(rev) | 211 p1, p2 = parents(rev) |
231 value = None | 212 value = None |
232 e = merge_caches.pop(rev, None) | 213 e = merge_caches.pop(rev, None) |
233 if e is not None: | 214 if e is not None: |
234 return e | 215 return e |
235 c = changelogrevision(rev) | 216 value = (p1, p2, changelogrevision(rev).changes) |
236 p1copies = c.p1copies | |
237 p2copies = c.p2copies | |
238 removed = c.filesremoved | |
239 if p1 != node.nullrev and p2 != node.nullrev: | 217 if p1 != node.nullrev and p2 != node.nullrev: |
240 # XXX some case we over cache, IGNORE | 218 # XXX some case we over cache, IGNORE |
241 value = merge_caches[rev] = ( | 219 merge_caches[rev] = value |
242 p1, | |
243 p2, | |
244 p1copies, | |
245 p2copies, | |
246 removed, | |
247 get_ismerged(rev), | |
248 ) | |
249 | |
250 if value is None: | |
251 value = (p1, p2, p1copies, p2copies, removed, get_ismerged(rev)) | |
252 return value | 220 return value |
253 | 221 |
254 return revinfo | 222 return revinfo |
255 | 223 |
256 | 224 |
322 copies = all_copies.pop(r, None) | 290 copies = all_copies.pop(r, None) |
323 if copies is None: | 291 if copies is None: |
324 # this is a root | 292 # this is a root |
325 copies = {} | 293 copies = {} |
326 for i, c in enumerate(children[r]): | 294 for i, c in enumerate(children[r]): |
327 p1, p2, p1copies, p2copies, removed, ismerged = revinfo(c) | 295 p1, p2, changes = revinfo(c) |
328 if r == p1: | 296 if r == p1: |
329 parent = 1 | 297 parent = 1 |
330 childcopies = p1copies | 298 childcopies = changes.copied_from_p1 |
331 else: | 299 else: |
332 assert r == p2 | 300 assert r == p2 |
333 parent = 2 | 301 parent = 2 |
334 childcopies = p2copies | 302 childcopies = changes.copied_from_p2 |
335 if not alwaysmatch: | 303 if not alwaysmatch: |
336 childcopies = { | 304 childcopies = { |
337 dst: src for dst, src in childcopies.items() if match(dst) | 305 dst: src for dst, src in childcopies.items() if match(dst) |
338 } | 306 } |
339 newcopies = copies | 307 newcopies = copies |
343 prev = copies.get(source) | 311 prev = copies.get(source) |
344 if prev is not None and prev[1] is not None: | 312 if prev is not None and prev[1] is not None: |
345 source = prev[1] | 313 source = prev[1] |
346 newcopies[dest] = (c, source) | 314 newcopies[dest] = (c, source) |
347 assert newcopies is not copies | 315 assert newcopies is not copies |
348 for f in removed: | 316 for f in changes.removed: |
349 if f in newcopies: | 317 if f in newcopies: |
350 if newcopies is copies: | 318 if newcopies is copies: |
351 # copy on write to avoid affecting potential other | 319 # copy on write to avoid affecting potential other |
352 # branches. when there are no other branches, this | 320 # branches. when there are no other branches, this |
353 # could be avoided. | 321 # could be avoided. |
364 # This is an arbitrary choice made anew when implementing | 332 # This is an arbitrary choice made anew when implementing |
365 # changeset based copies. It was made without regards with | 333 # changeset based copies. It was made without regards with |
366 # potential filelog related behavior. | 334 # potential filelog related behavior. |
367 if parent == 1: | 335 if parent == 1: |
368 _merge_copies_dict( | 336 _merge_copies_dict( |
369 othercopies, newcopies, isancestor, ismerged | 337 othercopies, newcopies, isancestor, changes |
370 ) | 338 ) |
371 else: | 339 else: |
372 _merge_copies_dict( | 340 _merge_copies_dict( |
373 newcopies, othercopies, isancestor, ismerged | 341 newcopies, othercopies, isancestor, changes |
374 ) | 342 ) |
375 all_copies[c] = newcopies | 343 all_copies[c] = newcopies |
376 | 344 |
377 final_copies = {} | 345 final_copies = {} |
378 for dest, (tt, source) in all_copies[targetrev].items(): | 346 for dest, (tt, source) in all_copies[targetrev].items(): |
379 if source is not None: | 347 if source is not None: |
380 final_copies[dest] = source | 348 final_copies[dest] = source |
381 return final_copies | 349 return final_copies |
382 | 350 |
383 | 351 |
384 def _merge_copies_dict(minor, major, isancestor, ismerged): | 352 def _merge_copies_dict(minor, major, isancestor, changes): |
385 """merge two copies-mapping together, minor and major | 353 """merge two copies-mapping together, minor and major |
386 | 354 |
387 In case of conflict, value from "major" will be picked. | 355 In case of conflict, value from "major" will be picked. |
388 | 356 |
389 - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an | 357 - `isancestors(low_rev, high_rev)`: callable return True if `low_rev` is an |
404 # content from "major" wins, unless it is older | 372 # content from "major" wins, unless it is older |
405 # than the branch point or there is a merge | 373 # than the branch point or there is a merge |
406 if ( | 374 if ( |
407 new_tt == other_tt | 375 new_tt == other_tt |
408 or not isancestor(new_tt, other_tt) | 376 or not isancestor(new_tt, other_tt) |
409 or ismerged(dest) | 377 or dest in changes.merged |
410 ): | 378 ): |
411 minor[dest] = value | 379 minor[dest] = value |
412 | 380 |
413 | 381 |
414 def _revinfo_getter_extra(repo): | 382 def _revinfo_getter_extra(repo): |