Patchwork [1,of,4,more-matchers] merge: have merge.update use a matcher instead of partial fn

login
register
mail settings
Submitter Augie Fackler
Date Dec. 15, 2015, 3:17 a.m.
Message ID <3c54f3c2fcbc57639d35.1450149437@imladris.local>
Download mbox | patch
Permalink /patch/12048/
State Accepted
Headers show

Comments

Augie Fackler - Dec. 15, 2015, 3:17 a.m.
# HG changeset patch
# User Augie Fackler <augie@google.com>
# Date 1450137243 18000
#      Mon Dec 14 18:54:03 2015 -0500
# Node ID 3c54f3c2fcbc57639d3501f4e592045d1b702cf6
# Parent  fe3c688faaf4745182ba8fbe5f04c5702f05babe
merge: have merge.update use a matcher instead of partial fn

This is relatively rarely used functionality, but migrating this to a
matcher will make future work on narrow clones more feasible.
Martin von Zweigbergk - Dec. 15, 2015, 5:01 a.m.
On Mon, Dec 14, 2015 at 7:18 PM Augie Fackler <raf@durin42.com> wrote:

> # HG changeset patch
> # User Augie Fackler <augie@google.com>
> # Date 1450137243 18000
> #      Mon Dec 14 18:54:03 2015 -0500
> # Node ID 3c54f3c2fcbc57639d3501f4e592045d1b702cf6
> # Parent  fe3c688faaf4745182ba8fbe5f04c5702f05babe
> merge: have merge.update use a matcher instead of partial fn
>
> This is relatively rarely used functionality, but migrating this to a
> matcher will make future work on narrow clones more feasible.
>

Regardless of that, I find this much easier to read. Thanks.


>
> diff --git a/hgext/histedit.py b/hgext/histedit.py
> --- a/hgext/histedit.py
> +++ b/hgext/histedit.py
> @@ -712,8 +712,8 @@ class base(histeditaction):
>
>      def run(self):
>          if self.repo['.'].node() != self.node:
> -            mergemod.update(self.repo, self.node, False, True, False)
> -            #                                     branchmerge, force,
> partial)
> +            mergemod.update(self.repo, self.node, False, True)
> +            #                                     branchmerge, force)
>          return self.continueclean()
>
>      def continuedirty(self):
> diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
> --- a/hgext/largefiles/overrides.py
> +++ b/hgext/largefiles/overrides.py
> @@ -1364,8 +1364,11 @@ def overridecat(orig, ui, repo, file1, *
>          err = 0
>      return err
>
> -def mergeupdate(orig, repo, node, branchmerge, force, partial,
> +def mergeupdate(orig, repo, node, branchmerge, force,
>                  *args, **kwargs):
> +    matcher = kwargs.get('matcher', None)
> +    # note if this is a partial update
> +    partial = matcher and not matcher.always()
>      wlock = repo.wlock()
>      try:
>          # branch |       |         |
> @@ -1405,7 +1408,7 @@ def mergeupdate(orig, repo, node, branch
>
>          oldstandins = lfutil.getstandinsstate(repo)
>
> -        result = orig(repo, node, branchmerge, force, partial, *args,
> **kwargs)
> +        result = orig(repo, node, branchmerge, force, *args, **kwargs)
>
>          newstandins = lfutil.getstandinsstate(repo)
>          filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
> diff --git a/hgext/rebase.py b/hgext/rebase.py
> --- a/hgext/rebase.py
> +++ b/hgext/rebase.py
> @@ -632,7 +632,7 @@ def rebasenode(repo, rev, p1, base, stat
>      # Update to target and merge it with local
>      if repo['.'].rev() != p1:
>          repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
> -        merge.update(repo, p1, False, True, False)
> +        merge.update(repo, p1, False, True)
>      else:
>          repo.ui.debug(" already in target\n")
>      repo.dirstate.write(repo.currenttransaction())
> @@ -641,7 +641,7 @@ def rebasenode(repo, rev, p1, base, stat
>          repo.ui.debug("   detach base %d:%s\n" % (base, repo[base]))
>      # When collapsing in-place, the parent is the common ancestor, we
>      # have to allow merging with it.
> -    stats = merge.update(repo, rev, True, True, False, base, collapse,
> +    stats = merge.update(repo, rev, True, True, base, collapse,
>                          labels=['dest', 'source'])
>      if collapse:
>          copies.duplicatecopies(repo, rev, target)
> @@ -958,7 +958,7 @@ def abort(repo, originalwd, target, stat
>          if cleanup:
>              # Update away from the rebase if necessary
>              if needupdate(repo, state):
> -                merge.update(repo, originalwd, False, True, False)
> +                merge.update(repo, originalwd, False, True)
>
>              # Strip from the first rebased revision
>              rebased = filter(lambda x: x >= 0 and x != target,
> state.values())
> diff --git a/hgext/transplant.py b/hgext/transplant.py
> --- a/hgext/transplant.py
> +++ b/hgext/transplant.py
> @@ -152,7 +152,7 @@ class transplanter(object):
>                      if pulls:
>                          if source != repo:
>                              exchange.pull(repo, source.peer(),
> heads=pulls)
> -                        merge.update(repo, pulls[-1], False, False, None)
> +                        merge.update(repo, pulls[-1], False, False)
>                          p1, p2 = repo.dirstate.parents()
>                          pulls = []
>
> @@ -216,7 +216,7 @@ class transplanter(object):
>              tr.close()
>              if pulls:
>                  exchange.pull(repo, source.peer(), heads=pulls)
> -                merge.update(repo, pulls[-1], False, False, None)
> +                merge.update(repo, pulls[-1], False, False)
>          finally:
>              self.saveseries(revmap, merges)
>              self.transplants.write()
> diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
> --- a/mercurial/cmdutil.py
> +++ b/mercurial/cmdutil.py
> @@ -183,9 +183,9 @@ def dorecord(ui, repo, commitfunc, cmdsu
>              # 3a. apply filtered patch to clean repo  (clean)
>              if backups:
>                  # Equivalent to hg.revert
> -                choices = lambda key: key in backups
> +                m = scmutil.matchfiles(repo, backups.keys())
>                  mergemod.update(repo, repo.dirstate.p1(),
> -                        False, True, choices)
> +                        False, True, matcher=m)
>
>              # 3b. (apply)
>              if dopatch:
> diff --git a/mercurial/commands.py b/mercurial/commands.py
> --- a/mercurial/commands.py
> +++ b/mercurial/commands.py
> @@ -636,8 +636,7 @@ def _dobackout(ui, repo, node=None, rev=
>              try:
>                  ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
>                               'backout')
> -                stats = mergemod.update(repo, parent, True, True, False,
> -                                        node, False)
> +                stats = mergemod.update(repo, parent, True, True, node,
> False)
>                  repo.setparents(op1, op2)
>                  dsguard.close()
>                  hg._showstats(repo, stats)
> diff --git a/mercurial/hg.py b/mercurial/hg.py
> --- a/mercurial/hg.py
> +++ b/mercurial/hg.py
> @@ -637,7 +637,7 @@ def updaterepo(repo, node, overwrite):
>      When overwrite is set, changes are clobbered, merged else
>
>      returns stats (see pydoc mercurial.merge.applyupdates)"""
> -    return mergemod.update(repo, node, False, overwrite, None,
> +    return mergemod.update(repo, node, False, overwrite,
>                             labels=['working copy', 'destination'])
>
>  def update(repo, node):
> @@ -662,7 +662,7 @@ def clean(repo, node, show_stats=True):
>  def merge(repo, node, force=None, remind=True):
>      """Branch merge with node, resolving changes. Return true if any
>      unresolved conflicts."""
> -    stats = mergemod.update(repo, node, True, force, False)
> +    stats = mergemod.update(repo, node, True, force)
>      _showstats(repo, stats)
>      if stats[3]:
>          repo.ui.status(_("use 'hg resolve' to retry unresolved file
> merges "
> diff --git a/mercurial/merge.py b/mercurial/merge.py
> --- a/mercurial/merge.py
> +++ b/mercurial/merge.py
> @@ -1266,15 +1266,15 @@ def recordupdates(repo, actions, branchm
>          else:
>              repo.dirstate.normal(f)
>
> -def update(repo, node, branchmerge, force, partial, ancestor=None,
> -           mergeancestor=False, labels=None):
> +def update(repo, node, branchmerge, force, ancestor=None,
> +           mergeancestor=False, labels=None, matcher=None):
>      """
>      Perform a merge between the working directory and the given node
>
>      node = the node to update to, or None if unspecified
>      branchmerge = whether to merge between branches
>      force = whether to force branch merging or file overwriting
> -    partial = a function to filter file lists (dirstate not updated)
> +    matcher = a matcher to filter file lists (dirstate not updated)
>      mergeancestor = whether it is merging with an ancestor. If true,
>        we should accept the incoming changes for any prompts that occur.
>        If false, merging with an ancestor (fast-forward) is only allowed
> @@ -1313,6 +1313,13 @@ def update(repo, node, branchmerge, forc
>
>      onode = node
>      wlock = repo.wlock()
> +    # If we're doing a partial update, we need to skip updating
> +    # the dirstate, so make a note of any partial-ness to the
> +    # update here.
> +    if matcher is None or matcher.always():
> +        partial = False
> +    else:
> +        partial = True
>

Would "partial = matcher is not None and not matcher.always()" work?


>      try:
>          wc = repo[None]
>          pl = wc.parents()
> @@ -1407,6 +1414,10 @@ def update(repo, node, branchmerge, forc
>              followcopies = True
>
>          ### calculate phase
> +        if matcher is None or matcher.always():
> +            partial = False
> +        else:
> +            partial = matcher.matchfn
>

Could we rename this use of "partial" to e.g. "partialfn" so we don't reuse
the same variable for a slightly different purpose?


>          actionbyfile, diverge, renamedelete = calculateupdates(
>              repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
>              followcopies)
> @@ -1516,7 +1527,7 @@ def graft(repo, ctx, pctx, labels, keepp
>      # which local deleted".
>      mergeancestor = repo.changelog.isancestor(repo['.'].node(),
> ctx.node())
>
> -    stats = update(repo, ctx.node(), True, True, False, pctx.node(),
> +    stats = update(repo, ctx.node(), True, True, pctx.node(),
>                     mergeancestor=mergeancestor, labels=labels)
>
>      pother = nullid
> diff --git a/tests/test-revlog-ancestry.py b/tests/test-revlog-ancestry.py
> --- a/tests/test-revlog-ancestry.py
> +++ b/tests/test-revlog-ancestry.py
> @@ -17,10 +17,10 @@ def addcommit(name, time):
>      commit(name, time)
>
>  def update(rev):
> -    merge.update(repo, rev, False, True, False)
> +    merge.update(repo, rev, False, True)
>
>  def merge_(rev):
> -    merge.update(repo, rev, True, False, False)
> +    merge.update(repo, rev, True, False)
>
>  if __name__ == '__main__':
>      addcommit("A", 0)
> @@ -82,4 +82,3 @@ if __name__ == '__main__':
>      print '\nDescendants of 5 and 4'
>      for r in repo.changelog.descendants([5, 4]):
>          print r,
> -
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel
>

Patch

diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -712,8 +712,8 @@  class base(histeditaction):
 
     def run(self):
         if self.repo['.'].node() != self.node:
-            mergemod.update(self.repo, self.node, False, True, False)
-            #                                     branchmerge, force, partial)
+            mergemod.update(self.repo, self.node, False, True)
+            #                                     branchmerge, force)
         return self.continueclean()
 
     def continuedirty(self):
diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py
--- a/hgext/largefiles/overrides.py
+++ b/hgext/largefiles/overrides.py
@@ -1364,8 +1364,11 @@  def overridecat(orig, ui, repo, file1, *
         err = 0
     return err
 
-def mergeupdate(orig, repo, node, branchmerge, force, partial,
+def mergeupdate(orig, repo, node, branchmerge, force,
                 *args, **kwargs):
+    matcher = kwargs.get('matcher', None)
+    # note if this is a partial update
+    partial = matcher and not matcher.always()
     wlock = repo.wlock()
     try:
         # branch |       |         |
@@ -1405,7 +1408,7 @@  def mergeupdate(orig, repo, node, branch
 
         oldstandins = lfutil.getstandinsstate(repo)
 
-        result = orig(repo, node, branchmerge, force, partial, *args, **kwargs)
+        result = orig(repo, node, branchmerge, force, *args, **kwargs)
 
         newstandins = lfutil.getstandinsstate(repo)
         filelist = lfutil.getlfilestoupdate(oldstandins, newstandins)
diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -632,7 +632,7 @@  def rebasenode(repo, rev, p1, base, stat
     # Update to target and merge it with local
     if repo['.'].rev() != p1:
         repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
-        merge.update(repo, p1, False, True, False)
+        merge.update(repo, p1, False, True)
     else:
         repo.ui.debug(" already in target\n")
     repo.dirstate.write(repo.currenttransaction())
@@ -641,7 +641,7 @@  def rebasenode(repo, rev, p1, base, stat
         repo.ui.debug("   detach base %d:%s\n" % (base, repo[base]))
     # When collapsing in-place, the parent is the common ancestor, we
     # have to allow merging with it.
-    stats = merge.update(repo, rev, True, True, False, base, collapse,
+    stats = merge.update(repo, rev, True, True, base, collapse,
                         labels=['dest', 'source'])
     if collapse:
         copies.duplicatecopies(repo, rev, target)
@@ -958,7 +958,7 @@  def abort(repo, originalwd, target, stat
         if cleanup:
             # Update away from the rebase if necessary
             if needupdate(repo, state):
-                merge.update(repo, originalwd, False, True, False)
+                merge.update(repo, originalwd, False, True)
 
             # Strip from the first rebased revision
             rebased = filter(lambda x: x >= 0 and x != target, state.values())
diff --git a/hgext/transplant.py b/hgext/transplant.py
--- a/hgext/transplant.py
+++ b/hgext/transplant.py
@@ -152,7 +152,7 @@  class transplanter(object):
                     if pulls:
                         if source != repo:
                             exchange.pull(repo, source.peer(), heads=pulls)
-                        merge.update(repo, pulls[-1], False, False, None)
+                        merge.update(repo, pulls[-1], False, False)
                         p1, p2 = repo.dirstate.parents()
                         pulls = []
 
@@ -216,7 +216,7 @@  class transplanter(object):
             tr.close()
             if pulls:
                 exchange.pull(repo, source.peer(), heads=pulls)
-                merge.update(repo, pulls[-1], False, False, None)
+                merge.update(repo, pulls[-1], False, False)
         finally:
             self.saveseries(revmap, merges)
             self.transplants.write()
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -183,9 +183,9 @@  def dorecord(ui, repo, commitfunc, cmdsu
             # 3a. apply filtered patch to clean repo  (clean)
             if backups:
                 # Equivalent to hg.revert
-                choices = lambda key: key in backups
+                m = scmutil.matchfiles(repo, backups.keys())
                 mergemod.update(repo, repo.dirstate.p1(),
-                        False, True, choices)
+                        False, True, matcher=m)
 
             # 3b. (apply)
             if dopatch:
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -636,8 +636,7 @@  def _dobackout(ui, repo, node=None, rev=
             try:
                 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
                              'backout')
-                stats = mergemod.update(repo, parent, True, True, False,
-                                        node, False)
+                stats = mergemod.update(repo, parent, True, True, node, False)
                 repo.setparents(op1, op2)
                 dsguard.close()
                 hg._showstats(repo, stats)
diff --git a/mercurial/hg.py b/mercurial/hg.py
--- a/mercurial/hg.py
+++ b/mercurial/hg.py
@@ -637,7 +637,7 @@  def updaterepo(repo, node, overwrite):
     When overwrite is set, changes are clobbered, merged else
 
     returns stats (see pydoc mercurial.merge.applyupdates)"""
-    return mergemod.update(repo, node, False, overwrite, None,
+    return mergemod.update(repo, node, False, overwrite,
                            labels=['working copy', 'destination'])
 
 def update(repo, node):
@@ -662,7 +662,7 @@  def clean(repo, node, show_stats=True):
 def merge(repo, node, force=None, remind=True):
     """Branch merge with node, resolving changes. Return true if any
     unresolved conflicts."""
-    stats = mergemod.update(repo, node, True, force, False)
+    stats = mergemod.update(repo, node, True, force)
     _showstats(repo, stats)
     if stats[3]:
         repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
@@ -1266,15 +1266,15 @@  def recordupdates(repo, actions, branchm
         else:
             repo.dirstate.normal(f)
 
-def update(repo, node, branchmerge, force, partial, ancestor=None,
-           mergeancestor=False, labels=None):
+def update(repo, node, branchmerge, force, ancestor=None,
+           mergeancestor=False, labels=None, matcher=None):
     """
     Perform a merge between the working directory and the given node
 
     node = the node to update to, or None if unspecified
     branchmerge = whether to merge between branches
     force = whether to force branch merging or file overwriting
-    partial = a function to filter file lists (dirstate not updated)
+    matcher = a matcher to filter file lists (dirstate not updated)
     mergeancestor = whether it is merging with an ancestor. If true,
       we should accept the incoming changes for any prompts that occur.
       If false, merging with an ancestor (fast-forward) is only allowed
@@ -1313,6 +1313,13 @@  def update(repo, node, branchmerge, forc
 
     onode = node
     wlock = repo.wlock()
+    # If we're doing a partial update, we need to skip updating
+    # the dirstate, so make a note of any partial-ness to the
+    # update here.
+    if matcher is None or matcher.always():
+        partial = False
+    else:
+        partial = True
     try:
         wc = repo[None]
         pl = wc.parents()
@@ -1407,6 +1414,10 @@  def update(repo, node, branchmerge, forc
             followcopies = True
 
         ### calculate phase
+        if matcher is None or matcher.always():
+            partial = False
+        else:
+            partial = matcher.matchfn
         actionbyfile, diverge, renamedelete = calculateupdates(
             repo, wc, p2, pas, branchmerge, force, partial, mergeancestor,
             followcopies)
@@ -1516,7 +1527,7 @@  def graft(repo, ctx, pctx, labels, keepp
     # which local deleted".
     mergeancestor = repo.changelog.isancestor(repo['.'].node(), ctx.node())
 
-    stats = update(repo, ctx.node(), True, True, False, pctx.node(),
+    stats = update(repo, ctx.node(), True, True, pctx.node(),
                    mergeancestor=mergeancestor, labels=labels)
 
     pother = nullid
diff --git a/tests/test-revlog-ancestry.py b/tests/test-revlog-ancestry.py
--- a/tests/test-revlog-ancestry.py
+++ b/tests/test-revlog-ancestry.py
@@ -17,10 +17,10 @@  def addcommit(name, time):
     commit(name, time)
 
 def update(rev):
-    merge.update(repo, rev, False, True, False)
+    merge.update(repo, rev, False, True)
 
 def merge_(rev):
-    merge.update(repo, rev, True, False, False)
+    merge.update(repo, rev, True, False)
 
 if __name__ == '__main__':
     addcommit("A", 0)
@@ -82,4 +82,3 @@  if __name__ == '__main__':
     print '\nDescendants of 5 and 4'
     for r in repo.changelog.descendants([5, 4]):
         print r,
-