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):