[PATCH 2 of 2] addremove: add --full/-f to force rematching of all removed files (status ! or R)
Peter Arrenbrecht
peter.arrenbrecht at gmail.com
Wed Apr 2 19:38:02 UTC 2008
# HG changeset patch
# User Peter Arrenbrecht <peter.arrenbrecht at gmail.com>
# Date 1207165043 -7200
# Node ID b007e781b89191603950acfb228fe0d4de97d382
# Parent e43616661358fa319579c0d9db6d50d6a1d69d18
addremove: add --full/-f to force rematching of all removed files (status ! or R)
With -s the addremove command only checks files with status ! (missing)
against files with status ? (new). Use the -f option with -s to force
(re)checking of all deleted files (status ! or R) against all new files
(status ? or A). This is especially helpful if you forgot -s or set
the similarity too high.
diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -267,31 +267,51 @@
if bestname:
yield bestname, a, bestscore
-def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
+def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None, full=None):
if dry_run is None:
dry_run = opts.get('dry_run')
if similarity is None:
similarity = float(opts.get('similarity') or 0)
- add, remove = [], []
+ if full is None:
+ full = opts.get('full')
+ newfiles, deletedfiles = [], []
+ sources, targets = [], []
mapping = {}
+ detectingrenames = (similarity > 0)
for src, abs, rel, exact in walk(repo, pats, opts):
target = repo.wjoin(abs)
- if src == 'f' and abs not in repo.dirstate:
- add.append(abs)
- mapping[abs] = rel, exact
- if repo.ui.verbose or not exact:
- repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
- if repo.dirstate[abs] != 'r' and (not util.lexists(target)
- or (os.path.isdir(target) and not os.path.islink(target))):
- remove.append(abs)
- mapping[abs] = rel, exact
- if repo.ui.verbose or not exact:
- repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
+ if src == 'f':
+ isrecorded = abs in repo.dirstate
+ issource = False
+ if not isrecorded:
+ newfiles.append(abs)
+ if repo.ui.verbose or not exact:
+ repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
+ issource = detectingrenames
+ elif detectingrenames and full:
+ issource = repo.dirstate[abs] == 'a'
+ if issource:
+ targets.append(abs)
+ mapping[abs] = rel, exact
+ if (not util.lexists(target) or
+ (os.path.isdir(target) and not os.path.islink(target))):
+ isrecorded = repo.dirstate[abs] == 'r'
+ istarget = False
+ if not isrecorded:
+ deletedfiles.append(abs)
+ if repo.ui.verbose or not exact:
+ repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
+ istarget = detectingrenames
+ elif full:
+ istarget = detectingrenames
+ if istarget:
+ sources.append(abs)
+ mapping[abs] = rel, exact
if not dry_run:
- repo.remove(remove)
- repo.add(add)
+ repo.remove(deletedfiles)
+ repo.add(newfiles)
if similarity > 0:
- for old, new, score in findrenames(repo, add, remove, similarity):
+ for old, new, score in findrenames(repo, targets, sources, similarity):
oldrel, oldexact = mapping[old]
newrel, newexact = mapping[new]
if repo.ui.verbose or not oldexact or not newexact:
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -58,6 +58,12 @@
those similar enough as renames. This option takes a percentage
between 0 (disabled) and 100 (files must be identical) as its
parameter. Detecting renamed files this way can be expensive.
+
+ With -s this command normally only checks files with status ! (missing)
+ against files with status ? (new). Use the -f option with -s to force
+ (re)checking of all deleted files (status ! or R) against all new files
+ (status ? or A). This is especially helpful if you forgot -s or set
+ the similarity too high.
"""
try:
sim = float(opts.get('similarity') or 0)
@@ -2892,7 +2898,9 @@
"addremove":
(addremove,
[('s', 'similarity', '',
- _('guess renamed files by similarity (0<=s<=100)')),
+ _('guess renamed files (status !) by similarity (0<=s<=100)')),
+ ('f', 'full', None,
+ _('make -s check all removed files (status R or !)')),
] + walkopts + dryrunopts,
_('hg addremove [OPTION]... [FILE]...')),
"^annotate|blame":
diff --git a/tests/test-addremove-similar b/tests/test-addremove-similar
--- a/tests/test-addremove-similar
+++ b/tests/test-addremove-similar
@@ -50,4 +50,37 @@
hg addremove -s -1
hg addremove -s 1e6
+cd ..
+
+echo % --full option
+
+hg init rep3; cd rep3
+python -c 'for x in range(50): print x' > a
+# make a1 a closer match that won't be considered because it hasn't gone
+cp a a1
+echo "One more" >> a1
+hg add a a1; hg ci -m a
+mv a b
+echo "One more" >> b
+
+# so here we forget -s
+hg stat -C
+hg addrem
+hg stat -C
+
+# and try again with it, but it doesn't capture already recorded removals
+hg addrem -s 90
+hg stat -C
+
+# so we use the --full option
+hg addrem -fs 90
+hg stat -C
+
+# if we place another copy there, it gets recorded as a second target
+python -c 'for x in range(50): print x' > c
+hg addrem -s 90 --full
+hg stat -C
+
+cd ..
+
true
diff --git a/tests/test-addremove-similar.out b/tests/test-addremove-similar.out
--- a/tests/test-addremove-similar.out
+++ b/tests/test-addremove-similar.out
@@ -20,3 +20,24 @@
abort: similarity must be a number
abort: similarity must be between 0 and 100
abort: similarity must be between 0 and 100
+% --full option
+! a
+? b
+adding b
+removing a
+A b
+R a
+A b
+R a
+recording removal of a as rename to b (96% similar)
+A b
+ a
+R a
+adding c
+recording removal of a as rename to b (96% similar)
+recording removal of a as rename to c (100% similar)
+A b
+ a
+A c
+ a
+R a
More information about the Mercurial-devel
mailing list