--- a/hgext/rebase.py Mon Jun 30 18:52:57 2014 -0300
+++ b/hgext/rebase.py Tue Jul 01 23:27:32 2014 -0500
@@ -345,7 +345,16 @@
'resolve, then hg rebase --continue)'))
finally:
ui.setconfig('ui', 'forcemerge', '', 'rebase')
- cmdutil.duplicatecopies(repo, rev, target)
+ if collapsef:
+ cmdutil.duplicatecopies(repo, rev, target)
+ else:
+ # If we're not using --collapse, we need to
+ # duplicate copies between the revision we're
+ # rebasing and its first parent, but *not*
+ # duplicate any copies that have already been
+ # performed in the destination.
+ p1rev = repo[rev].p1().rev()
+ cmdutil.duplicatecopies(repo, rev, p1rev, skiprev=target)
if not collapsef:
newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn,
editor=editor)
--- a/mercurial/cmdutil.py Mon Jun 30 18:52:57 2014 -0300
+++ b/mercurial/cmdutil.py Tue Jul 01 23:27:32 2014 -0500
@@ -1913,11 +1913,22 @@
return err
-def duplicatecopies(repo, rev, fromrev):
- '''reproduce copies from fromrev to rev in the dirstate'''
+def duplicatecopies(repo, rev, fromrev, skiprev=None):
+ '''reproduce copies from fromrev to rev in the dirstate
+
+ If skiprev is specified, it's a revision that should be used to
+ filter copy records. Any copies that occur between fromrev and
+ skiprev will not be duplicated, even if they appear in the set of
+ copies between fromrev and rev.
+ '''
+ exclude = {}
+ if skiprev is not None:
+ exclude = copies.pathcopies(repo[fromrev], repo[skiprev])
for dst, src in copies.pathcopies(repo[fromrev], repo[rev]).iteritems():
# copies.pathcopies returns backward renames, so dst might not
# actually be in the dirstate
+ if dst in exclude:
+ continue
if repo.dirstate[dst] in "nma":
repo.dirstate.copy(src, dst)
--- a/mercurial/tags.py Mon Jun 30 18:52:57 2014 -0300
+++ b/mercurial/tags.py Tue Jul 01 23:27:32 2014 -0500
@@ -72,6 +72,15 @@
filetags = _readtags(
ui, repo, data.splitlines(), "localtags",
recode=encoding.fromlocal)
+
+ # remove tags pointing to invalid nodes
+ cl = repo.changelog
+ for t in filetags.keys():
+ try:
+ cl.rev(filetags[t][0])
+ except (LookupError, ValueError):
+ del filetags[t]
+
_updatetags(filetags, "local", alltags, tagtypes)
def _readtags(ui, repo, lines, fn, recode=None):
--- a/tests/test-obsolete.t Mon Jun 30 18:52:57 2014 -0300
+++ b/tests/test-obsolete.t Tue Jul 01 23:27:32 2014 -0500
@@ -907,3 +907,15 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: A
+Test that removing a local tag does not cause some commands to fail
+
+ $ hg tag -l -r tip tiptag
+ $ hg tags
+ tiptag 2:3816541e5485
+ tip 2:3816541e5485
+ visible 0:193e9254ce7e
+ $ hg --config extensions.strip= strip -r tip --no-backup
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg tags
+ visible 0:193e9254ce7e
+ tip 0:193e9254ce7e
--- a/tests/test-rebase-rename.t Mon Jun 30 18:52:57 2014 -0300
+++ b/tests/test-rebase-rename.t Tue Jul 01 23:27:32 2014 -0500
@@ -240,3 +240,84 @@
1 files changed, 1 insertions(+), 0 deletions(-)
$ cd ..
+
+Verify that copies get preserved (issue4192).
+ $ hg init copy-gets-preserved
+ $ cd copy-gets-preserved
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit --message "File a created"
+ $ hg copy a b
+ $ echo b > b
+ $ hg commit --message "File b created as copy of a and modified"
+ $ hg copy b c
+ $ echo c > c
+ $ hg commit --message "File c created as copy of b and modified"
+ $ hg copy c d
+ $ echo d > d
+ $ hg commit --message "File d created as copy of c and modified"
+
+Note that there are four entries in the log for d
+ $ hg tglog --follow d
+ @ 3: 'File d created as copy of c and modified'
+ |
+ o 2: 'File c created as copy of b and modified'
+ |
+ o 1: 'File b created as copy of a and modified'
+ |
+ o 0: 'File a created'
+
+Update back to before we performed copies, and inject an unrelated change.
+ $ hg update 0
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+
+ $ echo unrelated > unrelated
+ $ hg add unrelated
+ $ hg commit --message "Unrelated file created"
+ created new head
+ $ hg update 4
+ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Rebase the copies on top of the unrelated change.
+ $ hg rebase --source 1 --dest 4
+ saved backup bundle to $TESTTMP/copy-gets-preserved/.hg/*.hg (glob)
+ $ hg update 4
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+There should still be four entries in the log for d
+ $ hg tglog --follow d
+ @ 4: 'File d created as copy of c and modified'
+ |
+ o 3: 'File c created as copy of b and modified'
+ |
+ o 2: 'File b created as copy of a and modified'
+ |
+ o 0: 'File a created'
+
+Same steps as above, but with --collapse on rebase to make sure the
+copy records collapse correctly.
+ $ hg co 1
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ echo more >> unrelated
+ $ hg ci -m 'unrelated commit is unrelated'
+ created new head
+ $ hg rebase -s 2 --dest 5 --collapse
+ merging b and c to c
+ merging c and d to d
+ saved backup bundle to $TESTTMP/copy-gets-preserved/.hg/*.hg (glob)
+ $ hg co tip
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+This should show both revision 3 and 0 since 'd' was transitively a
+copy of 'a'.
+
+ $ hg tglog --follow d
+ @ 3: 'Collapsed revision
+ | * File b created as copy of a and modified
+ | * File c created as copy of b and modified
+ | * File d created as copy of c and modified'
+ o 0: 'File a created'
+
+
+ $ cd ..