Bug 3739 - Rebases can store incorrect copy information
Summary: Rebases can store incorrect copy information
Status: RESOLVED FIXED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: website (show other bugs)
Version: 3.2-rc
Hardware: All All
: normal bug
Assignee: Bugzilla
URL:
Keywords:
: 2404 2471 3833 (view as bug list)
Depends on:
Blocks:
 
Reported: 2012-12-19 20:08 UTC by Siddharth Agarwal
Modified: 2014-11-04 14:07 UTC (History)
8 users (show)

See Also:
Python Version: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Siddharth Agarwal 2012-12-19 20:08 UTC
In some situations, the dest changes for rebases can store incorrect copy information. This can lead to all sorts of misleading error messages and possibly dataloss with binary files. A test to demonstrate this is in the comments.
Comment 1 Siddharth Agarwal 2012-12-19 20:09 UTC
Here's a test with the expected output inline. This fails, with the output of run-tests.py in the next comment.

# HG changeset patch
# User Siddharth Agarwal <sid0@fb.com>
# Date 1355964354 28800
# Node ID bd74cd178c9ae6c575996a0ffe6a385d0b78ceb2
# Parent  d00f0bfe007da572898cb37305a70ec31ee1ce8c
rebase: add test for clownshoes

diff --git a/hgext/rebase.py b/hgext/rebase.py
--- a/hgext/rebase.py
+++ b/hgext/rebase.py
@@ -358,12 +358,12 @@ def concludenode(repo, rev, p1, p2, comm
         ctx = repo[rev]
         if commitmsg is None:
             commitmsg = ctx.description()
-        extra = {'rebase_source': ctx.hex()}
-        if extrafn:
-            extrafn(ctx, extra)
+        # extra = {'rebase_source': ctx.hex()}
+        # if extrafn:
+        #     extrafn(ctx, extra)
         # Commit might fail if unresolved files exist
         newrev = repo.commit(text=commitmsg, user=ctx.user(),
-                             date=ctx.date(), extra=extra, editor=editor)
+                             date=ctx.date(), editor=editor)
         repo.dirstate.setbranch(repo[newrev].branch())
         targetphase = max(ctx.phase(), phases.draft)
         # retractboundary doesn't overwrite upper phase inherited from parent
diff --git a/tests/test-rebase-foo.t b/tests/test-rebase-foo.t
new file mode 100644
--- /dev/null
+++ b/tests/test-rebase-foo.t
@@ -0,0 +1,101 @@
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > rebase =
+  > evolve = !
+  > 
+  > [alias]
+  > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
+  > EOF
+
+
+  $ hg init a
+  $ cd a
+  $ touch fa
+  $ hg add fa
+  $ hg ci -m "A"
+  $ hg cp fa fb
+  $ hg ci -m "B"
+  $ touch fc
+  $ hg add fc
+  $ hg ci -m "C"
+
+  $ hg tglog
+  @  2: 'C'
+  |
+  o  1: 'B'
+  |
+  o  0: 'A'
+  
+
+  $ hg log --debug -r 2
+  changeset:   2:8da66e8263912a675464d675939b37e2edc7d636
+  tag:         tip
+  phase:       draft
+  parent:      1:cbf1f7d8b290e3479334c8853281e26488b209f9
+  parent:      -1:0000000000000000000000000000000000000000
+  manifest:    2:8a2895d110db6a8a6897856f8823636d85c91996
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  files+:      fc
+  extra:       branch=default
+  description:
+  C
+  
+  
+
+  $ hg rebase -s 2 -d 0
+  saved backup bundle to $TESTTMP/a/.hg/strip-backup/8da66e826391-backup.hg
+
+  $ hg log --debug -r 2
+  changeset:   2:a3cc092e07cbda4370c5dabee64f3e39dff80782
+  tag:         tip
+  phase:       draft
+  parent:      0:e42d81ab209791e29e25e14f7687478957522c0d
+  parent:      -1:0000000000000000000000000000000000000000
+  manifest:    2:e810681f783afbe6c0c14db0c9d4f2f909b61341
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  files+:      fc
+  extra:       branch=default
+  description:
+  C
+  
+  
+
+  $ hg rebase -s 2 -d 1
+  saved backup bundle to $TESTTMP/a/.hg/strip-backup/a3cc092e07cb-backup.hg
+
+  $ hg log --debug -r 2
+  changeset:   2:8da66e8263912a675464d675939b37e2edc7d636
+  tag:         tip
+  phase:       draft
+  parent:      1:cbf1f7d8b290e3479334c8853281e26488b209f9
+  parent:      -1:0000000000000000000000000000000000000000
+  manifest:    2:8a2895d110db6a8a6897856f8823636d85c91996
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  files+:      fc
+  extra:       branch=default
+  description:
+  C
+  
+  
+
+  $ hg rebase -s 2 -d 0
+  saved backup bundle to $TESTTMP/a/.hg/strip-backup/8da66e826391-backup.hg
+
+  $ hg log --debug -r 2
+  changeset:   2:a3cc092e07cbda4370c5dabee64f3e39dff80782
+  tag:         tip
+  phase:       draft
+  parent:      0:e42d81ab209791e29e25e14f7687478957522c0d
+  parent:      -1:0000000000000000000000000000000000000000
+  manifest:    2:e810681f783afbe6c0c14db0c9d4f2f909b61341
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  files+:      fc
+  extra:       branch=default
+  description:
+  C
+  
+
Comment 2 Siddharth Agarwal 2012-12-19 20:10 UTC
Failure output. Note the extra files present. From looking at debug logs, it seems like this is recorded as a copy from fb to fa.

(a) That's wrong in the first place -- changeset C has no copies.
(b) Changeset B has a copy from fa to fb, not fb to fa.

--- /home/sid0/mercurial/hg-experimental/tests/test-rebase-foo.t
+++ /home/sid0/mercurial/hg-experimental/tests/test-rebase-foo.t.err
@@ -66,14 +66,15 @@
   saved backup bundle to $TESTTMP/a/.hg/strip-backup/a3cc092e07cb-backup.hg
 
   $ hg log --debug -r 2
-  changeset:   2:8da66e8263912a675464d675939b37e2edc7d636
+  changeset:   2:2e64d2499ee62a3bc281553cdcbdb1cab5fb82cc
   tag:         tip
   phase:       draft
   parent:      1:cbf1f7d8b290e3479334c8853281e26488b209f9
   parent:      -1:0000000000000000000000000000000000000000
-  manifest:    2:8a2895d110db6a8a6897856f8823636d85c91996
+  manifest:    2:10813a0ace4aaf32016ead821d35db8dc03c062e
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
+  files:       fa
   files+:      fc
   extra:       branch=default
   description:
@@ -82,7 +83,7 @@
   
 
   $ hg rebase -s 2 -d 0
-  saved backup bundle to $TESTTMP/a/.hg/strip-backup/8da66e826391-backup.hg
+  saved backup bundle to $TESTTMP/a/.hg/strip-backup/2e64d2499ee6-backup.hg
 
   $ hg log --debug -r 2
   changeset:   2:a3cc092e07cbda4370c5dabee64f3e39dff80782

ERROR: /home/sid0/mercurial/hg-experimental/tests/test-rebase-foo.t output changed
!
Failed test-rebase-foo.t: output changed
# Ran 1 tests, 0 skipped, 1 failed.
Comment 3 Bryan O'Sullivan 2012-12-19 21:05 UTC
*** Bug 2471 has been marked as a duplicate of this bug. ***
Comment 4 Bryan O'Sullivan 2012-12-19 21:06 UTC
*** Bug 2404 has been marked as a duplicate of this bug. ***
Comment 5 HG Bot 2013-01-02 01:49 UTC
Fixed by http://selenic.com/repo/hg/rev/f23dea2b296e
Siddharth Agarwal <sid0@fb.com>
copies: do not track backward copies, only renames (issue3739)

The inverse of a rename is a rename, but the inverse of a copy is not a copy.
Presenting it as such -- in particular, stuffing it into the same dict as real
copies -- causes bugs because other code starts believing the inverse copies
are 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 inverse copy (which was
hitherto presented as a real copy) is no longer displayed.

Keeping track of inverse copies is useful in some situations -- composability
of diffs, for example, since adding "a" followed by an inverse copy "b" to "a"
is equivalent to a rename "b" to "a". However, representing them would require
a more complex data structure than the same dict in which real copies are also
stored.

(please test the fix)
Comment 6 Siddharth Agarwal 2013-02-19 16:58 UTC
*** Bug 3833 has been marked as a duplicate of this bug. ***
Comment 7 Matt Mackall 2014-11-04 14:07 UTC
Bug reopened with nonsensical component change and no additional info -> close.

Open a new bug, please. Even if it superficially appears to be the same, it will have a different fix so it's a different bug.