Patchwork [2,of,2] duplicatecopies: do not mark items not in the dirstate as copies

login
register
mail settings
Submitter Siddharth Agarwal
Date March 29, 2013, 1:30 a.m.
Message ID <c6c13f87ea45d01e65bb.1364520602@sid0x220>
Download mbox | patch
Permalink /patch/1215/
State Accepted
Commit 78d760aa3607f13c8d24b9a6807aa998c4d61f0a
Headers show

Comments

Siddharth Agarwal - March 29, 2013, 1:30 a.m.
# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1364520439 25200
#      Thu Mar 28 18:27:19 2013 -0700
# Node ID c6c13f87ea45d01e65bb946b5f1d94d281bdaf84
# Parent  04f784d278a2b4ae3f42bb50c512e081a100246e
duplicatecopies: do not mark items not in the dirstate as copies

Consider the following repo:

  0 -- 1 (renames a to b)
    \
     - 2

If we're rebasing 2 onto 1, then duplicatecopies is called with arguments (2,
1). copies.pathcopies goes backwards from 1 to 0 and returns the pair dst = a,
src = b. Of course, since we're working on top of 2, at this point a doesn't
exist in the dirstate.

Extra entries in the copymap are currently harmless because the copymap is
only queried for items in the dirstate map. However, if the dirstate.copy
method becomes one of the sources used to determine which files have changed,
this will prove problematic.

Note that we can't avoid going backwards in general -- consider this repo:

  0 -- 1 (renames a to b)
    \
     - 2 (renames a to c)

Rebasing 2 onto 1 should produce a rename from b to c.

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -1593,7 +1593,10 @@  def forget(ui, repo, match, prefix, expl
 def duplicatecopies(repo, rev, fromrev):
     '''reproduce copies from fromrev to rev in the dirstate'''
     for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
-        repo.dirstate.copy(src, dst)
+        # copies.pathcopies returns backward renames, so dst might not
+        # actually be in the dirstate
+        if repo.dirstate[dst] in "nma":
+            repo.dirstate.copy(src, dst)
 
 def commit(ui, repo, commitfunc, pats, opts):
     '''commit the specified files or all outstanding changes'''