# HG changeset patch # User Siddharth Agarwal # Date 2015-11-30 18:19:39 # Node ID d837da26155e759257902a8cd1c187d510956fb3 # Parent 6f045b563fa50d42ea179fbbb601979a7877ab7c 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. diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -479,7 +479,10 @@ class mergestate(object): if fcd.isabsent(): # dc: remote picked action = 'g' elif fco.isabsent(): # cd: local picked - action = 'a' + if dfile in self.localctx: + action = 'am' + else: + action = 'a' # else: regular merges (no action necessary) self._results[dfile] = r, action @@ -524,7 +527,7 @@ class mergestate(object): def actions(self): """return lists of actions to perform on the dirstate""" - actions = {'r': [], 'f': [], 'a': [], 'g': []} + actions = {'r': [], 'f': [], 'a': [], 'am': [], 'g': []} for f, (r, action) in self._results.iteritems(): if action is not None: actions[action].append((f, None, "merge result")) @@ -631,7 +634,7 @@ def _checkcollision(repo, wmf, actions): if actions: # k, dr, e and rd are no-op - for m in 'a', 'f', 'g', 'cd', 'dc': + for m in 'a', 'am', 'f', 'g', 'cd', 'dc': for f, args, msg in actions[m]: pmmf.add(f) for f, args, msg in actions['r']: @@ -1065,6 +1068,12 @@ def applyupdates(repo, actions, wctx, mc 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']: + 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']: repo.ui.debug(" %s: %s -> k\n" % (f, msg)) @@ -1189,6 +1198,13 @@ def recordupdates(repo, actions, branchm if not branchmerge: repo.dirstate.add(f) + # re-add/mark as modified + for f, args, msg in actions.get('am', []): + if branchmerge: + repo.dirstate.normallookup(f) + else: + repo.dirstate.add(f) + # exec change for f, args, msg in actions.get('e', []): repo.dirstate.normallookup(f) @@ -1390,7 +1406,7 @@ def update(repo, node, branchmerge, forc repo, wc, p2, pas, branchmerge, force, partial, mergeancestor, followcopies) # Convert to dictionary-of-lists format - actions = dict((m, []) for m in 'a f g cd dc r dm dg m e k'.split()) + actions = dict((m, []) for m in 'a am f g cd dc r dm dg m e k'.split()) for f, (m, args, msg) in actionbyfile.iteritems(): if m not in actions: actions[m] = [] @@ -1411,6 +1427,8 @@ def update(repo, node, branchmerge, forc "use (c)hanged version or (d)elete?" "$$ &Changed $$ &Delete") % f, 0): actions['r'].append((f, None, "prompt delete")) + elif f in p1: + actions['am'].append((f, None, "prompt keep")) else: actions['a'].append((f, None, "prompt keep")) diff --git a/tests/test-rename-merge2.t b/tests/test-rename-merge2.t --- a/tests/test-rename-merge2.t +++ b/tests/test-rename-merge2.t @@ -725,7 +725,7 @@ m "um a c" "um x c" " " "10 do merg use (c)hanged version or (d)elete? c preserving b for resolve of b preserving rev for resolve of rev - a: prompt keep -> a + a: prompt keep -> am b: both created -> m (premerge) picked tool 'python ../merge' for b (binary False symlink False) merging b