[PATCH 3 of 3] copies: do not track backward copies, only renames (issue3739)

Siddharth Agarwal sid0 at fb.com
Fri Dec 21 15:08:23 CST 2012


# HG changeset patch
# User Siddharth Agarwal <sid0 at fb.com>
# Date 1356123985 28800
# Node ID af618ad15aa529d53062f7cf73d45f539f72ebfd
# Parent  554d6cba20701d6b44870a79389cc89812173aed
copies: do not track backward copies, only renames (issue3739)

The inverse of a rename is a rename back, but the inverse of a copy is a
remove, not a "copy back". Removes are already tracked separately, which means
that returning inverted copies serves no useful purpose. Indeed, it can and
does cause bugs because other code starts believing the fake inverted copies
are actually real.

The only test whose output changes is test-mv-cp-st-diff.t. When a backwards
status -C command is run where a copy is involved, the inverted version of the
copy is no longer displayed (though the remove remains intact). Inverted
copies don't make sense anyway, so the point is moot.

diff --git a/mercurial/copies.py b/mercurial/copies.py
--- a/mercurial/copies.py
+++ b/mercurial/copies.py
@@ -145,12 +145,16 @@ def _forwardcopies(a, b):
 
     return cm
 
-def _backwardcopies(a, b):
-    # because the forward mapping is 1:n, we can lose renames here
-    # in particular, we find renames better than copies
+def _backwardrenames(a, b):
+    # Even though we're not taking copies into account, 1:n rename situations
+    # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
+    # arbitrarily pick one of the renames.
     f = _forwardcopies(b, a)
     r = {}
     for k, v in f.iteritems():
+        # remove copies
+        if v in a:
+            continue
         r[v] = k
     return r
 
@@ -162,8 +166,8 @@ def pathcopies(x, y):
     if a == x:
         return _forwardcopies(x, y)
     if a == y:
-        return _backwardcopies(x, y)
-    return _chain(x, y, _backwardcopies(x, a), _forwardcopies(a, y))
+        return _backwardrenames(x, y)
+    return _chain(x, y, _backwardrenames(x, a), _forwardcopies(a, y))
 
 def mergecopies(repo, c1, c2, ca):
     """
diff --git a/tests/test-mv-cp-st-diff.t b/tests/test-mv-cp-st-diff.t
--- a/tests/test-mv-cp-st-diff.t
+++ b/tests/test-mv-cp-st-diff.t
@@ -670,7 +670,6 @@ single copy
   
   % hg st -C --rev . --rev 0
   M a
-    b
   R b
   
   % hg diff --git --rev . --rev 0
@@ -728,7 +727,6 @@ single copy
   
   % hg st -C --rev . --rev 2
   M a
-    b
   A x/y
   R b
   
@@ -1072,7 +1070,6 @@ copy chain
   
   % hg st -C --rev . --rev 0
   M a
-    b
   R b
   R c
   
@@ -1148,7 +1145,6 @@ copy chain
   
   % hg st -C --rev . --rev 2
   M a
-    b
   A x/y
   R b
   R c
diff --git a/tests/test-rebase-rename.t b/tests/test-rebase-rename.t
--- a/tests/test-rebase-rename.t
+++ b/tests/test-rebase-rename.t
@@ -20,7 +20,10 @@
   $ hg ci -Am B
   adding b
 
-  $ hg up -q -C 0
+  $ hg mv b b-renamed
+  $ hg ci -m 'rename B'
+
+  $ hg up -q -C 1
 
   $ hg mv a a-renamed
 
@@ -28,28 +31,32 @@
   created new head
 
   $ hg tglog
-  @  2: 'rename A'
+  @  3: 'rename A'
   |
-  | o  1: 'B'
+  | o  2: 'rename B'
   |/
+  o  1: 'B'
+  |
   o  0: 'A'
   
 
 Rename is tracked:
 
   $ hg tlog -p --git -r tip
-  2: 'rename A' 
+  3: 'rename A' 
   diff --git a/a b/a-renamed
   rename from a
   rename to a-renamed
   
 Rebase the revision containing the rename:
 
-  $ hg rebase -s 2 -d 1
+  $ hg rebase -s 3 -d 2
   saved backup bundle to $TESTTMP/a/.hg/strip-backup/*-backup.hg (glob)
 
   $ hg tglog
-  @  2: 'rename A'
+  @  3: 'rename A'
+  |
+  o  2: 'rename B'
   |
   o  1: 'B'
   |
@@ -59,11 +66,32 @@ Rebase the revision containing the renam
 Rename is not lost:
 
   $ hg tlog -p --git -r tip
-  2: 'rename A' 
+  3: 'rename A' 
   diff --git a/a b/a-renamed
   rename from a
   rename to a-renamed
   
+
+Rebased revision does not contain information about b (issue3739)
+
+  $ hg log -r 3 --debug
+  changeset:   3:3b905b1064f14ace3ad02353b79dd42d32981655
+  tag:         tip
+  phase:       draft
+  parent:      2:920a371a5635af23a26a011ca346cecd1cfcb942
+  parent:      -1:0000000000000000000000000000000000000000
+  manifest:    3:c4a62b2b64593c8fe0523d4c1ba2e243a8bd4dce
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  files+:      a-renamed
+  files-:      a
+  extra:       branch=default
+  extra:       rebase_source=89af05cb38a281f891c6f5581dd027092da29166
+  description:
+  rename A
+  
+  
+
   $ cd ..
 
 
@@ -78,47 +106,75 @@ Rename is not lost:
   $ hg ci -Am B
   adding b
 
-  $ hg up -q -C 0
+  $ hg cp b b-copied
+  $ hg ci -Am 'copy B'
+
+  $ hg up -q -C 1
 
   $ hg cp a a-copied
   $ hg ci -m 'copy A'
   created new head
 
   $ hg tglog
-  @  2: 'copy A'
+  @  3: 'copy A'
   |
-  | o  1: 'B'
+  | o  2: 'copy B'
   |/
+  o  1: 'B'
+  |
   o  0: 'A'
   
 Copy is tracked:
 
   $ hg tlog -p --git -r tip
-  2: 'copy A' 
+  3: 'copy A' 
   diff --git a/a b/a-copied
   copy from a
   copy to a-copied
   
 Rebase the revision containing the copy:
 
-  $ hg rebase -s 2 -d 1
+  $ hg rebase -s 3 -d 2
   saved backup bundle to $TESTTMP/b/.hg/strip-backup/*-backup.hg (glob)
 
   $ hg tglog
-  @  2: 'copy A'
+  @  3: 'copy A'
+  |
+  o  2: 'copy B'
   |
   o  1: 'B'
   |
   o  0: 'A'
   
+
 Copy is not lost:
 
   $ hg tlog -p --git -r tip
-  2: 'copy A' 
+  3: 'copy A' 
   diff --git a/a b/a-copied
   copy from a
   copy to a-copied
   
+
+Rebased revision does not contain information about b (issue3739)
+
+  $ hg log -r 3 --debug
+  changeset:   3:98f6e6dbf45ab54079c2237fbd11066a5c41a11d
+  tag:         tip
+  phase:       draft
+  parent:      2:39e588434882ff77d01229d169cdc77f29e8855e
+  parent:      -1:0000000000000000000000000000000000000000
+  manifest:    3:2232f329d66fffe3930d43479ae624f66322b04d
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  files+:      a-copied
+  extra:       branch=default
+  extra:       rebase_source=0a8162ff18a8900df8df8ef7ac0046955205613e
+  description:
+  copy A
+  
+  
+
   $ cd ..
 
 


More information about the Mercurial-devel mailing list