[PATCH 1 of 9] merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH 1 of 9] merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)

Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1595507594 -19800
#      Thu Jul 23 18:03:14 2020 +0530
# Node ID f3f40eb3553885db4ff8a67e298602c842fceea1
# Parent  4b923da0cb86f0e1ce3302b72471319c18bb4470
# EXP-Topic merge-refactor
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)

Earlier, manifestmerge() and calculateupdates() returns a tuple of three things.
I wanted to add one more thing to return value.

Introducing a special class which represents results of a merge will help
understand better and also ease adding new return values.

Differential Revision: https://phab.mercurial-scm.org/D8799

diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py
--- a/hgext/convert/hg.py
+++ b/hgext/convert/hg.py
@@ -217,7 +217,7 @@ class mercurial_sink(common.converter_si
         """
         anc = [p1ctx.ancestor(p2ctx)]
         # Calculate what files are coming from p2
-        actions, diverge, rename = mergemod.calculateupdates(
+        mresult = mergemod.calculateupdates(
             self.repo,
             p1ctx,
             p2ctx,
@@ -228,7 +228,7 @@ class mercurial_sink(common.converter_si
             followcopies=False,
         )
 
-        for file, (action, info, msg) in pycompat.iteritems(actions):
+        for file, (action, info, msg) in pycompat.iteritems(mresult.actions):
             if source.targetfilebelongstosource(file):
                 # If the file belongs to the source repo, ignore the p2
                 # since it will be covered by the existing fileset.
diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -543,16 +543,16 @@ def overridecalculateupdates(
     origfn, repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
 ):
     overwrite = force and not branchmerge
-    actions, diverge, renamedelete = origfn(
+    mresult = origfn(
         repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs
     )
 
     if overwrite:
-        return actions, diverge, renamedelete
+        return mresult
 
     # Convert to dictionary with filename as key and action as value.
     lfiles = set()
-    for f in actions:
+    for f in mresult.actions:
         splitstandin = lfutil.splitstandin(f)
         if splitstandin is not None and splitstandin in p1:
             lfiles.add(splitstandin)
@@ -561,8 +561,8 @@ def overridecalculateupdates(
 
     for lfile in sorted(lfiles):
         standin = lfutil.standin(lfile)
-        (lm, largs, lmsg) = actions.get(lfile, (None, None, None))
-        (sm, sargs, smsg) = actions.get(standin, (None, None, None))
+        (lm, largs, lmsg) = mresult.actions.get(lfile, (None, None, None))
+        (sm, sargs, smsg) = mresult.actions.get(standin, (None, None, None))
         if sm in (b'g', b'dc') and lm != b'r':
             if sm == b'dc':
                 f1, f2, fa, move, anc = sargs
@@ -578,14 +578,22 @@ def overridecalculateupdates(
                 % lfile
             )
             if repo.ui.promptchoice(usermsg, 0) == 0:  # pick remote largefile
-                actions[lfile] = (b'r', None, b'replaced by standin')
-                actions[standin] = (b'g', sargs, b'replaces standin')
+                mresult.actions[lfile] = (b'r', None, b'replaced by standin')
+                mresult.actions[standin] = (b'g', sargs, b'replaces standin')
             else:  # keep local normal file
-                actions[lfile] = (b'k', None, b'replaces standin')
+                mresult.actions[lfile] = (b'k', None, b'replaces standin')
                 if branchmerge:
-                    actions[standin] = (b'k', None, b'replaced by non-standin')
+                    mresult.actions[standin] = (
+                        b'k',
+                        None,
+                        b'replaced by non-standin',
+                    )
                 else:
-                    actions[standin] = (b'r', None, b'replaced by non-standin')
+                    mresult.actions[standin] = (
+                        b'r',
+                        None,
+                        b'replaced by non-standin',
+                    )
         elif lm in (b'g', b'dc') and sm != b'r':
             if lm == b'dc':
                 f1, f2, fa, move, anc = largs
@@ -603,24 +611,32 @@ def overridecalculateupdates(
             if repo.ui.promptchoice(usermsg, 0) == 0:  # keep local largefile
                 if branchmerge:
                     # largefile can be restored from standin safely
-                    actions[lfile] = (b'k', None, b'replaced by standin')
-                    actions[standin] = (b'k', None, b'replaces standin')
+                    mresult.actions[lfile] = (
+                        b'k',
+                        None,
+                        b'replaced by standin',
+                    )
+                    mresult.actions[standin] = (b'k', None, b'replaces standin')
                 else:
                     # "lfile" should be marked as "removed" without
                     # removal of itself
-                    actions[lfile] = (
+                    mresult.actions[lfile] = (
                         b'lfmr',
                         None,
                         b'forget non-standin largefile',
                     )
 
                     # linear-merge should treat this largefile as 're-added'
-                    actions[standin] = (b'a', None, b'keep standin')
+                    mresult.actions[standin] = (b'a', None, b'keep standin')
             else:  # pick remote normal file
-                actions[lfile] = (b'g', largs, b'replaces standin')
-                actions[standin] = (b'r', None, b'replaced by non-standin')
+                mresult.actions[lfile] = (b'g', largs, b'replaces standin')
+                mresult.actions[standin] = (
+                    b'r',
+                    None,
+                    b'replaced by non-standin',
+                )
 
-    return actions, diverge, renamedelete
+    return mresult
 
 
 @eh.wrapfunction(mergestatemod, b'recordupdates')
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -540,6 +540,41 @@ def _filternarrowactions(narrowmatch, br
             )
 
 
+class mergeresult(object):
+    ''''An object representing result of merging manifests.
+
+    It has information about what actions need to be performed on dirstate
+    mapping of divergent renames and other such cases. '''
+
+    def __init__(self, actions, diverge, renamedelete):
+        """
+        actions: dict of filename as keys and action related info as values
+        diverge: mapping of source name -> list of dest name for
+                 divergent renames
+        renamedelete: mapping of source name -> list of destinations for files
+                      deleted on one side and renamed on other.
+        """
+
+        self._actions = actions
+        self._diverge = diverge
+        self._renamedelete = renamedelete
+
+    @property
+    def actions(self):
+        return self._actions
+
+    @property
+    def diverge(self):
+        return self._diverge
+
+    @property
+    def renamedelete(self):
+        return self._renamedelete
+
+    def setactions(self, actions):
+        self._actions = actions
+
+
 def manifestmerge(
     repo,
     wctx,
@@ -559,12 +594,7 @@ def manifestmerge(
     matcher = matcher to filter file lists
     acceptremote = accept the incoming changes without prompting
 
-    Returns:
-
-    actions: dict of filename as keys and action related info as values
-    diverge: mapping of source name -> list of dest name for divergent renames
-    renamedelete: mapping of source name -> list of destinations for files
-                  deleted on one side and renamed on other.
+    Returns an object of mergeresult class
     """
     if matcher is not None and matcher.always():
         matcher = None
@@ -845,7 +875,7 @@ def manifestmerge(
     renamedelete = branch_copies1.renamedelete
     renamedelete.update(branch_copies2.renamedelete)
 
-    return actions, diverge, renamedelete
+    return mergeresult(actions, diverge, renamedelete)
 
 
 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
@@ -891,13 +921,13 @@ def calculateupdates(
 
     Also filters out actions which are unrequired if repository is sparse.
 
-    Returns same 3 element tuple as manifestmerge().
+    Returns mergeresult object same as manifestmerge().
     """
     # Avoid cycle.
     from . import sparse
 
     if len(ancestors) == 1:  # default
-        actions, diverge, renamedelete = manifestmerge(
+        mresult = manifestmerge(
             repo,
             wctx,
             mctx,
@@ -908,7 +938,7 @@ def calculateupdates(
             acceptremote,
             followcopies,
         )
-        _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
+        _checkunknownfiles(repo, wctx, mctx, force, mresult.actions, mergeforce)
 
     else:  # only when merge.preferancestor=* - the default
         repo.ui.note(
@@ -927,7 +957,7 @@ def calculateupdates(
         diverge, renamedelete = None, None
         for ancestor in ancestors:
             repo.ui.note(_(b'\ncalculating bids for ancestor %s\n') % ancestor)
-            actions, diverge1, renamedelete1 = manifestmerge(
+            mresult1 = manifestmerge(
                 repo,
                 wctx,
                 mctx,
@@ -939,16 +969,20 @@ def calculateupdates(
                 followcopies,
                 forcefulldiff=True,
             )
-            _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce)
+            _checkunknownfiles(
+                repo, wctx, mctx, force, mresult1.actions, mergeforce
+            )
 
             # Track the shortest set of warning on the theory that bid
             # merge will correctly incorporate more information
-            if diverge is None or len(diverge1) < len(diverge):
-                diverge = diverge1
-            if renamedelete is None or len(renamedelete) < len(renamedelete1):
-                renamedelete = renamedelete1
+            if diverge is None or len(mresult1.diverge) < len(diverge):
+                diverge = mresult1.diverge
+            if renamedelete is None or len(renamedelete) < len(
+                mresult1.renamedelete
+            ):
+                renamedelete = mresult1.renamedelete
 
-            for f, a in sorted(pycompat.iteritems(actions)):
+            for f, a in sorted(pycompat.iteritems(mresult1.actions)):
                 m, args, msg = a
                 if m == mergestatemod.ACTION_GET_OTHER_AND_STORE:
                     m = mergestatemod.ACTION_GET
@@ -1000,17 +1034,19 @@ def calculateupdates(
             actions[f] = l[0]
             continue
         repo.ui.note(_(b'end of auction\n\n'))
+        mresult = mergeresult(actions, diverge, renamedelete)
 
     if wctx.rev() is None:
         fractions = _forgetremoved(wctx, mctx, branchmerge)
-        actions.update(fractions)
+        mresult.actions.update(fractions)
 
     prunedactions = sparse.filterupdatesactions(
-        repo, wctx, mctx, branchmerge, actions
+        repo, wctx, mctx, branchmerge, mresult.actions
     )
-    _resolvetrivial(repo, wctx, mctx, ancestors[0], actions)
+    _resolvetrivial(repo, wctx, mctx, ancestors[0], mresult.actions)
 
-    return prunedactions, diverge, renamedelete
+    mresult.setactions(prunedactions)
+    return mresult
 
 
 def _getcwd():
@@ -1734,7 +1770,7 @@ def update(
             followcopies = False
 
         ### calculate phase
-        actionbyfile, diverge, renamedelete = calculateupdates(
+        mresult = calculateupdates(
             repo,
             wc,
             p2,
@@ -1747,6 +1783,8 @@ def update(
             mergeforce=mergeforce,
         )
 
+        actionbyfile = mresult.actions
+
         if updatecheck == UPDATECHECK_NO_CONFLICT:
             for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
                 if m not in (
@@ -1840,7 +1878,7 @@ def update(
                 _checkcollision(repo, wc.manifest(), actions)
 
         # divergent renames
-        for f, fl in sorted(pycompat.iteritems(diverge)):
+        for f, fl in sorted(pycompat.iteritems(mresult.diverge)):
             repo.ui.warn(
                 _(
                     b"note: possible conflict - %s was renamed "
@@ -1852,7 +1890,7 @@ def update(
                 repo.ui.warn(b" %s\n" % nf)
 
         # rename and delete
-        for f, fl in sorted(pycompat.iteritems(renamedelete)):
+        for f, fl in sorted(pycompat.iteritems(mresult.renamedelete)):
             repo.ui.warn(
                 _(
                     b"note: possible conflict - %s was deleted "

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 2 of 9] merge: introduce 'commitinfo' in mergeresult

Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1594723868 -19800
#      Tue Jul 14 16:21:08 2020 +0530
# Node ID 095b5d6b721c7068dd2e388e9b50fe3a29127eea
# Parent  f3f40eb3553885db4ff8a67e298602c842fceea1
# EXP-Topic merge-refactor
merge: introduce 'commitinfo' in mergeresult

commitinfo will be used to pass information which is required on commit phase
from the merge phase.

One common example is, merge chooses filenode from second parent and we need to
tell commit to choose that. Right now this one and related cases are not very
neatly implement and there is no clear line on how to pass on such information.
Upcoming patches will try to work on in this area and make things easier.

Differential Revision: https://phab.mercurial-scm.org/D8742

diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py
--- a/hgext/convert/hg.py
+++ b/hgext/convert/hg.py
@@ -217,6 +217,7 @@ class mercurial_sink(common.converter_si
         """
         anc = [p1ctx.ancestor(p2ctx)]
         # Calculate what files are coming from p2
+        # TODO: mresult.commitinfo might be able to get that info
         mresult = mergemod.calculateupdates(
             self.repo,
             p1ctx,
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -546,18 +546,21 @@ class mergeresult(object):
     It has information about what actions need to be performed on dirstate
     mapping of divergent renames and other such cases. '''
 
-    def __init__(self, actions, diverge, renamedelete):
+    def __init__(self, actions, diverge, renamedelete, commitinfo):
         """
         actions: dict of filename as keys and action related info as values
         diverge: mapping of source name -> list of dest name for
                  divergent renames
         renamedelete: mapping of source name -> list of destinations for files
                       deleted on one side and renamed on other.
+        commitinfo: dict containing data which should be used on commit
+                    contains a filename -> info mapping
         """
 
         self._actions = actions
         self._diverge = diverge
         self._renamedelete = renamedelete
+        self._commitinfo = commitinfo
 
     @property
     def actions(self):
@@ -571,6 +574,10 @@ class mergeresult(object):
     def renamedelete(self):
         return self._renamedelete
 
+    @property
+    def commitinfo(self):
+        return self._commitinfo
+
     def setactions(self, actions):
         self._actions = actions
 
@@ -608,6 +615,10 @@ def manifestmerge(
     branch_copies1 = copies.branch_copies()
     branch_copies2 = copies.branch_copies()
     diverge = {}
+    # information from merge which is needed at commit time
+    # for example choosing filelog of which parent to commit
+    # TODO: use specific constants in future for this mapping
+    commitinfo = {}
     if followcopies:
         branch_copies1, branch_copies2, diverge = copies.mergecopies(
             repo, wctx, p2, pa
@@ -701,6 +712,8 @@ def manifestmerge(
                             (fl2, False),
                             b'remote is newer',
                         )
+                        if branchmerge:
+                            commitinfo[f] = b'other'
                 elif nol and n2 == a:  # remote only changed 'x'
                     actions[f] = (
                         mergestatemod.ACTION_EXEC,
@@ -715,6 +728,8 @@ def manifestmerge(
                         (fl1, False),
                         b'remote is newer',
                     )
+                    if branchmerge:
+                        commitinfo[f] = b'other'
                 else:  # both changed something
                     actions[f] = (
                         mergestatemod.ACTION_MERGE,
@@ -875,7 +890,7 @@ def manifestmerge(
     renamedelete = branch_copies1.renamedelete
     renamedelete.update(branch_copies2.renamedelete)
 
-    return mergeresult(actions, diverge, renamedelete)
+    return mergeresult(actions, diverge, renamedelete, commitinfo)
 
 
 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
@@ -1034,7 +1049,8 @@ def calculateupdates(
             actions[f] = l[0]
             continue
         repo.ui.note(_(b'end of auction\n\n'))
-        mresult = mergeresult(actions, diverge, renamedelete)
+        # TODO: think about commitinfo when bid merge is used
+        mresult = mergeresult(actions, diverge, renamedelete, {})
 
     if wctx.rev() is None:
         fractions = _forgetremoved(wctx, mctx, branchmerge)

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 3 of 9] merge: pass commitinfo to applyupdates() and get it stored in mergestate

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1594724512 -19800
#      Tue Jul 14 16:31:52 2020 +0530
# Node ID 15b6efc31daf8fa412f9379dc55ab7e0df87b50b
# Parent  095b5d6b721c7068dd2e388e9b50fe3a29127eea
# EXP-Topic merge-refactor
merge: pass commitinfo to applyupdates() and get it stored in mergestate

This patch passes the commitinfo calulcated in manifestmerge() to applyupdates()
so that it can be read there and stored in mergestate. On commit, we can read
mergestate for such information and act accordingly.

This patch also makes ACTION_GET_OTHER_AND_STORE not required anymore. Next
patch will remove the messy code surrounding it.

Differential Revision: https://phab.mercurial-scm.org/D8743

diff --git a/hgext/remotefilelog/__init__.py b/hgext/remotefilelog/__init__.py
--- a/hgext/remotefilelog/__init__.py
+++ b/hgext/remotefilelog/__init__.py
@@ -479,7 +479,7 @@ def storewrapper(orig, requirements, pat
 
 # prefetch files before update
 def applyupdates(
-    orig, repo, actions, wctx, mctx, overwrite, wantfiledata, labels=None
+    orig, repo, actions, wctx, mctx, overwrite, wantfiledata, **opts
 ):
     if isenabled(repo):
         manifest = mctx.manifest()
@@ -488,9 +488,7 @@ def applyupdates(
             files.append((f, hex(manifest[f])))
         # batch fetch the needed files from the server
         repo.fileservice.prefetch(files)
-    return orig(
-        repo, actions, wctx, mctx, overwrite, wantfiledata, labels=labels
-    )
+    return orig(repo, actions, wctx, mctx, overwrite, wantfiledata, **opts)
 
 
 # Prefetch merge checkunknownfiles
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1241,12 +1241,21 @@ def emptyactions():
 
 
 def applyupdates(
-    repo, actions, wctx, mctx, overwrite, wantfiledata, labels=None
+    repo,
+    actions,
+    wctx,
+    mctx,
+    overwrite,
+    wantfiledata,
+    labels=None,
+    commitinfo=None,
 ):
     """apply the merge action list to the working directory
 
     wctx is the working copy context
     mctx is the context to be merged into the working copy
+    commitinfo is a mapping of information which needs to be stored somewhere
+               (probably mergestate) so that it can be used at commit time.
 
     Return a tuple of (counts, filedata), where counts is a tuple
     (updated, merged, removed, unresolved) that describes how many
@@ -1261,6 +1270,15 @@ def applyupdates(
         repo, wctx.p1().node(), mctx.node(), labels
     )
 
+    if commitinfo is None:
+        commitinfo = {}
+
+    for f, op in pycompat.iteritems(commitinfo):
+        # the other side of filenode was choosen while merging, store this in
+        # mergestate so that it can be reused on commit
+        if op == b'other':
+            ms.addmergedother(f)
+
     # add ACTION_GET_OTHER_AND_STORE to mergestate
     for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
         ms.addmergedother(e[0])
@@ -1935,7 +1953,14 @@ def update(
 
         wantfiledata = updatedirstate and not branchmerge
         stats, getfiledata = applyupdates(
-            repo, actions, wc, p2, overwrite, wantfiledata, labels=labels
+            repo,
+            actions,
+            wc,
+            p2,
+            overwrite,
+            wantfiledata,
+            labels=labels,
+            commitinfo=mresult.commitinfo,
         )
 
         if updatedirstate:

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 4 of 9] merge: remove no longer required ACTION_GET_OTHER_AND_STORE

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1594725028 -19800
#      Tue Jul 14 16:40:28 2020 +0530
# Node ID 94e7528a24c54cdd8da2e1470a101d55ac87a1dd
# Parent  15b6efc31daf8fa412f9379dc55ab7e0df87b50b
# EXP-Topic merge-refactor
merge: remove no longer required ACTION_GET_OTHER_AND_STORE

In 1b8fd4af33189c84feadb47c74d659ec31cde3b9 I (ab)used merge actions to pass
info from manifestmerge() to applyupdates() and store info in mergestate.

In previous patches, we introduced a separate return value from manifestmerge()
and calculateupdates() and an argument to applyupdates() which achieved the same
thing.

Let's remove this no longer required messy code.

Differential Revision: https://phab.mercurial-scm.org/D8744

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -706,9 +706,7 @@ def manifestmerge(
                         )
                     else:
                         actions[f] = (
-                            mergestatemod.ACTION_GET_OTHER_AND_STORE
-                            if branchmerge
-                            else mergestatemod.ACTION_GET,
+                            mergestatemod.ACTION_GET,
                             (fl2, False),
                             b'remote is newer',
                         )
@@ -722,9 +720,7 @@ def manifestmerge(
                     )
                 elif nol and n1 == a:  # local only changed 'x'
                     actions[f] = (
-                        mergestatemod.ACTION_GET_OTHER_AND_STORE
-                        if branchmerge
-                        else mergestatemod.ACTION_GET,
+                        mergestatemod.ACTION_GET,
                         (fl1, False),
                         b'remote is newer',
                     )
@@ -999,8 +995,6 @@ def calculateupdates(
 
             for f, a in sorted(pycompat.iteritems(mresult1.actions)):
                 m, args, msg = a
-                if m == mergestatemod.ACTION_GET_OTHER_AND_STORE:
-                    m = mergestatemod.ACTION_GET
                 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m))
                 if f in fbids:
                     d = fbids[f]
@@ -1235,7 +1229,6 @@ def emptyactions():
             mergestatemod.ACTION_KEEP,
             mergestatemod.ACTION_PATH_CONFLICT,
             mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
-            mergestatemod.ACTION_GET_OTHER_AND_STORE,
         )
     }
 
@@ -1279,10 +1272,6 @@ def applyupdates(
         if op == b'other':
             ms.addmergedother(f)
 
-    # add ACTION_GET_OTHER_AND_STORE to mergestate
-    for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
-        ms.addmergedother(e[0])
-
     moves = []
     for m, l in actions.items():
         l.sort()
@@ -1827,7 +1816,6 @@ def update(
                     mergestatemod.ACTION_EXEC,
                     mergestatemod.ACTION_REMOVE,
                     mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
-                    mergestatemod.ACTION_GET_OTHER_AND_STORE,
                 ):
                     msg = _(b"conflicting changes")
                     hint = _(b"commit or update --clean to discard changes")
@@ -1898,10 +1886,6 @@ def update(
                 actions[m] = []
             actions[m].append((f, args, msg))
 
-        # ACTION_GET_OTHER_AND_STORE is a mergestatemod.ACTION_GET + store in mergestate
-        for e in actions[mergestatemod.ACTION_GET_OTHER_AND_STORE]:
-            actions[mergestatemod.ACTION_GET].append(e)
-
         if not util.fscasesensitive(repo.path):
             # check collision between files only in p2 for clean update
             if not branchmerge and (
diff --git a/mercurial/mergestate.py b/mercurial/mergestate.py
--- a/mercurial/mergestate.py
+++ b/mercurial/mergestate.py
@@ -113,8 +113,6 @@ ACTION_DIR_RENAME_MOVE_LOCAL = b'dm'
 ACTION_KEEP = b'k'
 ACTION_EXEC = b'e'
 ACTION_CREATED_MERGE = b'cm'
-# GET the other/remote side and store this info in mergestate
-ACTION_GET_OTHER_AND_STORE = b'gs'
 
 
 class mergestate(object):

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 5 of 9] merge: introduce hasconflicts() on mergeresult object

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1595580818 -19800
#      Fri Jul 24 14:23:38 2020 +0530
# Node ID b96b39636881b521a71cbdca9b202965f46be380
# Parent  94e7528a24c54cdd8da2e1470a101d55ac87a1dd
# EXP-Topic merge-refactor
merge: introduce hasconflicts() on mergeresult object

This and upcoming patches will improve the mergeresult object making it more
powerful and provide clean APIs for various things. Doing this will clean up the
core merge code which is present in `update()` a bit.

Differential Revision: https://phab.mercurial-scm.org/D8816

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -581,6 +581,21 @@ class mergeresult(object):
     def setactions(self, actions):
         self._actions = actions
 
+    def hasconflicts(self):
+        """ tells whether this merge resulted in some actions which can
+        result in conflicts or not """
+        for _, (m, _, _) in pycompat.iteritems(self._actions):
+            if m not in (
+                mergestatemod.ACTION_GET,
+                mergestatemod.ACTION_KEEP,
+                mergestatemod.ACTION_EXEC,
+                mergestatemod.ACTION_REMOVE,
+                mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
+            ):
+                return True
+
+        return False
+
 
 def manifestmerge(
     repo,
@@ -1809,17 +1824,10 @@ def update(
         actionbyfile = mresult.actions
 
         if updatecheck == UPDATECHECK_NO_CONFLICT:
-            for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
-                if m not in (
-                    mergestatemod.ACTION_GET,
-                    mergestatemod.ACTION_KEEP,
-                    mergestatemod.ACTION_EXEC,
-                    mergestatemod.ACTION_REMOVE,
-                    mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
-                ):
-                    msg = _(b"conflicting changes")
-                    hint = _(b"commit or update --clean to discard changes")
-                    raise error.Abort(msg, hint=hint)
+            if mresult.hasconflicts():
+                msg = _(b"conflicting changes")
+                hint = _(b"commit or update --clean to discard changes")
+                raise error.Abort(msg, hint=hint)
 
         # Prompt and create actions. Most of this is in the resolve phase
         # already, but we can't handle .hgsubstate in filemerge or

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 6 of 9] merge: move conversion of file-key dict to action-key dict in mergeresult

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1595582100 -19800
#      Fri Jul 24 14:45:00 2020 +0530
# Node ID 90aa9c3e8a0ee8b4ad7e807922f6d6a7d132328b
# Parent  b96b39636881b521a71cbdca9b202965f46be380
# EXP-Topic merge-refactor
merge: move conversion of file-key dict to action-key dict in mergeresult

Initially the actions dict which we get has file has keys, but later we want a
dict which has actions as keys. This patch moves code computing that to
mergeresult class as that's where it should be anyway.

Differential Revision: https://phab.mercurial-scm.org/D8817

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -578,6 +578,19 @@ class mergeresult(object):
     def commitinfo(self):
         return self._commitinfo
 
+    @property
+    def actionsdict(self):
+        """ returns a dictionary of actions to be perfomed with action as key
+        and a list of files and related arguments as values """
+        # Convert to dictionary-of-lists format
+        actions = emptyactions()
+        for f, (m, args, msg) in pycompat.iteritems(self._actions):
+            if m not in actions:
+                actions[m] = []
+            actions[m].append((f, args, msg))
+
+        return actions
+
     def setactions(self, actions):
         self._actions = actions
 
@@ -1821,8 +1834,6 @@ def update(
             mergeforce=mergeforce,
         )
 
-        actionbyfile = mresult.actions
-
         if updatecheck == UPDATECHECK_NO_CONFLICT:
             if mresult.hasconflicts():
                 msg = _(b"conflicting changes")
@@ -1832,9 +1843,9 @@ def update(
         # Prompt and create actions. Most of this is in the resolve phase
         # already, but we can't handle .hgsubstate in filemerge or
         # subrepoutil.submerge yet so we have to keep prompting for it.
-        if b'.hgsubstate' in actionbyfile:
+        if b'.hgsubstate' in mresult.actions:
             f = b'.hgsubstate'
-            m, args, msg = actionbyfile[f]
+            m, args, msg = mresult.actions[f]
             prompts = filemerge.partextras(labels)
             prompts[b'f'] = f
             if m == mergestatemod.ACTION_CHANGED_DELETED:
@@ -1847,19 +1858,19 @@ def update(
                     % prompts,
                     0,
                 ):
-                    actionbyfile[f] = (
+                    mresult.actions[f] = (
                         mergestatemod.ACTION_REMOVE,
                         None,
                         b'prompt delete',
                     )
                 elif f in p1:
-                    actionbyfile[f] = (
+                    mresult.actions[f] = (
                         mergestatemod.ACTION_ADD_MODIFIED,
                         None,
                         b'prompt keep',
                     )
                 else:
-                    actionbyfile[f] = (
+                    mresult.actions[f] = (
                         mergestatemod.ACTION_ADD,
                         None,
                         b'prompt keep',
@@ -1879,20 +1890,16 @@ def update(
                     )
                     == 0
                 ):
-                    actionbyfile[f] = (
+                    mresult.actions[f] = (
                         mergestatemod.ACTION_GET,
                         (flags, False),
                         b'prompt recreating',
                     )
                 else:
-                    del actionbyfile[f]
+                    del mresult.actions[f]
 
         # Convert to dictionary-of-lists format
-        actions = emptyactions()
-        for f, (m, args, msg) in pycompat.iteritems(actionbyfile):
-            if m not in actions:
-                actions[m] = []
-            actions[m].append((f, args, msg))
+        actions = mresult.actionsdict
 
         if not util.fscasesensitive(repo.path):
             # check collision between files only in p2 for clean update

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 7 of 9] merge: improve documentation of fbid dict used for merge bid

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1595583920 -19800
#      Fri Jul 24 15:15:20 2020 +0530
# Node ID fd4d429e5030115e63be709471e2ffe6b04a0919
# Parent  90aa9c3e8a0ee8b4ad7e807922f6d6a7d132328b
# EXP-Topic merge-refactor
merge: improve documentation of fbid dict used for merge bid

I improved the comments explaning what the dict contains meanwhile organizing
the comment structure which prevents some confusion.

Due to formatting issues, the empty dict was wrapped in `()` which might decieve
in thinking that it's a tuple of dict until you decide to find a comma.

Differential Revision: https://phab.mercurial-scm.org/D8818

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -989,10 +989,12 @@ def calculateupdates(
             )
         )
 
-        # Call for bids
-        fbids = (
-            {}
-        )  # mapping filename to bids (action method to list af actions)
+        # mapping filename to bids (action method to list af actions)
+        # {FILENAME1 : BID1, FILENAME2 : BID2}
+        # BID is another dictionary which contains
+        # mapping of following form:
+        # {ACTION_X : [info, ..], ACTION_Y : [info, ..]}
+        fbids = {}
         diverge, renamedelete = None, None
         for ancestor in ancestors:
             repo.ui.note(_(b'\ncalculating bids for ancestor %s\n') % ancestor)
@@ -1033,6 +1035,7 @@ def calculateupdates(
                 else:
                     fbids[f] = {m: [a]}
 
+        # Call for bids
         # Pick the best bid for each file
         repo.ui.note(_(b'\nauction for merging merge bids\n'))
         actions = {}

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 8 of 9] merge: make mergeresult constructor initialize empty object

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1595586371 -19800
#      Fri Jul 24 15:56:11 2020 +0530
# Node ID 3fbc59f2adf7af284211f8bc41ce957a8d6da24a
# Parent  fd4d429e5030115e63be709471e2ffe6b04a0919
# EXP-Topic merge-refactor
merge: make mergeresult constructor initialize empty object

In future patches, we will be going to update mergeresult object
instead of building an actions dict and then setting it in the object.

Differential Revision: https://phab.mercurial-scm.org/D8819

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -546,7 +546,7 @@ class mergeresult(object):
     It has information about what actions need to be performed on dirstate
     mapping of divergent renames and other such cases. '''
 
-    def __init__(self, actions, diverge, renamedelete, commitinfo):
+    def __init__(self):
         """
         actions: dict of filename as keys and action related info as values
         diverge: mapping of source name -> list of dest name for
@@ -556,7 +556,12 @@ class mergeresult(object):
         commitinfo: dict containing data which should be used on commit
                     contains a filename -> info mapping
         """
+        self._actions = {}
+        self._diverge = {}
+        self._renamedelete = {}
+        self._commitinfo = {}
 
+    def updatevalues(self, actions, diverge, renamedelete, commitinfo):
         self._actions = actions
         self._diverge = diverge
         self._renamedelete = renamedelete
@@ -914,7 +919,9 @@ def manifestmerge(
     renamedelete = branch_copies1.renamedelete
     renamedelete.update(branch_copies2.renamedelete)
 
-    return mergeresult(actions, diverge, renamedelete, commitinfo)
+    mresult = mergeresult()
+    mresult.updatevalues(actions, diverge, renamedelete, commitinfo)
+    return mresult
 
 
 def _resolvetrivial(repo, wctx, mctx, ancestor, actions):
@@ -965,6 +972,7 @@ def calculateupdates(
     # Avoid cycle.
     from . import sparse
 
+    mresult = None
     if len(ancestors) == 1:  # default
         mresult = manifestmerge(
             repo,
@@ -1075,7 +1083,8 @@ def calculateupdates(
             continue
         repo.ui.note(_(b'end of auction\n\n'))
         # TODO: think about commitinfo when bid merge is used
-        mresult = mergeresult(actions, diverge, renamedelete, {})
+        mresult = mergeresult()
+        mresult.updatevalues(actions, diverge, renamedelete, {})
 
     if wctx.rev() is None:
         fractions = _forgetremoved(wctx, mctx, branchmerge)

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 9 of 9] merge: introduce mergeresult.addfile() and use it

Pulkit Goyal
In reply to this post by Pulkit Goyal
# HG changeset patch
# User Pulkit Goyal <[hidden email]>
# Date 1595587719 -19800
#      Fri Jul 24 16:18:39 2020 +0530
# Node ID 9b0f612c41a6f62ec4923c8e2d5d84873556d610
# Parent  3fbc59f2adf7af284211f8bc41ce957a8d6da24a
# EXP-Topic merge-refactor
merge: introduce mergeresult.addfile() and use it

We want to use mergeresult object at more and more places instead of this
actions dict to simplify code and further add new APIs to mergeresult object.

This patch introduces `addfile()` which adds a new file to the internal actions
dict for now.

Differential Revision: https://phab.mercurial-scm.org/D8820

diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -578,21 +578,17 @@ def overridecalculateupdates(
                 % lfile
             )
             if repo.ui.promptchoice(usermsg, 0) == 0:  # pick remote largefile
-                mresult.actions[lfile] = (b'r', None, b'replaced by standin')
-                mresult.actions[standin] = (b'g', sargs, b'replaces standin')
+                mresult.addfile(lfile, b'r', None, b'replaced by standin')
+                mresult.addfile(standin, b'g', sargs, b'replaces standin')
             else:  # keep local normal file
-                mresult.actions[lfile] = (b'k', None, b'replaces standin')
+                mresult.addfile(lfile, b'k', None, b'replaces standin')
                 if branchmerge:
-                    mresult.actions[standin] = (
-                        b'k',
-                        None,
-                        b'replaced by non-standin',
+                    mresult.addfile(
+                        standin, b'k', None, b'replaced by non-standin',
                     )
                 else:
-                    mresult.actions[standin] = (
-                        b'r',
-                        None,
-                        b'replaced by non-standin',
+                    mresult.addfile(
+                        standin, b'r', None, b'replaced by non-standin',
                     )
         elif lm in (b'g', b'dc') and sm != b'r':
             if lm == b'dc':
@@ -611,29 +607,23 @@ def overridecalculateupdates(
             if repo.ui.promptchoice(usermsg, 0) == 0:  # keep local largefile
                 if branchmerge:
                     # largefile can be restored from standin safely
-                    mresult.actions[lfile] = (
-                        b'k',
-                        None,
-                        b'replaced by standin',
+                    mresult.addfile(
+                        lfile, b'k', None, b'replaced by standin',
                     )
-                    mresult.actions[standin] = (b'k', None, b'replaces standin')
+                    mresult.addfile(standin, b'k', None, b'replaces standin')
                 else:
                     # "lfile" should be marked as "removed" without
                     # removal of itself
-                    mresult.actions[lfile] = (
-                        b'lfmr',
-                        None,
-                        b'forget non-standin largefile',
+                    mresult.addfile(
+                        lfile, b'lfmr', None, b'forget non-standin largefile',
                     )
 
                     # linear-merge should treat this largefile as 're-added'
-                    mresult.actions[standin] = (b'a', None, b'keep standin')
+                    mresult.addfile(standin, b'a', None, b'keep standin')
             else:  # pick remote normal file
-                mresult.actions[lfile] = (b'g', largs, b'replaces standin')
-                mresult.actions[standin] = (
-                    b'r',
-                    None,
-                    b'replaced by non-standin',
+                mresult.addfile(lfile, b'g', largs, b'replaces standin')
+                mresult.addfile(
+                    standin, b'r', None, b'replaced by non-standin',
                 )
 
     return mresult
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -561,12 +561,21 @@ class mergeresult(object):
         self._renamedelete = {}
         self._commitinfo = {}
 
-    def updatevalues(self, actions, diverge, renamedelete, commitinfo):
-        self._actions = actions
+    def updatevalues(self, diverge, renamedelete, commitinfo):
         self._diverge = diverge
         self._renamedelete = renamedelete
         self._commitinfo = commitinfo
 
+    def addfile(self, filename, action, data, message):
+        """ adds a new file to the mergeresult object
+
+        filename: file which we are adding
+        action: one of mergestatemod.ACTION_*
+        data: a tuple of information like fctx and ctx related to this merge
+        message: a message about the merge
+        """
+        self._actions[filename] = (action, data, message)
+
     @property
     def actions(self):
         return self._actions
@@ -636,6 +645,7 @@ def manifestmerge(
 
     Returns an object of mergeresult class
     """
+    mresult = mergeresult()
     if matcher is not None and matcher.always():
         matcher = None
 
@@ -700,7 +710,6 @@ def manifestmerge(
 
     diff = m1.diff(m2, match=matcher)
 
-    actions = {}
     for f, ((n1, fl1), (n2, fl2)) in pycompat.iteritems(diff):
         if n1 and n2:  # file exists on both local and remote side
             if f not in ma:
@@ -709,13 +718,15 @@ def manifestmerge(
                     f, None
                 ) or branch_copies2.copy.get(f, None)
                 if fa is not None:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_MERGE,
                         (f, f, fa, False, pa.node()),
                         b'both renamed from %s' % fa,
                     )
                 else:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_MERGE,
                         (f, f, None, False, pa.node()),
                         b'both created',
@@ -725,20 +736,20 @@ def manifestmerge(
                 fla = ma.flags(f)
                 nol = b'l' not in fl1 + fl2 + fla
                 if n2 == a and fl2 == fla:
-                    actions[f] = (
-                        mergestatemod.ACTION_KEEP,
-                        (),
-                        b'remote unchanged',
+                    mresult.addfile(
+                        f, mergestatemod.ACTION_KEEP, (), b'remote unchanged',
                     )
                 elif n1 == a and fl1 == fla:  # local unchanged - use remote
                     if n1 == n2:  # optimization: keep local content
-                        actions[f] = (
+                        mresult.addfile(
+                            f,
                             mergestatemod.ACTION_EXEC,
                             (fl2,),
                             b'update permissions',
                         )
                     else:
-                        actions[f] = (
+                        mresult.addfile(
+                            f,
                             mergestatemod.ACTION_GET,
                             (fl2, False),
                             b'remote is newer',
@@ -746,13 +757,15 @@ def manifestmerge(
                         if branchmerge:
                             commitinfo[f] = b'other'
                 elif nol and n2 == a:  # remote only changed 'x'
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_EXEC,
                         (fl2,),
                         b'update permissions',
                     )
                 elif nol and n1 == a:  # local only changed 'x'
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_GET,
                         (fl1, False),
                         b'remote is newer',
@@ -760,7 +773,8 @@ def manifestmerge(
                     if branchmerge:
                         commitinfo[f] = b'other'
                 else:  # both changed something
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_MERGE,
                         (f, f, f, False, pa.node()),
                         b'versions differ',
@@ -773,20 +787,23 @@ def manifestmerge(
             ):  # directory rename, move local
                 f2 = branch_copies1.movewithdir[f]
                 if f2 in m2:
-                    actions[f2] = (
+                    mresult.addfile(
+                        f2,
                         mergestatemod.ACTION_MERGE,
                         (f, f2, None, True, pa.node()),
                         b'remote directory rename, both created',
                     )
                 else:
-                    actions[f2] = (
+                    mresult.addfile(
+                        f2,
                         mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
                         (f, fl1),
                         b'remote directory rename - move from %s' % f,
                     )
             elif f in branch_copies1.copy:
                 f2 = branch_copies1.copy[f]
-                actions[f] = (
+                mresult.addfile(
+                    f,
                     mergestatemod.ACTION_MERGE,
                     (f, f2, f2, False, pa.node()),
                     b'local copied/moved from %s' % f2,
@@ -794,13 +811,15 @@ def manifestmerge(
             elif f in ma:  # clean, a different, no remote
                 if n1 != ma[f]:
                     if acceptremote:
-                        actions[f] = (
+                        mresult.addfile(
+                            f,
                             mergestatemod.ACTION_REMOVE,
                             None,
                             b'remote delete',
                         )
                     else:
-                        actions[f] = (
+                        mresult.addfile(
+                            f,
                             mergestatemod.ACTION_CHANGED_DELETED,
                             (f, None, f, False, pa.node()),
                             b'prompt changed/deleted',
@@ -808,16 +827,12 @@ def manifestmerge(
                 elif n1 == addednodeid:
                     # This file was locally added. We should forget it instead of
                     # deleting it.
-                    actions[f] = (
-                        mergestatemod.ACTION_FORGET,
-                        None,
-                        b'remote deleted',
+                    mresult.addfile(
+                        f, mergestatemod.ACTION_FORGET, None, b'remote deleted',
                     )
                 else:
-                    actions[f] = (
-                        mergestatemod.ACTION_REMOVE,
-                        None,
-                        b'other deleted',
+                    mresult.addfile(
+                        f, mergestatemod.ACTION_REMOVE, None, b'other deleted',
                     )
         elif n2:  # file exists only on remote side
             if f in copied1:
@@ -825,13 +840,15 @@ def manifestmerge(
             elif f in branch_copies2.movewithdir:
                 f2 = branch_copies2.movewithdir[f]
                 if f2 in m1:
-                    actions[f2] = (
+                    mresult.addfile(
+                        f2,
                         mergestatemod.ACTION_MERGE,
                         (f2, f, None, False, pa.node()),
                         b'local directory rename, both created',
                     )
                 else:
-                    actions[f2] = (
+                    mresult.addfile(
+                        f2,
                         mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
                         (f, fl2),
                         b'local directory rename - get from %s' % f,
@@ -839,13 +856,15 @@ def manifestmerge(
             elif f in branch_copies2.copy:
                 f2 = branch_copies2.copy[f]
                 if f2 in m2:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_MERGE,
                         (f2, f, f2, False, pa.node()),
                         b'remote copied from %s' % f2,
                     )
                 else:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_MERGE,
                         (f2, f, f2, True, pa.node()),
                         b'remote moved from %s' % f2,
@@ -863,19 +882,22 @@ def manifestmerge(
                 # Checking whether the files are different is expensive, so we
                 # don't do that when we can avoid it.
                 if not force:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_CREATED,
                         (fl2,),
                         b'remote created',
                     )
                 elif not branchmerge:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_CREATED,
                         (fl2,),
                         b'remote created',
                     )
                 else:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_CREATED_MERGE,
                         (fl2, pa.node()),
                         b'remote created, get or merge',
@@ -888,20 +910,23 @@ def manifestmerge(
                         df = branch_copies1.dirmove[d] + f[len(d) :]
                         break
                 if df is not None and df in m1:
-                    actions[df] = (
+                    mresult.addfile(
+                        df,
                         mergestatemod.ACTION_MERGE,
                         (df, f, f, False, pa.node()),
                         b'local directory rename - respect move '
                         b'from %s' % f,
                     )
                 elif acceptremote:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_CREATED,
                         (fl2,),
                         b'remote recreating',
                     )
                 else:
-                    actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_DELETED_CHANGED,
                         (None, f, f, False, pa.node()),
                         b'prompt deleted/changed',
@@ -909,18 +934,17 @@ def manifestmerge(
 
     if repo.ui.configbool(b'experimental', b'merge.checkpathconflicts'):
         # If we are merging, look for path conflicts.
-        checkpathconflicts(repo, wctx, p2, actions)
+        checkpathconflicts(repo, wctx, p2, mresult.actions)
 
     narrowmatch = repo.narrowmatch()
     if not narrowmatch.always():
         # Updates "actions" in place
-        _filternarrowactions(narrowmatch, branchmerge, actions)
+        _filternarrowactions(narrowmatch, branchmerge, mresult.actions)
 
     renamedelete = branch_copies1.renamedelete
     renamedelete.update(branch_copies2.renamedelete)
 
-    mresult = mergeresult()
-    mresult.updatevalues(actions, diverge, renamedelete, commitinfo)
+    mresult.updatevalues(diverge, renamedelete, commitinfo)
     return mresult
 
 
@@ -1046,7 +1070,7 @@ def calculateupdates(
         # Call for bids
         # Pick the best bid for each file
         repo.ui.note(_(b'\nauction for merging merge bids\n'))
-        actions = {}
+        mresult = mergeresult()
         for f, bids in sorted(fbids.items()):
             # bids is a mapping from action method to list af actions
             # Consensus?
@@ -1054,19 +1078,19 @@ def calculateupdates(
                 m, l = list(bids.items())[0]
                 if all(a == l[0] for a in l[1:]):  # len(bids) is > 1
                     repo.ui.note(_(b" %s: consensus for %s\n") % (f, m))
-                    actions[f] = l[0]
+                    mresult.addfile(f, *l[0])
                     continue
             # If keep is an option, just do it.
             if mergestatemod.ACTION_KEEP in bids:
                 repo.ui.note(_(b" %s: picking 'keep' action\n") % f)
-                actions[f] = bids[mergestatemod.ACTION_KEEP][0]
+                mresult.addfile(f, *bids[mergestatemod.ACTION_KEEP][0])
                 continue
             # If there are gets and they all agree [how could they not?], do it.
             if mergestatemod.ACTION_GET in bids:
                 ga0 = bids[mergestatemod.ACTION_GET][0]
                 if all(a == ga0 for a in bids[mergestatemod.ACTION_GET][1:]):
                     repo.ui.note(_(b" %s: picking 'get' action\n") % f)
-                    actions[f] = ga0
+                    mresult.addfile(f, *ga0)
                     continue
             # TODO: Consider other simple actions such as mode changes
             # Handle inefficient democrazy.
@@ -1079,12 +1103,11 @@ def calculateupdates(
             repo.ui.warn(
                 _(b' %s: ambiguous merge - picked %s action\n') % (f, m)
             )
-            actions[f] = l[0]
+            mresult.addfile(f, *l[0])
             continue
         repo.ui.note(_(b'end of auction\n\n'))
         # TODO: think about commitinfo when bid merge is used
-        mresult = mergeresult()
-        mresult.updatevalues(actions, diverge, renamedelete, {})
+        mresult.updatevalues(diverge, renamedelete, {})
 
     if wctx.rev() is None:
         fractions = _forgetremoved(wctx, mctx, branchmerge)
@@ -1870,22 +1893,19 @@ def update(
                     % prompts,
                     0,
                 ):
-                    mresult.actions[f] = (
-                        mergestatemod.ACTION_REMOVE,
-                        None,
-                        b'prompt delete',
+                    mresult.addfile(
+                        f, mergestatemod.ACTION_REMOVE, None, b'prompt delete',
                     )
                 elif f in p1:
-                    mresult.actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_ADD_MODIFIED,
                         None,
                         b'prompt keep',
                     )
                 else:
-                    mresult.actions[f] = (
-                        mergestatemod.ACTION_ADD,
-                        None,
-                        b'prompt keep',
+                    mresult.addfile(
+                        f, mergestatemod.ACTION_ADD, None, b'prompt keep',
                     )
             elif m == mergestatemod.ACTION_DELETED_CHANGED:
                 f1, f2, fa, move, anc = args
@@ -1902,7 +1922,8 @@ def update(
                     )
                     == 0
                 ):
-                    mresult.actions[f] = (
+                    mresult.addfile(
+                        f,
                         mergestatemod.ACTION_GET,
                         (flags, False),
                         b'prompt recreating',

_______________________________________________
Mercurial-devel mailing list
[hidden email]
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel