diff --git a/mercurial/changelog.py b/mercurial/changelog.py --- a/mercurial/changelog.py +++ b/mercurial/changelog.py @@ -87,6 +87,18 @@ ] return "\n".join(items) +def decodecopies(data): + try: + copies = {} + for l in data.split('\n'): + k, v = l.split('\0') + copies[k] = v + return copies + except ValueError: + # Perhaps someone had chosen the same key name (e.g. "p1copies") and + # used different syntax for the value. + return None + def stripdesc(desc): """strip trailing whitespace and leading and trailing empty lines""" return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n') @@ -286,6 +298,16 @@ return self._text[off[2] + 1:off[3]].split('\n') @property + def p1copies(self): + rawcopies = self.extra.get('p1copies') + return rawcopies and decodecopies(rawcopies) + + @property + def p2copies(self): + rawcopies = self.extra.get('p2copies') + return rawcopies and decodecopies(rawcopies) + + @property def description(self): return encoding.tolocal(self._text[self._offsets[3] + 2:]) diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -441,6 +441,21 @@ return self._changeset.files @propertycache def _copies(self): + source = self._repo.ui.config('experimental', 'copies.read-from') + p1copies = self._changeset.p1copies + p2copies = self._changeset.p2copies + # If config says to get copy metadata only from changeset, then return + # that, defaulting to {} if there was no copy metadata. + # In compatibility mode, we return copy data from the changeset if + # it was recorded there, and otherwise we fall back to getting it from + # the filelogs (below). + if (source == 'changeset-only' or + (source == 'compatibility' and p1copies is not None)): + return p1copies or {}, p2copies or {} + + # Otherwise (config said to read only from filelog, or we are in + # compatiblity mode and there is not data in the changeset), we get + # the copy metadata from the filelogs. p1copies = {} p2copies = {} p1 = self.p1() diff --git a/mercurial/copies.py b/mercurial/copies.py --- a/mercurial/copies.py +++ b/mercurial/copies.py @@ -162,8 +162,8 @@ def usechangesetcentricalgo(repo): """Checks if we should use changeset-centric copy algorithms""" - return (repo.ui.config('experimental', 'copies.read-from') == - 'compatibility') + return (repo.ui.config('experimental', 'copies.read-from') in + ('changeset-only', 'compatibility')) def _committedforwardcopies(a, b, match): """Like _forwardcopies(), but b.rev() cannot be None (working copy)""" diff --git a/tests/test-copies-in-changeset.t b/tests/test-copies-in-changeset.t --- a/tests/test-copies-in-changeset.t +++ b/tests/test-copies-in-changeset.t @@ -2,9 +2,11 @@ $ cat >> $HGRCPATH << EOF > [experimental] > copies.write-to=changeset-only + > copies.read-from=changeset-only > [alias] > changesetcopies = log -r . -T 'files: {files} > {extras % "{ifcontains("copies", key, "{key}: {value}\n")}"}' + > showcopies = log -r . -T '{file_copies % "{source} -> {name}\n"}' > EOF Check that copies are recorded correctly @@ -23,6 +25,15 @@ p1copies: b\x00a (esc) c\x00a (esc) d\x00a (esc) + $ hg showcopies + a -> b + a -> c + a -> d + $ hg showcopies --config experimental.copies.read-from=compatibility + a -> b + a -> c + a -> d + $ hg showcopies --config experimental.copies.read-from=filelog-only Check that renames are recorded correctly @@ -31,6 +42,8 @@ $ hg changesetcopies files: b b2 p1copies: b2\x00b (esc) + $ hg showcopies + b -> b2 Rename onto existing file. This should get recorded in the changeset files list and in the extras, even though there is no filelog entry. @@ -46,6 +59,8 @@ $ hg changesetcopies files: c p1copies: c\x00b2 (esc) + $ hg showcopies + b2 -> c $ hg debugindex c rev linkrev nodeid p1 p2 0 1 b789fdd96dc2 000000000000 000000000000 @@ -74,6 +89,10 @@ p1copies: g\x00a (esc) i\x00f (esc) p2copies: h\x00d (esc) + $ hg showcopies + a -> g + d -> h + f -> i Test writing to both changeset and filelog @@ -88,6 +107,12 @@ copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 \x01 (esc) a + $ hg showcopies + a -> j + $ hg showcopies --config experimental.copies.read-from=compatibility + a -> j + $ hg showcopies --config experimental.copies.read-from=filelog-only + a -> j Test writing only to filelog @@ -101,5 +126,10 @@ copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 \x01 (esc) a + $ hg showcopies + $ hg showcopies --config experimental.copies.read-from=compatibility + a -> k + $ hg showcopies --config experimental.copies.read-from=filelog-only + a -> k $ cd .. diff --git a/tests/test-copies.t b/tests/test-copies.t --- a/tests/test-copies.t +++ b/tests/test-copies.t @@ -1,4 +1,4 @@ -#testcases filelog compatibility +#testcases filelog compatibility changeset $ cat >> $HGRCPATH << EOF > [extensions] @@ -14,6 +14,14 @@ > EOF #endif +#if changeset + $ cat >> $HGRCPATH << EOF + > [experimental] + > copies.read-from = changeset-only + > copies.write-to = changeset-only + > EOF +#endif + $ REPONUM=0 $ newrepo() { > cd $TESTTMP @@ -376,11 +384,13 @@ o 0 add x on branch 1 x $ hg debugp1copies -r 2 + x -> z (changeset !) $ hg debugp2copies -r 2 - x -> z + x -> z (no-changeset !) $ hg debugpathcopies 1 2 + x -> z (changeset !) $ hg debugpathcopies 0 2 - x -> z + x -> z (no-changeset !) Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent of the merge to the merge should include the copy from the other side. @@ -539,6 +549,9 @@ Grafting revision 4 on top of revision 2, showing that it respect the rename: +TODO: Make this work with copy info in changesets (probably by writing a +changeset-centric version of copies.mergecopies()) +#if no-changeset $ hg up 2 -q $ hg graft -r 4 --base 3 --hidden grafting 4:af28412ec03c "added d, modified b" (tip) @@ -554,6 +567,8 @@ b +baba +#endif + Test to make sure that fullcopytracing algorithm don't fail when both the merging csets are dirty (a dirty cset is one who is not the descendant of merge base) -------------------------------------------------------------------------------------------------