changeset 34846:f05a6e015ecc

copies: add a config to limit the number of candidates to check in heuristics The heuristics algorithm find possible candidates for move/copy and then check whether they are actually a copy or move. In some cases, there can be lot of candidates possible which can actually slow down the algorithm. This patch introduces a config option `experimental.copytrace.movecandidateslimit` using which one can limit the candidates to check. The limit defaults to 100. Thanks to Yuya for suggesting to skip copytracing for that file with a warning. Differential Revision: https://phab.mercurial-scm.org/D987
author Pulkit Goyal <7895pulkit@gmail.com>
date Tue, 10 Oct 2017 02:25:03 +0530
parents 78d9a7b7cdb6
children e27f1f04c2cf
files mercurial/configitems.py mercurial/copies.py tests/test-copytrace-heuristics.t
diffstat 3 files changed, 80 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/configitems.py	Tue Oct 17 10:31:44 2017 -0700
+++ b/mercurial/configitems.py	Tue Oct 10 02:25:03 2017 +0530
@@ -330,6 +330,9 @@
 coreconfigitem('experimental', 'copytrace',
     default='on',
 )
+coreconfigitem('experimental', 'copytrace.movecandidateslimit',
+    default=100,
+)
 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
     default=100,
 )
--- a/mercurial/copies.py	Tue Oct 17 10:31:44 2017 -0700
+++ b/mercurial/copies.py	Tue Oct 10 02:25:03 2017 +0530
@@ -11,6 +11,8 @@
 import heapq
 import os
 
+from .i18n import _
+
 from . import (
     match as matchmod,
     node,
@@ -644,6 +646,11 @@
 
         [experimental]
         copytrace = heuristics
+
+    In some cases the copy/move candidates found by heuristics can be very large
+    in number and that will make the algorithm slow. The number of possible
+    candidates to check can be limited by using the config
+    `experimental.copytrace.movecandidateslimit` which defaults to 100.
     """
 
     if c1.rev() is None:
@@ -704,6 +711,17 @@
             # f is guaranteed to be present in c2, that's why
             # c2.filectx(f) won't fail
             f2 = c2.filectx(f)
+            # we can have a lot of candidates which can slow down the heuristics
+            # config value to limit the number of candidates moves to check
+            maxcandidates = repo.ui.configint('experimental',
+                                              'copytrace.movecandidateslimit')
+
+            if len(movecandidates) > maxcandidates:
+                repo.ui.status(_("skipping copytracing for '%s', more "
+                                 "candidates than the limit: %d\n")
+                               % (f, len(movecandidates)))
+                continue
+
             for candidate in movecandidates:
                 f1 = c1.filectx(candidate)
                 if _related(f1, f2, anc.rev()):
--- a/tests/test-copytrace-heuristics.t	Tue Oct 17 10:31:44 2017 -0700
+++ b/tests/test-copytrace-heuristics.t	Tue Oct 10 02:25:03 2017 +0530
@@ -201,6 +201,65 @@
   $ cd ..
   $ rm -rf repo
 
+Test the copytrace.movecandidateslimit with many move candidates
+----------------------------------------------------------------
+
+  $ hg init repo
+  $ initclient repo
+  $ cd repo
+  $ echo a > a
+  $ hg add a
+  $ hg ci -m initial
+  $ hg mv a foo
+  $ echo a > b
+  $ echo a > c
+  $ echo a > d
+  $ echo a > e
+  $ echo a > f
+  $ echo a > g
+  $ hg add b
+  $ hg add c
+  $ hg add d
+  $ hg add e
+  $ hg add f
+  $ hg add g
+  $ hg ci -m 'mv a foo, add many files'
+  $ hg up -q ".^"
+  $ echo b > a
+  $ hg ci -m 'mod a'
+  created new head
+
+  $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
+  @  changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
+  |   desc: mod a
+  | o  changeset: 8329d5c6bf479ec5ca59b9864f3f45d07213f5a4
+  |/    desc: mv a foo, add many files
+  o  changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
+      desc: initial
+
+With small limit
+
+  $ hg rebase -s 2 -d 1 --config experimental.copytrace.movecandidateslimit=0
+  rebasing 2:ef716627c70b "mod a" (tip)
+  skipping copytracing for 'a', more candidates than the limit: 7
+  other [source] changed a which local [dest] deleted
+  use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
+  unresolved conflicts (see hg resolve, then hg rebase --continue)
+  [1]
+
+  $ hg rebase --abort
+  rebase aborted
+
+With default limit which is 100
+
+  $ hg rebase -s 2 -d 1
+  rebasing 2:ef716627c70b "mod a" (tip)
+  merging foo and a to foo
+  saved backup bundle to $TESTTMP/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
+
+  $ cd ..
+  $ rm -rf repo
+
 Move file in one branch and delete it in another
 -----------------------------------------------