Mercurial > public > mercurial-scm > hg
diff mercurial/cmdutil.py @ 2958:ff3ea21a981a
addremove: add -s/--similarity option
progress on issue 295.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Fri, 18 Aug 2006 22:13:58 -0700 |
parents | 6e062d9b188f |
children | bc3fe3b5b785 |
line wrap: on
line diff
--- a/mercurial/cmdutil.py Fri Aug 18 21:18:01 2006 -0700 +++ b/mercurial/cmdutil.py Fri Aug 18 22:13:58 2006 -0700 @@ -8,7 +8,7 @@ from demandload import demandload from node import * from i18n import gettext as _ -demandload(globals(), 'util') +demandload(globals(), 'mdiff util') demandload(globals(), 'os sys') def make_filename(repo, pat, node, @@ -93,19 +93,53 @@ for r in results: yield r -def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None): +def findrenames(repo, added=None, removed=None, threshold=0.5): + if added is None or removed is None: + added, removed = repo.status()[1:3] + changes = repo.changelog.read(repo.dirstate.parents()[0]) + mf = repo.manifest.read(changes[0]) + for a in added: + aa = repo.wread(a) + bestscore, bestname = None, None + for r in removed: + rr = repo.file(r).read(mf[r]) + delta = mdiff.textdiff(aa, rr) + if len(delta) < len(aa): + myscore = 1.0 - (float(len(delta)) / len(aa)) + if bestscore is None or myscore > bestscore: + bestscore, bestname = myscore, r + if bestname and bestscore >= threshold: + yield bestname, a, bestscore + +def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None, + similarity=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 = [], [] + mapping = {} for src, abs, rel, exact in walk(repo, pats, opts): if src == 'f' and repo.dirstate.state(abs) == '?': 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.state(abs) != 'r' and not os.path.exists(rel): 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 not dry_run: repo.add(add, wlock=wlock) repo.remove(remove, wlock=wlock) + if similarity > 0: + for old, new, score in findrenames(repo, add, remove, similarity): + oldrel, oldexact = mapping[old] + newrel, newexact = mapping[new] + if repo.ui.verbose or not oldexact or not newexact: + repo.ui.status(_('recording removal of %s as rename to %s ' + '(%d%% similar)\n') % + (oldrel, newrel, score * 100)) + if not dry_run: + repo.copy(old, new, wlock=wlock)