patch: fix copies when patching over uncommitted changed (issue2459) stable
authorPatrick Mezard <pmezard@gmail.com>
Thu, 28 Oct 2010 21:25:53 +0200
branchstable
changeset 12874 bb7bf43b72fb
parent 12873 e1855dee28c1
child 12875 b59b5193d4d0
patch: fix copies when patching over uncommitted changed (issue2459)
mercurial/cmdutil.py
tests/test-git-import.t
--- a/mercurial/cmdutil.py	Wed Oct 27 16:54:46 2010 -0500
+++ b/mercurial/cmdutil.py	Thu Oct 28 21:25:53 2010 +0200
@@ -348,7 +348,7 @@
 
     wctx = repo[None]
     for src, dst in copies:
-        wctx.copy(src, dst)
+        dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd)
     if (not similarity) and removes:
         wctx.remove(sorted(removes), True)
 
@@ -367,6 +367,25 @@
     files.extend([r for r in removes if r not in files])
     return sorted(files)
 
+def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
+    """Update the dirstate to reflect the intent of copying src to dst. For
+    different reasons it might not end with dst being marked as copied from src.
+    """
+    origsrc = repo.dirstate.copied(src) or src
+    if dst == origsrc: # copying back a copy?
+        if repo.dirstate[dst] not in 'mn' and not dryrun:
+            repo.dirstate.normallookup(dst)
+    else:
+        if repo.dirstate[origsrc] == 'a' and origsrc == src:
+            if not ui.quiet:
+                ui.warn(_("%s has not been committed yet, so no copy "
+                          "data will be stored for %s.\n")
+                        % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
+            if repo.dirstate[dst] in '?r' and not dryrun:
+                wctx.add([dst])
+        elif not dryrun:
+            wctx.copy(origsrc, dst)
+
 def copy(ui, repo, pats, opts, rename=False):
     # called with the repo lock held
     #
@@ -458,21 +477,7 @@
         targets[abstarget] = abssrc
 
         # fix up dirstate
-        origsrc = repo.dirstate.copied(abssrc) or abssrc
-        if abstarget == origsrc: # copying back a copy?
-            if state not in 'mn' and not dryrun:
-                repo.dirstate.normallookup(abstarget)
-        else:
-            if repo.dirstate[origsrc] == 'a' and origsrc == abssrc:
-                if not ui.quiet:
-                    ui.warn(_("%s has not been committed yet, so no copy "
-                              "data will be stored for %s.\n")
-                            % (repo.pathto(origsrc, cwd), reltarget))
-                if repo.dirstate[abstarget] in '?r' and not dryrun:
-                    wctx.add([abstarget])
-            elif not dryrun:
-                wctx.copy(origsrc, abstarget)
-
+        dirstatecopy(ui, repo, wctx, abssrc, abstarget, dryrun=dryrun, cwd=cwd)
         if rename and not dryrun:
             wctx.remove([abssrc], not after)
 
--- a/tests/test-git-import.t	Wed Oct 27 16:54:46 2010 -0500
+++ b/tests/test-git-import.t	Thu Oct 28 21:25:53 2010 +0200
@@ -361,4 +361,25 @@
   A binary2
     text2
   R text2
+  $ cd ..
 
+Consecutive import with renames (issue2459)
+
+  $ hg init issue2459
+  $ cd issue2459
+  $ hg import --no-commit --force - <<EOF
+  > diff --git a/a b/a
+  > new file mode 100644
+  > EOF
+  applying patch from stdin
+  $ hg import --no-commit --force - <<EOF
+  > diff --git a/a b/b
+  > rename from a
+  > rename to b
+  > EOF
+  applying patch from stdin
+  a has not been committed yet, so no copy data will be stored for b.
+  $ hg debugstate
+  a   0         -1 unset               b
+  $ hg ci -m done
+  $ cd ..