Mercurial > public > mercurial-scm > hg
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 |