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
--- 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
-----------------------------------------------