comparison mercurial/copies.py @ 30581:43a9e02a7b7f

graft: support grafting changes to new file in renamed directory (issue5436)
author Gábor Stefanik <gabor.stefanik@nng.com>
date Mon, 05 Dec 2016 17:40:01 +0100
parents 1070df141718
children 5a909a8098a1
comparison
equal deleted inserted replaced
30580:51e7c83e05ee 30581:43a9e02a7b7f
308 def mergecopies(repo, c1, c2, base): 308 def mergecopies(repo, c1, c2, base):
309 """ 309 """
310 Find moves and copies between context c1 and c2 that are relevant 310 Find moves and copies between context c1 and c2 that are relevant
311 for merging. 'base' will be used as the merge base. 311 for merging. 'base' will be used as the merge base.
312 312
313 Returns four dicts: "copy", "movewithdir", "diverge", and 313 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
314 "renamedelete". 314 "dirmove".
315 315
316 "copy" is a mapping from destination name -> source name, 316 "copy" is a mapping from destination name -> source name,
317 where source is in c1 and destination is in c2 or vice-versa. 317 where source is in c1 and destination is in c2 or vice-versa.
318 318
319 "movewithdir" is a mapping from source name -> destination name, 319 "movewithdir" is a mapping from source name -> destination name,
324 "diverge" is a mapping of source name -> list of destination names 324 "diverge" is a mapping of source name -> list of destination names
325 for divergent renames. 325 for divergent renames.
326 326
327 "renamedelete" is a mapping of source name -> list of destination 327 "renamedelete" is a mapping of source name -> list of destination
328 names for files deleted in c1 that were renamed in c2 or vice-versa. 328 names for files deleted in c1 that were renamed in c2 or vice-versa.
329
330 "dirmove" is a mapping of detected source dir -> destination dir renames.
331 This is needed for handling changes to new files previously grafted into
332 renamed directories.
329 """ 333 """
330 # avoid silly behavior for update from empty dir 334 # avoid silly behavior for update from empty dir
331 if not c1 or not c2 or c1 == c2: 335 if not c1 or not c2 or c1 == c2:
332 return {}, {}, {}, {} 336 return {}, {}, {}, {}, {}
333 337
334 # avoid silly behavior for parent -> working dir 338 # avoid silly behavior for parent -> working dir
335 if c2.node() is None and c1.node() == repo.dirstate.p1(): 339 if c2.node() is None and c1.node() == repo.dirstate.p1():
336 return repo.dirstate.copies(), {}, {}, {} 340 return repo.dirstate.copies(), {}, {}, {}, {}
337 341
338 # Copy trace disabling is explicitly below the node == p1 logic above 342 # Copy trace disabling is explicitly below the node == p1 logic above
339 # because the logic above is required for a simple copy to be kept across a 343 # because the logic above is required for a simple copy to be kept across a
340 # rebase. 344 # rebase.
341 if repo.ui.configbool('experimental', 'disablecopytrace'): 345 if repo.ui.configbool('experimental', 'disablecopytrace'):
342 return {}, {}, {}, {} 346 return {}, {}, {}, {}, {}
343 347
344 # In certain scenarios (e.g. graft, update or rebase), base can be 348 # In certain scenarios (e.g. graft, update or rebase), base can be
345 # overridden We still need to know a real common ancestor in this case We 349 # overridden We still need to know a real common ancestor in this case We
346 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there 350 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
347 # can be multiple common ancestors, e.g. in case of bidmerge. Because our 351 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
363 tca = _c1.ancestor(_c2) 367 tca = _c1.ancestor(_c2)
364 368
365 limit = _findlimit(repo, c1.rev(), c2.rev()) 369 limit = _findlimit(repo, c1.rev(), c2.rev())
366 if limit is None: 370 if limit is None:
367 # no common ancestor, no copies 371 # no common ancestor, no copies
368 return {}, {}, {}, {} 372 return {}, {}, {}, {}, {}
369 repo.ui.debug(" searching for copies back to rev %d\n" % limit) 373 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
370 374
371 m1 = c1.manifest() 375 m1 = c1.manifest()
372 m2 = c2.manifest() 376 m2 = c2.manifest()
373 mb = base.manifest() 377 mb = base.manifest()
501 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f, 505 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
502 note)) 506 note))
503 del divergeset 507 del divergeset
504 508
505 if not fullcopy: 509 if not fullcopy:
506 return copy, {}, diverge, renamedelete 510 return copy, {}, diverge, renamedelete, {}
507 511
508 repo.ui.debug(" checking for directory renames\n") 512 repo.ui.debug(" checking for directory renames\n")
509 513
510 # generate a directory move map 514 # generate a directory move map
511 d1, d2 = c1.dirs(), c2.dirs() 515 d1, d2 = c1.dirs(), c2.dirs()
539 if i in dirmove: 543 if i in dirmove:
540 del dirmove[i] 544 del dirmove[i]
541 del d1, d2, invalid 545 del d1, d2, invalid
542 546
543 if not dirmove: 547 if not dirmove:
544 return copy, {}, diverge, renamedelete 548 return copy, {}, diverge, renamedelete, {}
545 549
546 for d in dirmove: 550 for d in dirmove:
547 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" % 551 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
548 (d, dirmove[d])) 552 (d, dirmove[d]))
549 553
559 movewithdir[f] = df 563 movewithdir[f] = df
560 repo.ui.debug((" pending file src: '%s' -> " 564 repo.ui.debug((" pending file src: '%s' -> "
561 "dst: '%s'\n") % (f, df)) 565 "dst: '%s'\n") % (f, df))
562 break 566 break
563 567
564 return copy, movewithdir, diverge, renamedelete 568 return copy, movewithdir, diverge, renamedelete, dirmove
565 569
566 def _related(f1, f2, limit): 570 def _related(f1, f2, limit):
567 """return True if f1 and f2 filectx have a common ancestor 571 """return True if f1 and f2 filectx have a common ancestor
568 572
569 Walk back to common ancestor to see if the two files originate 573 Walk back to common ancestor to see if the two files originate