[PATCH] import: add similarity option (issue295)

Brendan Cully brendan at kublai.com
Sat Nov 22 02:22:48 CST 2008


# HG changeset patch
# User Brendan Cully <brendan at kublai.com>
# Date 1227342117 28800
# Node ID c227bbf29d91a07d2572769747320cd7f7b8d384
# Parent  03b60f2f90bf14594ffd733cace1102c5c10499b
import: add similarity option (issue295)

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -1581,6 +1581,9 @@
     recorded in the patch. This may happen due to character set
     problems or other deficiencies in the text patch format.
 
+    With --similarity, hg will attempt to discover renames and copies
+    in the patch in the same way as 'addremove'.
+
     To read a patch from standard input, use patch name "-".
     See 'hg help dates' for a list of formats valid for -d/--date.
     """
@@ -1590,6 +1593,13 @@
     if date:
         opts['date'] = util.parsedate(date)
 
+    try:
+        sim = float(opts.get('similarity') or 0)
+    except ValueError:
+        raise util.Abort(_('similarity must be a number'))
+    if sim < 0 or sim > 100:
+        raise util.Abort(_('similarity must be between 0 and 100'))
+
     if opts.get('exact') or not opts.get('force'):
         cmdutil.bail_if_changed(repo)
 
@@ -1653,7 +1663,7 @@
                     fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
                                        files=files)
                 finally:
-                    files = patch.updatedir(ui, repo, files)
+                    files = patch.updatedir(ui, repo, files, similarity=sim/100.)
                 if not opts.get('no_commit'):
                     n = repo.commit(files, message, opts.get('user') or user,
                                     opts.get('date') or date)
@@ -3003,13 +3013,15 @@
     ('U', 'unified', '', _('number of lines of context to show'))
 ]
 
+similarityopts = [
+    ('s', 'similarity', '',
+           _('guess renamed files by similarity (0<=s<=100)'))
+]
+
 table = {
     "^add": (add, walkopts + dryrunopts, _('[OPTION]... [FILE]...')),
     "addremove":
-        (addremove,
-         [('s', 'similarity', '',
-           _('guess renamed files by similarity (0<=s<=100)')),
-         ] + walkopts + dryrunopts,
+        (addremove, similarityopts + walkopts + dryrunopts,
          _('[OPTION]... [FILE]...')),
     "^annotate|blame":
         (annotate,
@@ -3192,7 +3204,7 @@
            _('apply patch to the nodes from which it was generated')),
           ('', 'import-branch', None,
            _('Use any branch information in patch (implied by --exact)'))] +
-         commitopts + commitopts2,
+         commitopts + commitopts2 + similarityopts,
          _('[OPTION]... PATCH...')),
     "incoming|in":
         (incoming,
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -1004,7 +1004,7 @@
         ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'),
         context=get('unified', getter=ui.config))
 
-def updatedir(ui, repo, patches):
+def updatedir(ui, repo, patches, similarity=0):
     '''Update dirstate after patch application according to metadata'''
     if not patches:
         return
@@ -1028,7 +1028,7 @@
     for src, dst in copies:
         repo.copy(src, dst)
     removes = removes.keys()
-    if removes:
+    if (not similarity) and removes:
         repo.remove(util.sort(removes), True)
     for f in patches:
         gp = patches[f]
@@ -1041,7 +1041,7 @@
                 repo.wwrite(gp.path, '', flags)
             else:
                 util.set_flags(dst, islink, isexec)
-    cmdutil.addremove(repo, cfiles)
+    cmdutil.addremove(repo, cfiles, similarity=similarity)
     files = patches.keys()
     files.extend([r for r in removes if r not in files])
     return util.sort(files)
diff --git a/tests/test-import b/tests/test-import
--- a/tests/test-import
+++ b/tests/test-import
@@ -285,3 +285,31 @@
 rename to bar
 EOF
 cd ..
+
+echo '% test import with similarity (issue295)'
+hg init sim
+cd sim
+echo 'this is a test' > a
+hg ci -Ama
+cat > ../rename.diff <<EOF
+diff --git a/a b/a
+deleted file mode 100644
+--- a/a
++++ /dev/null
+@@ -1,1 +0,0 @@
+-this is a test
+diff --git a/b b/b
+new file mode 100644
+--- /dev/null
++++ b/b
+@@ -0,0 +1,2 @@
++this is a test
++foo
+EOF
+hg import --no-commit -v -s 1 ../rename.diff
+hg st -C
+hg revert -a
+rm b
+hg import --no-commit -v -s 100 ../rename.diff
+hg st -C
+cd ..
diff --git a/tests/test-import.out b/tests/test-import.out
--- a/tests/test-import.out
+++ b/tests/test-import.out
@@ -273,3 +273,23 @@
 % test paths outside repo root
 applying patch from stdin
 abort: ../outside/foo not under root
+% test import with similarity (issue295)
+adding a
+applying ../rename.diff
+patching file a
+patching file b
+removing a
+adding b
+recording removal of a as rename to b (88% similar)
+A b
+  a
+R a
+undeleting a
+forgetting b
+applying ../rename.diff
+patching file a
+patching file b
+removing a
+adding b
+A b
+R a


More information about the Mercurial-devel mailing list