diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -71,6 +71,23 @@ MERGE_RECORD_RESOLVED_PATH = b'pr' MERGE_RECORD_DRIVER_RESOLVED = b'd' +ACTION_FORGET = b'f' +ACTION_REMOVE = b'r' +ACTION_ADD = b'a' +ACTION_GET = b'g' +ACTION_PATH_CONFLICT = b'p' +ACTION_PATH_CONFLICT_RESOLVE = b'pr' +ACTION_ADD_MODIFIED = b'am' +ACTION_CREATED = b'c' +ACTION_DELETED_CHANGED = b'dc' +ACTION_CHANGED_DELETED = b'cd' +ACTION_MERGE = b'm' +ACTION_LOCAL_DIR_RENAME_GET = b'dg' +ACTION_DIR_RENAME_MOVE_LOCAL = b'dm' +ACTION_KEEP = b'k' +ACTION_EXEC = b'e' +ACTION_CREATED_MERGE = b'cm' + class mergestate(object): '''track 3-way merge state of individual files @@ -588,18 +605,18 @@ if fcd.isabsent(): # dc: local picked. Need to drop if present, which may # happen on re-resolves. - action = 'f' + action = ACTION_FORGET else: # cd: remote picked (or otherwise deleted) - action = 'r' + action = ACTION_REMOVE else: if fcd.isabsent(): # dc: remote picked - action = 'g' + action = ACTION_GET elif fco.isabsent(): # cd: local picked if dfile in self.localctx: - action = 'am' + action = ACTION_ADD_MODIFIED else: - action = 'a' + action = ACTION_ADD # else: regular merges (no action necessary) self._results[dfile] = r, action @@ -631,7 +648,7 @@ if r is None: updated += 1 elif r == 0: - if action == 'r': + if action == ACTION_REMOVE: removed += 1 else: merged += 1 @@ -643,7 +660,13 @@ def actions(self): """return lists of actions to perform on the dirstate""" - actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []} + actions = { + ACTION_REMOVE: [], + ACTION_FORGET: [], + ACTION_ADD: [], + ACTION_ADD_MODIFIED: [], + ACTION_GET: [], + } for f, (r, action) in self._results.iteritems(): if action is not None: actions[action].append((f, None, "merge result")) @@ -658,19 +681,19 @@ """queues a file to be removed from the dirstate Meant for use by custom merge drivers.""" - self._results[f] = 0, 'r' + self._results[f] = 0, ACTION_REMOVE def queueadd(self, f): """queues a file to be added to the dirstate Meant for use by custom merge drivers.""" - self._results[f] = 0, 'a' + self._results[f] = 0, ACTION_ADD def queueget(self, f): """queues a file to be marked modified in the dirstate Meant for use by custom merge drivers.""" - self._results[f] = 0, 'g' + self._results[f] = 0, ACTION_GET def _getcheckunknownconfig(repo, section, name): config = repo.ui.config(section, name) @@ -771,14 +794,14 @@ checkunknowndirs = _unknowndirschecker() for f, (m, args, msg) in actions.iteritems(): - if m in ('c', 'dc'): + if m in (ACTION_CREATED, ACTION_DELETED_CHANGED): if _checkunknownfile(repo, wctx, mctx, f): fileconflicts.add(f) elif pathconfig and f not in wctx: path = checkunknowndirs(repo, wctx, f) if path is not None: pathconflicts.add(path) - elif m == 'dg': + elif m == ACTION_LOCAL_DIR_RENAME_GET: if _checkunknownfile(repo, wctx, mctx, f, args[0]): fileconflicts.add(f) @@ -790,7 +813,7 @@ collectconflicts(unknownconflicts, unknownconfig) else: for f, (m, args, msg) in actions.iteritems(): - if m == 'cm': + if m == ACTION_CREATED_MERGE: fl2, anc = args different = _checkunknownfile(repo, wctx, mctx, f) if repo.dirstate._ignore(f): @@ -811,16 +834,16 @@ # don't like an abort happening in the middle of # merge.update. if not different: - actions[f] = ('g', (fl2, False), "remote created") + actions[f] = (ACTION_GET, (fl2, False), 'remote created') elif mergeforce or config == 'abort': - actions[f] = ('m', (f, f, None, False, anc), - "remote differs from untracked local") + actions[f] = (ACTION_MERGE, (f, f, None, False, anc), + 'remote differs from untracked local') elif config == 'abort': abortconflicts.add(f) else: if config == 'warn': warnconflicts.add(f) - actions[f] = ('g', (fl2, True), "remote created") + actions[f] = (ACTION_GET, (fl2, True), 'remote created') for f in sorted(abortconflicts): warn = repo.ui.warn @@ -842,11 +865,11 @@ repo.ui.warn(_("%s: replacing untracked files in directory\n") % f) for f, (m, args, msg) in actions.iteritems(): - if m == 'c': + if m == ACTION_CREATED: backup = (f in fileconflicts or f in pathconflicts or any(p in pathconflicts for p in util.finddirs(f))) flags, = args - actions[f] = ('g', (flags, backup), msg) + actions[f] = (ACTION_GET, (flags, backup), msg) def _forgetremoved(wctx, mctx, branchmerge): """ @@ -864,9 +887,9 @@ """ actions = {} - m = 'f' + m = ACTION_FORGET if branchmerge: - m = 'r' + m = ACTION_REMOVE for f in wctx.deleted(): if f not in mctx: actions[f] = m, None, "forget deleted" @@ -874,7 +897,7 @@ if not branchmerge: for f in wctx.removed(): if f not in mctx: - actions[f] = 'f', None, "forget removed" + actions[f] = ACTION_FORGET, None, "forget removed" return actions @@ -883,19 +906,20 @@ pmmf = set(wmf) if actions: - # k, dr, e and rd are no-op - for m in 'a', 'am', 'f', 'g', 'cd', 'dc': + # KEEP and EXEC are no-op + for m in (ACTION_ADD, ACTION_ADD_MODIFIED, ACTION_FORGET, ACTION_GET, + ACTION_CHANGED_DELETED, ACTION_DELETED_CHANGED): for f, args, msg in actions[m]: pmmf.add(f) - for f, args, msg in actions['r']: + for f, args, msg in actions[ACTION_REMOVE]: pmmf.discard(f) - for f, args, msg in actions['dm']: + for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]: f2, flags = args pmmf.discard(f2) pmmf.add(f) - for f, args, msg in actions['dg']: + for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]: pmmf.add(f) - for f, args, msg in actions['m']: + for f, args, msg in actions[ACTION_MERGE]: f1, f2, fa, move, anc = args if move: pmmf.discard(f1) @@ -971,7 +995,8 @@ deletedfiles = set() for f, (m, args, msg) in actions.items(): - if m in ('c', 'dc', 'm', 'cm'): + if m in (ACTION_CREATED, ACTION_DELETED_CHANGED, ACTION_MERGE, + ACTION_CREATED_MERGE): # This action may create a new local file. createdfiledirs.update(util.finddirs(f)) if mf.hasdir(f): @@ -980,13 +1005,13 @@ # will be checked once we know what all the deleted files are. remoteconflicts.add(f) # Track the names of all deleted files. - if m == 'r': + if m == ACTION_REMOVE: deletedfiles.add(f) - if m == 'm': + if m == ACTION_MERGE: f1, f2, fa, move, anc = args if move: deletedfiles.add(f1) - if m == 'dm': + if m == ACTION_DIR_RENAME_MOVE_LOCAL: f2, flags = args deletedfiles.add(f2) @@ -1002,7 +1027,10 @@ # A file is in a directory which aliases a local file. # We will need to rename the local file. localconflicts.add(p) - if p in actions and actions[p][0] in ('c', 'dc', 'm', 'cm'): + if p in actions and actions[p][0] in (ACTION_CREATED, + ACTION_DELETED_CHANGED, + ACTION_MERGE, + ACTION_CREATED_MERGE): # The file is in a directory which aliases a remote file. # This is an internal inconsistency within the remote # manifest. @@ -1013,8 +1041,10 @@ if p not in deletedfiles: ctxname = bytes(wctx).rstrip('+') pnew = util.safename(p, ctxname, wctx, set(actions.keys())) - actions[pnew] = ('pr', (p,), "local path conflict") - actions[p] = ('p', (pnew, 'l'), "path conflict") + actions[pnew] = (ACTION_PATH_CONFLICT_RESOLVE, (p,), + 'local path conflict') + actions[p] = (ACTION_PATH_CONFLICT, (pnew, 'l'), + 'path conflict') if remoteconflicts: # Check if all files in the conflicting directories have been removed. @@ -1023,14 +1053,16 @@ if f not in deletedfiles: m, args, msg = actions[p] pnew = util.safename(p, ctxname, wctx, set(actions.keys())) - if m in ('dc', 'm'): + if m in (ACTION_DELETED_CHANGED, ACTION_MERGE): # Action was merge, just update target. actions[pnew] = (m, args, msg) else: # Action was create, change to renamed get action. fl = args[0] - actions[pnew] = ('dg', (p, fl), "remote path conflict") - actions[p] = ('p', (pnew, 'r'), "path conflict") + actions[pnew] = (ACTION_LOCAL_DIR_RENAME_GET, (p, fl), + 'remote path conflict') + actions[p] = (ACTION_PATH_CONFLICT, (pnew, ACTION_REMOVE), + 'path conflict') remoteconflicts.remove(p) break @@ -1108,77 +1140,80 @@ if f not in ma: fa = copy.get(f, None) if fa is not None: - actions[f] = ('m', (f, f, fa, False, pa.node()), - "both renamed from " + fa) + actions[f] = (ACTION_MERGE, (f, f, fa, False, pa.node()), + 'both renamed from %s' % fa) else: - actions[f] = ('m', (f, f, None, False, pa.node()), - "both created") + actions[f] = (ACTION_MERGE, (f, f, None, False, pa.node()), + 'both created') else: a = ma[f] fla = ma.flags(f) nol = 'l' not in fl1 + fl2 + fla if n2 == a and fl2 == fla: - actions[f] = ('k', (), "remote unchanged") + actions[f] = (ACTION_KEEP, (), 'remote unchanged') elif n1 == a and fl1 == fla: # local unchanged - use remote if n1 == n2: # optimization: keep local content - actions[f] = ('e', (fl2,), "update permissions") + actions[f] = (ACTION_EXEC, (fl2,), 'update permissions') else: - actions[f] = ('g', (fl2, False), "remote is newer") + actions[f] = (ACTION_GET, (fl2, False), + 'remote is newer') elif nol and n2 == a: # remote only changed 'x' - actions[f] = ('e', (fl2,), "update permissions") + actions[f] = (ACTION_EXEC, (fl2,), 'update permissions') elif nol and n1 == a: # local only changed 'x' - actions[f] = ('g', (fl1, False), "remote is newer") + actions[f] = (ACTION_GET, (fl1, False), 'remote is newer') else: # both changed something - actions[f] = ('m', (f, f, f, False, pa.node()), - "versions differ") + actions[f] = (ACTION_MERGE, (f, f, f, False, pa.node()), + 'versions differ') elif n1: # file exists only on local side if f in copied: pass # we'll deal with it on m2 side elif f in movewithdir: # directory rename, move local f2 = movewithdir[f] if f2 in m2: - actions[f2] = ('m', (f, f2, None, True, pa.node()), - "remote directory rename, both created") + actions[f2] = (ACTION_MERGE, (f, f2, None, True, pa.node()), + 'remote directory rename, both created') else: - actions[f2] = ('dm', (f, fl1), - "remote directory rename - move from " + f) + actions[f2] = (ACTION_DIR_RENAME_MOVE_LOCAL, (f, fl1), + 'remote directory rename - move from %s' % f) elif f in copy: f2 = copy[f] - actions[f] = ('m', (f, f2, f2, False, pa.node()), - "local copied/moved from " + f2) + actions[f] = (ACTION_MERGE, (f, f2, f2, False, pa.node()), + 'local copied/moved from %s' % f2) elif f in ma: # clean, a different, no remote if n1 != ma[f]: if acceptremote: - actions[f] = ('r', None, "remote delete") + actions[f] = (ACTION_REMOVE, None, 'remote delete') else: - actions[f] = ('cd', (f, None, f, False, pa.node()), - "prompt changed/deleted") + actions[f] = (ACTION_CHANGED_DELETED, + (f, None, f, False, pa.node()), + 'prompt changed/deleted') elif n1 == addednodeid: # This extra 'a' is added by working copy manifest to mark # the file as locally added. We should forget it instead of # deleting it. - actions[f] = ('f', None, "remote deleted") + actions[f] = (ACTION_FORGET, None, 'remote deleted') else: - actions[f] = ('r', None, "other deleted") + actions[f] = (ACTION_REMOVE, None, 'other deleted') elif n2: # file exists only on remote side if f in copied: pass # we'll deal with it on m1 side elif f in movewithdir: f2 = movewithdir[f] if f2 in m1: - actions[f2] = ('m', (f2, f, None, False, pa.node()), - "local directory rename, both created") + actions[f2] = (ACTION_MERGE, + (f2, f, None, False, pa.node()), + 'local directory rename, both created') else: - actions[f2] = ('dg', (f, fl2), - "local directory rename - get from " + f) + actions[f2] = (ACTION_LOCAL_DIR_RENAME_GET, (f, fl2), + 'local directory rename - get from %s' % f) elif f in copy: f2 = copy[f] if f2 in m2: - actions[f] = ('m', (f2, f, f2, False, pa.node()), - "remote copied from " + f2) + actions[f] = (ACTION_MERGE, (f2, f, f2, False, pa.node()), + 'remote copied from %s' % f2) else: - actions[f] = ('m', (f2, f, f2, True, pa.node()), - "remote moved from " + f2) + actions[f] = (ACTION_MERGE, (f2, f, f2, True, pa.node()), + 'remote moved from %s' % f2) elif f not in ma: # local unknown, remote created: the logic is described by the # following table: @@ -1192,12 +1227,12 @@ # Checking whether the files are different is expensive, so we # don't do that when we can avoid it. if not force: - actions[f] = ('c', (fl2,), "remote created") + actions[f] = (ACTION_CREATED, (fl2,), 'remote created') elif not branchmerge: - actions[f] = ('c', (fl2,), "remote created") + actions[f] = (ACTION_CREATED, (fl2,), 'remote created') else: - actions[f] = ('cm', (fl2, pa.node()), - "remote created, get or merge") + actions[f] = (ACTION_CREATED_MERGE, (fl2, pa.node()), + 'remote created, get or merge') elif n2 != ma[f]: df = None for d in dirmove: @@ -1206,13 +1241,15 @@ df = dirmove[d] + f[len(d):] break if df is not None and df in m1: - actions[df] = ('m', (df, f, f, False, pa.node()), - "local directory rename - respect move from " + f) + actions[df] = (ACTION_MERGE, (df, f, f, False, pa.node()), + 'local directory rename - respect move ' + 'from %s' % f) elif acceptremote: - actions[f] = ('c', (fl2,), "remote recreating") + actions[f] = (ACTION_CREATED, (fl2,), 'remote recreating') else: - actions[f] = ('dc', (None, f, f, False, pa.node()), - "prompt deleted/changed") + actions[f] = (ACTION_DELETED_CHANGED, + (None, f, f, False, pa.node()), + 'prompt deleted/changed') if repo.ui.configbool('experimental', 'merge.checkpathconflicts'): # If we are merging, look for path conflicts. @@ -1226,10 +1263,12 @@ # We force a copy of actions.items() because we're going to mutate # actions as we resolve trivial conflicts. for f, (m, args, msg) in list(actions.items()): - if m == 'cd' and f in ancestor and not wctx[f].cmp(ancestor[f]): + if (m == ACTION_CHANGED_DELETED and f in ancestor + and not wctx[f].cmp(ancestor[f])): # local did change but ended up with same content - actions[f] = 'r', None, "prompt same" - elif m == 'dc' and f in ancestor and not mctx[f].cmp(ancestor[f]): + actions[f] = ACTION_REMOVE, None, 'prompt same' + elif (m == ACTION_DELETED_CHANGED and f in ancestor + and not mctx[f].cmp(ancestor[f])): # remote did change but ended up with same content del actions[f] # don't get = keep local deleted @@ -1293,18 +1332,18 @@ if all(a == l[0] for a in l[1:]): # len(bids) is > 1 repo.ui.note(_(" %s: consensus for %s\n") % (f, m)) actions[f] = l[0] - if m == 'dm': + if m == ACTION_DIR_RENAME_MOVE_LOCAL: dms.append(f) continue # If keep is an option, just do it. - if 'k' in bids: + if ACTION_KEEP in bids: repo.ui.note(_(" %s: picking 'keep' action\n") % f) - actions[f] = bids['k'][0] + actions[f] = bids[ACTION_KEEP][0] continue # If there are gets and they all agree [how could they not?], do it. - if 'g' in bids: - ga0 = bids['g'][0] - if all(a == ga0 for a in bids['g'][1:]): + if ACTION_GET in bids: + ga0 = bids[ACTION_GET][0] + if all(a == ga0 for a in bids[ACTION_GET][1:]): repo.ui.note(_(" %s: picking 'get' action\n") % f) actions[f] = ga0 continue @@ -1319,14 +1358,14 @@ repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') % (f, m)) actions[f] = l[0] - if m == 'dm': + if m == ACTION_DIR_RENAME_MOVE_LOCAL: dms.append(f) continue # Work around 'dm' that can cause multiple actions for the same file for f in dms: dm, (f0, flags), msg = actions[f] - assert dm == 'dm', dm - if f0 in actions and actions[f0][0] == 'r': + assert dm == ACTION_DIR_RENAME_MOVE_LOCAL, dm + if f0 in actions and actions[f0][0] == ACTION_REMOVE: # We have one bid for removing a file and another for moving it. # These two could be merged as first move and then delete ... # but instead drop moving and just delete. @@ -1431,7 +1470,8 @@ # Skipping 'a', 'am', 'f', 'r', 'dm', 'e', 'k', 'p' and 'pr', because they # don't touch the context to be merged in. 'cd' is skipped, because # changed/deleted never resolves to something from the remote side. - oplist = [actions[a] for a in 'g dc dg m'.split()] + oplist = [actions[a] for a in (ACTION_GET, ACTION_DELETED_CHANGED, + ACTION_LOCAL_DIR_RENAME_GET, ACTION_MERGE)] prefetch = scmutil.fileprefetchhooks prefetch(repo, ctx, [f for sublist in oplist for f, args, msg in sublist]) @@ -1486,9 +1526,9 @@ l.sort() # 'cd' and 'dc' actions are treated like other merge conflicts - mergeactions = sorted(actions['cd']) - mergeactions.extend(sorted(actions['dc'])) - mergeactions.extend(actions['m']) + mergeactions = sorted(actions[ACTION_CHANGED_DELETED]) + mergeactions.extend(sorted(actions[ACTION_DELETED_CHANGED])) + mergeactions.extend(actions[ACTION_MERGE]) for f, args, msg in mergeactions: f1, f2, fa, move, anc = args if f == '.hgsubstate': # merged internally @@ -1523,14 +1563,15 @@ wctx[f].audit() wctx[f].remove() - numupdates = sum(len(l) for m, l in actions.items() if m != 'k') + numupdates = sum(len(l) for m, l in actions.items() + if m != ACTION_KEEP) z = 0 - if [a for a in actions['r'] if a[0] == '.hgsubstate']: + if [a for a in actions[ACTION_REMOVE] if a[0] == '.hgsubstate']: subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) # record path conflicts - for f, args, msg in actions['p']: + for f, args, msg in actions[ACTION_PATH_CONFLICT]: f1, fo = args s = repo.ui.status s(_("%s: path conflict - a file or link has the same name as a " @@ -1550,14 +1591,14 @@ # remove in parallel (must come before resolving path conflicts and getting) prog = worker.worker(repo.ui, cost, batchremove, (repo, wctx), - actions['r']) + actions[ACTION_REMOVE]) for i, item in prog: z += i progress(_updating, z, item=item, total=numupdates, unit=_files) - removed = len(actions['r']) + removed = len(actions[ACTION_REMOVE]) # resolve path conflicts (must come before getting) - for f, args, msg in actions['pr']: + for f, args, msg in actions[ACTION_PATH_CONFLICT_RESOLVE]: repo.ui.debug(" %s: %s -> pr\n" % (f, msg)) f0, = args if wctx[f0].lexists(): @@ -1570,40 +1611,40 @@ # get in parallel prog = worker.worker(repo.ui, cost, batchget, (repo, mctx, wctx), - actions['g']) + actions[ACTION_GET]) for i, item in prog: z += i progress(_updating, z, item=item, total=numupdates, unit=_files) - updated = len(actions['g']) + updated = len(actions[ACTION_GET]) - if [a for a in actions['g'] if a[0] == '.hgsubstate']: + if [a for a in actions[ACTION_GET] if a[0] == '.hgsubstate']: subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels) # forget (manifest only, just log it) (must come first) - for f, args, msg in actions['f']: + for f, args, msg in actions[ACTION_FORGET]: repo.ui.debug(" %s: %s -> f\n" % (f, msg)) z += 1 progress(_updating, z, item=f, total=numupdates, unit=_files) # re-add (manifest only, just log it) - for f, args, msg in actions['a']: + for f, args, msg in actions[ACTION_ADD]: repo.ui.debug(" %s: %s -> a\n" % (f, msg)) z += 1 progress(_updating, z, item=f, total=numupdates, unit=_files) # re-add/mark as modified (manifest only, just log it) - for f, args, msg in actions['am']: + for f, args, msg in actions[ACTION_ADD_MODIFIED]: repo.ui.debug(" %s: %s -> am\n" % (f, msg)) z += 1 progress(_updating, z, item=f, total=numupdates, unit=_files) # keep (noop, just log it) - for f, args, msg in actions['k']: + for f, args, msg in actions[ACTION_KEEP]: repo.ui.debug(" %s: %s -> k\n" % (f, msg)) # no progress # directory rename, move local - for f, args, msg in actions['dm']: + for f, args, msg in actions[ACTION_DIR_RENAME_MOVE_LOCAL]: repo.ui.debug(" %s: %s -> dm\n" % (f, msg)) z += 1 progress(_updating, z, item=f, total=numupdates, unit=_files) @@ -1615,7 +1656,7 @@ updated += 1 # local directory rename, get - for f, args, msg in actions['dg']: + for f, args, msg in actions[ACTION_LOCAL_DIR_RENAME_GET]: repo.ui.debug(" %s: %s -> dg\n" % (f, msg)) z += 1 progress(_updating, z, item=f, total=numupdates, unit=_files) @@ -1625,7 +1666,7 @@ updated += 1 # exec - for f, args, msg in actions['e']: + for f, args, msg in actions[ACTION_EXEC]: repo.ui.debug(" %s: %s -> e\n" % (f, msg)) z += 1 progress(_updating, z, item=f, total=numupdates, unit=_files) @@ -1703,17 +1744,17 @@ extraactions = ms.actions() if extraactions: - mfiles = set(a[0] for a in actions['m']) + mfiles = set(a[0] for a in actions[ACTION_MERGE]) for k, acts in extraactions.iteritems(): actions[k].extend(acts) - # Remove these files from actions['m'] as well. This is important - # because in recordupdates, files in actions['m'] are processed - # after files in other actions, and the merge driver might add - # files to those actions via extraactions above. This can lead to a - # file being recorded twice, with poor results. This is especially - # problematic for actions['r'] (currently only possible with the - # merge driver in the initial merge process; interrupted merges - # don't go through this flow). + # Remove these files from actions[ACTION_MERGE] as well. This is + # important because in recordupdates, files in actions[ACTION_MERGE] + # are processed after files in other actions, and the merge driver + # might add files to those actions via extraactions above. This can + # lead to a file being recorded twice, with poor results. This is + # especially problematic for actions[ACTION_REMOVE] (currently only + # possible with the merge driver in the initial merge process; + # interrupted merges don't go through this flow). # # The real fix here is to have indexes by both file and action so # that when the action for a file is changed it is automatically @@ -1724,7 +1765,8 @@ # those lists aren't consulted again. mfiles.difference_update(a[0] for a in acts) - actions['m'] = [a for a in actions['m'] if a[0] in mfiles] + actions[ACTION_MERGE] = [a for a in actions[ACTION_MERGE] + if a[0] in mfiles] progress(_updating, None, total=numupdates, unit=_files) return updateresult(updated, merged, removed, unresolved) @@ -1732,18 +1774,18 @@ def recordupdates(repo, actions, branchmerge): "record merge actions to the dirstate" # remove (must come first) - for f, args, msg in actions.get('r', []): + for f, args, msg in actions.get(ACTION_REMOVE, []): if branchmerge: repo.dirstate.remove(f) else: repo.dirstate.drop(f) # forget (must come first) - for f, args, msg in actions.get('f', []): + for f, args, msg in actions.get(ACTION_FORGET, []): repo.dirstate.drop(f) # resolve path conflicts - for f, args, msg in actions.get('pr', []): + for f, args, msg in actions.get(ACTION_PATH_CONFLICT_RESOLVE, []): f0, = args origf0 = repo.dirstate.copied(f0) or f0 repo.dirstate.add(f) @@ -1754,33 +1796,33 @@ repo.dirstate.drop(f0) # re-add - for f, args, msg in actions.get('a', []): + for f, args, msg in actions.get(ACTION_ADD, []): repo.dirstate.add(f) # re-add/mark as modified - for f, args, msg in actions.get('am', []): + for f, args, msg in actions.get(ACTION_ADD_MODIFIED, []): if branchmerge: repo.dirstate.normallookup(f) else: repo.dirstate.add(f) # exec change - for f, args, msg in actions.get('e', []): + for f, args, msg in actions.get(ACTION_EXEC, []): repo.dirstate.normallookup(f) # keep - for f, args, msg in actions.get('k', []): + for f, args, msg in actions.get(ACTION_KEEP, []): pass # get - for f, args, msg in actions.get('g', []): + for f, args, msg in actions.get(ACTION_GET, []): if branchmerge: repo.dirstate.otherparent(f) else: repo.dirstate.normal(f) # merge - for f, args, msg in actions.get('m', []): + for f, args, msg in actions.get(ACTION_MERGE, []): f1, f2, fa, move, anc = args if branchmerge: # We've done a branch merge, mark this file as merged @@ -1805,7 +1847,7 @@ repo.dirstate.drop(f1) # directory rename, move local - for f, args, msg in actions.get('dm', []): + for f, args, msg in actions.get(ACTION_DIR_RENAME_MOVE_LOCAL, []): f0, flag = args if branchmerge: repo.dirstate.add(f) @@ -1816,7 +1858,7 @@ repo.dirstate.drop(f0) # directory rename, get - for f, args, msg in actions.get('dg', []): + for f, args, msg in actions.get(ACTION_LOCAL_DIR_RENAME_GET, []): f0, flag = args if branchmerge: repo.dirstate.add(f) @@ -1989,7 +2031,8 @@ if updatecheck == 'noconflict': for f, (m, args, msg) in actionbyfile.iteritems(): - if m not in ('g', 'k', 'e', 'r', 'pr'): + if m not in (ACTION_GET, ACTION_KEEP, ACTION_EXEC, + ACTION_REMOVE, ACTION_PATH_CONFLICT_RESOLVE): msg = _("conflicting changes") hint = _("commit or update --clean to discard changes") raise error.Abort(msg, hint=hint) @@ -2002,30 +2045,45 @@ m, args, msg = actionbyfile[f] prompts = filemerge.partextras(labels) prompts['f'] = f - if m == 'cd': + if m == ACTION_CHANGED_DELETED: if repo.ui.promptchoice( _("local%(l)s changed %(f)s which other%(o)s deleted\n" "use (c)hanged version or (d)elete?" "$$ &Changed $$ &Delete") % prompts, 0): - actionbyfile[f] = ('r', None, "prompt delete") + actionbyfile[f] = (ACTION_REMOVE, None, 'prompt delete') elif f in p1: - actionbyfile[f] = ('am', None, "prompt keep") + actionbyfile[f] = (ACTION_ADD_MODIFIED, None, 'prompt keep') else: - actionbyfile[f] = ('a', None, "prompt keep") - elif m == 'dc': + actionbyfile[f] = (ACTION_ADD, None, 'prompt keep') + elif m == ACTION_DELETED_CHANGED: f1, f2, fa, move, anc = args flags = p2[f2].flags() if repo.ui.promptchoice( _("other%(o)s changed %(f)s which local%(l)s deleted\n" "use (c)hanged version or leave (d)eleted?" "$$ &Changed $$ &Deleted") % prompts, 0) == 0: - actionbyfile[f] = ('g', (flags, False), "prompt recreating") + actionbyfile[f] = (ACTION_GET, (flags, False), + 'prompt recreating') else: del actionbyfile[f] # Convert to dictionary-of-lists format actions = dict((m, []) - for m in 'a am f g cd dc r dm dg m e k p pr'.split()) + for m in ( + ACTION_ADD, + ACTION_ADD_MODIFIED, + ACTION_FORGET, + ACTION_GET, + ACTION_CHANGED_DELETED, + ACTION_DELETED_CHANGED, + ACTION_REMOVE, + ACTION_DIR_RENAME_MOVE_LOCAL, + ACTION_LOCAL_DIR_RENAME_GET, + ACTION_MERGE, + ACTION_EXEC, + ACTION_KEEP, + ACTION_PATH_CONFLICT, + ACTION_PATH_CONFLICT_RESOLVE)) for f, (m, args, msg) in actionbyfile.iteritems(): if m not in actions: actions[m] = [] @@ -2088,7 +2146,7 @@ if (fsmonitorwarning and not fsmonitorenabled and p1.node() == nullid - and len(actions['g']) >= fsmonitorthreshold + and len(actions[ACTION_GET]) >= fsmonitorthreshold and pycompat.sysplatform.startswith(('linux', 'darwin'))): repo.ui.warn( _('(warning: large working directory being used without '