comparison mercurial/merge.py @ 27131:d837da26155e

merge: add a new action type representing files to add/mark as modified This is somewhat different from the currently existing 'a' action, for the following case: - dirty working copy, with file 'fa' added and 'fm' modified - hg merge --force with a rev that neither has 'fa' nor 'fm' - for the change/delete conflicts we pick 'changed' for both 'fa' and 'fm'. In this case 'branchmerge' is true, but we need to distinguish between 'fa', which should ultimately be marked added, and 'fm', which should be marked modified. Our current strategy is to just not touch the dirstate at all. That works for now, but won't work once we move change/delete conflicts to the resolve phase. In that case we may perform repeated re-resolves, some of which might mark the file removed or remove the file from the dirstate. We'll need to re-add the file to the dirstate, and we need to be able to figure out whether we mark the file added or modified. That is what the new 'am' action lets us do.
author Siddharth Agarwal <sid0@fb.com>
date Mon, 30 Nov 2015 10:19:39 -0800
parents 6f045b563fa5
children baa7571f40c5
comparison
equal deleted inserted replaced
27130:6f045b563fa5 27131:d837da26155e
477 action = 'r' 477 action = 'r'
478 else: 478 else:
479 if fcd.isabsent(): # dc: remote picked 479 if fcd.isabsent(): # dc: remote picked
480 action = 'g' 480 action = 'g'
481 elif fco.isabsent(): # cd: local picked 481 elif fco.isabsent(): # cd: local picked
482 action = 'a' 482 if dfile in self.localctx:
483 action = 'am'
484 else:
485 action = 'a'
483 # else: regular merges (no action necessary) 486 # else: regular merges (no action necessary)
484 self._results[dfile] = r, action 487 self._results[dfile] = r, action
485 488
486 return complete, r 489 return complete, r
487 490
522 return len([True for f, entry in self._state.iteritems() 525 return len([True for f, entry in self._state.iteritems()
523 if entry[0] == 'u']) 526 if entry[0] == 'u'])
524 527
525 def actions(self): 528 def actions(self):
526 """return lists of actions to perform on the dirstate""" 529 """return lists of actions to perform on the dirstate"""
527 actions = {'r': [], 'f': [], 'a': [], 'g': []} 530 actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []}
528 for f, (r, action) in self._results.iteritems(): 531 for f, (r, action) in self._results.iteritems():
529 if action is not None: 532 if action is not None:
530 actions[action].append((f, None, "merge result")) 533 actions[action].append((f, None, "merge result"))
531 return actions 534 return actions
532 535
629 # build provisional merged manifest up 632 # build provisional merged manifest up
630 pmmf = set(wmf) 633 pmmf = set(wmf)
631 634
632 if actions: 635 if actions:
633 # k, dr, e and rd are no-op 636 # k, dr, e and rd are no-op
634 for m in 'a', 'f', 'g', 'cd', 'dc': 637 for m in 'a', 'am', 'f', 'g', 'cd', 'dc':
635 for f, args, msg in actions[m]: 638 for f, args, msg in actions[m]:
636 pmmf.add(f) 639 pmmf.add(f)
637 for f, args, msg in actions['r']: 640 for f, args, msg in actions['r']:
638 pmmf.discard(f) 641 pmmf.discard(f)
639 for f, args, msg in actions['dm']: 642 for f, args, msg in actions['dm']:
1063 for f, args, msg in actions['a']: 1066 for f, args, msg in actions['a']:
1064 repo.ui.debug(" %s: %s -> a\n" % (f, msg)) 1067 repo.ui.debug(" %s: %s -> a\n" % (f, msg))
1065 z += 1 1068 z += 1
1066 progress(_updating, z, item=f, total=numupdates, unit=_files) 1069 progress(_updating, z, item=f, total=numupdates, unit=_files)
1067 1070
1071 # re-add/mark as modified (manifest only, just log it)
1072 for f, args, msg in actions['am']:
1073 repo.ui.debug(" %s: %s -> am\n" % (f, msg))
1074 z += 1
1075 progress(_updating, z, item=f, total=numupdates, unit=_files)
1076
1068 # keep (noop, just log it) 1077 # keep (noop, just log it)
1069 for f, args, msg in actions['k']: 1078 for f, args, msg in actions['k']:
1070 repo.ui.debug(" %s: %s -> k\n" % (f, msg)) 1079 repo.ui.debug(" %s: %s -> k\n" % (f, msg))
1071 # no progress 1080 # no progress
1072 1081
1185 repo.dirstate.drop(f) 1194 repo.dirstate.drop(f)
1186 1195
1187 # re-add 1196 # re-add
1188 for f, args, msg in actions.get('a', []): 1197 for f, args, msg in actions.get('a', []):
1189 if not branchmerge: 1198 if not branchmerge:
1199 repo.dirstate.add(f)
1200
1201 # re-add/mark as modified
1202 for f, args, msg in actions.get('am', []):
1203 if branchmerge:
1204 repo.dirstate.normallookup(f)
1205 else:
1190 repo.dirstate.add(f) 1206 repo.dirstate.add(f)
1191 1207
1192 # exec change 1208 # exec change
1193 for f, args, msg in actions.get('e', []): 1209 for f, args, msg in actions.get('e', []):
1194 repo.dirstate.normallookup(f) 1210 repo.dirstate.normallookup(f)
1388 ### calculate phase 1404 ### calculate phase
1389 actionbyfile, diverge, renamedelete = calculateupdates( 1405 actionbyfile, diverge, renamedelete = calculateupdates(
1390 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor, 1406 repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
1391 followcopies) 1407 followcopies)
1392 # Convert to dictionary-of-lists format 1408 # Convert to dictionary-of-lists format
1393 actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split()) 1409 actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split())
1394 for f, (m, args, msg) in actionbyfile.iteritems(): 1410 for f, (m, args, msg) in actionbyfile.iteritems():
1395 if m not in actions: 1411 if m not in actions:
1396 actions[m] = [] 1412 actions[m] = []
1397 actions[m].append((f, args, msg)) 1413 actions[m].append((f, args, msg))
1398 1414
1409 if repo.ui.promptchoice( 1425 if repo.ui.promptchoice(
1410 _("local changed %s which remote deleted\n" 1426 _("local changed %s which remote deleted\n"
1411 "use (c)hanged version or (d)elete?" 1427 "use (c)hanged version or (d)elete?"
1412 "$$ &Changed $$ &Delete") % f, 0): 1428 "$$ &Changed $$ &Delete") % f, 0):
1413 actions['r'].append((f, None, "prompt delete")) 1429 actions['r'].append((f, None, "prompt delete"))
1430 elif f in p1:
1431 actions['am'].append((f, None, "prompt keep"))
1414 else: 1432 else:
1415 actions['a'].append((f, None, "prompt keep")) 1433 actions['a'].append((f, None, "prompt keep"))
1416 1434
1417 for f, args, msg in sorted(actions['dc']): 1435 for f, args, msg in sorted(actions['dc']):
1418 f1, f2, fa, move, anc = args 1436 f1, f2, fa, move, anc = args