copytrace: use the full copytracing method if only drafts are involved
This patch adds the functionality to use the full copytracing even if
`experimental.copytrace = heuristics` in cases when drafts are involved.
This is also a part of copytrace extension in fbext.
This also adds tests which are also taken from fbext.
.. feature::
The `heuristics` option for `experimental.copytrace` performs full
copytracing if both source and destination branches contains non-public
changsets only.
Differential Revision: https://phab.mercurial-scm.org/D625
--- a/mercurial/copies.py Fri Sep 15 10:43:22 2017 -0700
+++ b/mercurial/copies.py Sun Sep 03 20:06:45 2017 +0530
@@ -15,6 +15,7 @@
match as matchmod,
node,
pathutil,
+ phases,
scmutil,
util,
)
@@ -367,10 +368,27 @@
if copytracing == 'off':
return {}, {}, {}, {}, {}
elif copytracing == 'heuristics':
+ # Do full copytracing if only drafts are involved as that will be fast
+ # enough and will also cover the copies which can be missed by
+ # heuristics
+ if _isfullcopytraceable(c1, base):
+ return _fullcopytracing(repo, c1, c2, base)
return _heuristicscopytracing(repo, c1, c2, base)
else:
return _fullcopytracing(repo, c1, c2, base)
+def _isfullcopytraceable(c1, base):
+ """ Checks that if base, source and destination are all draft branches, if
+ yes let's use the full copytrace algorithm for increased capabilities since
+ it will be fast enough.
+ """
+
+ nonpublicphases = set([phases.draft, phases.secret])
+
+ if (c1.phase() in nonpublicphases) and (base.phase() in nonpublicphases):
+ return True
+ return False
+
def _fullcopytracing(repo, c1, c2, base):
""" The full copytracing algorithm which finds all the new files that were
added from merge base up to the top commit and for each file it checks if
--- a/tests/test-copytrace-heuristics.t Fri Sep 15 10:43:22 2017 -0700
+++ b/tests/test-copytrace-heuristics.t Sun Sep 03 20:06:45 2017 +0530
@@ -589,3 +589,79 @@
$ cd ..
$ rm -rf server
$ rm -rf repo
+
+Test full copytrace ability on draft branch
+-------------------------------------------
+
+File directory and base name changed in same move
+ $ hg init repo
+ $ initclient repo
+ $ mkdir repo/dir1
+ $ cd repo/dir1
+ $ echo a > a
+ $ hg add a
+ $ hg ci -qm initial
+ $ cd ..
+ $ hg mv -q dir1 dir2
+ $ hg mv dir2/a dir2/b
+ $ hg ci -qm 'mv a b; mv dir1 dir2'
+ $ hg up -q '.^'
+ $ cd dir1
+ $ echo b >> a
+ $ cd ..
+ $ hg ci -qm 'mod a'
+
+ $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
+ @ changeset 6207d2d318e710b882e3d5ada2a89770efc42c96
+ | desc mod a, phase: draft
+ | o changeset abffdd4e3dfc04bc375034b970299b2a309a1cce
+ |/ desc mv a b; mv dir1 dir2, phase: draft
+ o changeset 81973cd24b58db2fdf18ce3d64fb2cc3284e9ab3
+ desc initial, phase: draft
+
+ $ hg rebase -s . -d 1
+ rebasing 2:6207d2d318e7 "mod a" (tip)
+ merging dir2/b and dir1/a to dir2/b
+ saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/6207d2d318e7-1c9779ad-rebase.hg (glob)
+ $ cat dir2/b
+ a
+ b
+ $ cd ..
+ $ rm -rf server
+ $ rm -rf repo
+
+Move directory in one merge parent, while adding file to original directory
+in other merge parent. File moved on rebase.
+ $ hg init repo
+ $ initclient repo
+ $ mkdir repo/dir1
+ $ cd repo/dir1
+ $ echo dummy > dummy
+ $ hg add dummy
+ $ cd ..
+ $ hg ci -qm initial
+ $ cd dir1
+ $ echo a > a
+ $ hg add a
+ $ cd ..
+ $ hg ci -qm 'hg add dir1/a'
+ $ hg up -q '.^'
+ $ hg mv -q dir1 dir2
+ $ hg ci -qm 'mv dir1 dir2'
+
+ $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
+ @ changeset e8919e7df8d036e07b906045eddcd4a42ff1915f
+ | desc mv dir1 dir2, phase: draft
+ | o changeset 7c7c6f339be00f849c3cb2df738ca91db78b32c8
+ |/ desc hg add dir1/a, phase: draft
+ o changeset a235dcce55dcf42034c4e374cb200662d0bb4a13
+ desc initial, phase: draft
+
+ $ hg rebase -s . -d 1
+ rebasing 2:e8919e7df8d0 "mv dir1 dir2" (tip)
+ saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/e8919e7df8d0-f62fab62-rebase.hg (glob)
+ $ ls dir2
+ a
+ dummy
+ $ rm -rf server
+ $ rm -rf repo