D6183: copies: add config option for writing copy metadata to file and/or changset
martinvonz (Martin von Zweigbergk)
phabricator at mercurial-scm.org
Sat Apr 13 18:17:44 EDT 2019
martinvonz updated this revision to Diff 14734.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D6183?vs=14663&id=14734
REVISION DETAIL
https://phab.mercurial-scm.org/D6183
AFFECTED FILES
mercurial/changelog.py
mercurial/configitems.py
mercurial/localrepo.py
tests/test-annotate.t
tests/test-copies-in-changeset.t
tests/test-fastannotate-hg.t
CHANGE DETAILS
diff --git a/tests/test-fastannotate-hg.t b/tests/test-fastannotate-hg.t
--- a/tests/test-fastannotate-hg.t
+++ b/tests/test-fastannotate-hg.t
@@ -443,7 +443,7 @@
> def reposetup(ui, repo):
> class legacyrepo(repo.__class__):
> def _filecommit(self, fctx, manifest1, manifest2,
- > linkrev, tr, changelist):
+ > linkrev, tr, changelist, includecopymeta):
> fname = fctx.path()
> text = fctx.data()
> flog = self.file(fname)
diff --git a/tests/test-copies-in-changeset.t b/tests/test-copies-in-changeset.t
new file mode 100644
--- /dev/null
+++ b/tests/test-copies-in-changeset.t
@@ -0,0 +1,105 @@
+
+ $ cat >> $HGRCPATH << EOF
+ > [experimental]
+ > copies.write-to=changeset-only
+ > [alias]
+ > changesetcopies = log -r . -T 'files: {files}
+ > {extras % "{ifcontains("copies", key, "{key}: {value}\n")}"}'
+ > EOF
+
+Check that copies are recorded correctly
+
+ $ hg init repo
+ $ cd repo
+ $ echo a > a
+ $ hg add a
+ $ hg ci -m initial
+ $ hg cp a b
+ $ hg cp a c
+ $ hg cp a d
+ $ hg ci -m 'copy a to b, c, and d'
+ $ hg changesetcopies
+ files: b c d
+ p1copies: b\x00a (esc)
+ c\x00a (esc)
+ d\x00a (esc)
+
+Check that renames are recorded correctly
+
+ $ hg mv b b2
+ $ hg ci -m 'rename b to b2'
+ $ hg changesetcopies
+ files: b b2
+ p1copies: b2\x00b (esc)
+
+Rename onto existing file. This should get recorded in the changeset files list and in the extras,
+even though there is no filelog entry.
+
+ $ hg cp b2 c --force
+ $ hg st --copies
+ M c
+ b2
+ $ hg debugindex c
+ rev linkrev nodeid p1 p2
+ 0 1 b789fdd96dc2 000000000000 000000000000
+ $ hg ci -m 'move b onto d'
+ $ hg changesetcopies
+ files: c
+ p1copies: c\x00b2 (esc)
+ $ hg debugindex c
+ rev linkrev nodeid p1 p2
+ 0 1 b789fdd96dc2 000000000000 000000000000
+
+Create a merge commit with copying done during merge.
+
+ $ hg co 0
+ 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+ $ hg cp a e
+ $ hg cp a f
+ $ hg ci -m 'copy a to e and f'
+ created new head
+ $ hg merge 3
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+File 'a' exists on both sides, so 'g' could be recorded as being from p1 or p2, but we currently
+always record it as being from p1
+ $ hg cp a g
+File 'd' exists only in p2, so 'h' should be from p2
+ $ hg cp d h
+File 'f' exists only in p1, so 'i' should be from p1
+ $ hg cp f i
+ $ hg ci -m 'merge'
+ $ hg changesetcopies
+ files: g h i
+ p1copies: g\x00a (esc)
+ i\x00f (esc)
+ p2copies: h\x00d (esc)
+
+Test writing to both changeset and filelog
+
+ $ hg cp a j
+ $ hg ci -m 'copy a to j' --config experimental.copies.write-to=compatibility
+ $ hg changesetcopies
+ files: j
+ p1copies: j\x00a (esc)
+ $ hg debugdata j 0
+ \x01 (esc)
+ copy: a
+ copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
+ \x01 (esc)
+ a
+
+Test writing only to filelog
+
+ $ hg cp a k
+ $ hg ci -m 'copy a to k' --config experimental.copies.write-to=filelog-only
+ $ hg changesetcopies
+ files: k
+ $ hg debugdata k 0
+ \x01 (esc)
+ copy: a
+ copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
+ \x01 (esc)
+ a
+
+ $ cd ..
diff --git a/tests/test-annotate.t b/tests/test-annotate.t
--- a/tests/test-annotate.t
+++ b/tests/test-annotate.t
@@ -438,7 +438,7 @@
> def reposetup(ui, repo):
> class legacyrepo(repo.__class__):
> def _filecommit(self, fctx, manifest1, manifest2,
- > linkrev, tr, changelist):
+ > linkrev, tr, changelist, includecopymeta):
> fname = fctx.path()
> text = fctx.data()
> flog = self.file(fname)
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -2316,7 +2316,8 @@
"""Returns the wlock if it's held, or None if it's not."""
return self._currentlock(self._wlockref)
- def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
+ def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist,
+ includecopymeta):
"""
commit an individual file as part of a larger transaction
"""
@@ -2375,8 +2376,9 @@
if cnode:
self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(cnode)))
- meta["copy"] = cfname
- meta["copyrev"] = hex(cnode)
+ if includecopymeta:
+ meta["copy"] = cfname
+ meta["copyrev"] = hex(cnode)
fparent1, fparent2 = nullid, newfparent
else:
self.ui.warn(_("warning: can't find ancestor for '%s' "
@@ -2544,6 +2546,12 @@
p1, p2 = ctx.p1(), ctx.p2()
user = ctx.user()
+ writecopiesto = self.ui.config('experimental', 'copies.write-to')
+ writefilecopymeta = writecopiesto != 'changeset-only'
+ p1copies, p2copies = None, None
+ if writecopiesto in ('changeset-only', 'compatibility'):
+ p1copies = ctx.p1copies()
+ p2copies = ctx.p2copies()
with self.lock(), self.transaction("commit") as tr:
trp = weakref.proxy(tr)
@@ -2577,7 +2585,8 @@
else:
added.append(f)
m[f] = self._filecommit(fctx, m1, m2, linkrev,
- trp, changed)
+ trp, changed,
+ writefilecopymeta)
m.setflag(f, fctx.flags())
except OSError:
self.ui.warn(_("trouble committing %s!\n") %
@@ -2631,7 +2640,8 @@
self.changelog.delayupdate(tr)
n = self.changelog.add(mn, files, ctx.description(),
trp, p1.node(), p2.node(),
- user, ctx.date(), ctx.extra().copy())
+ user, ctx.date(), ctx.extra().copy(),
+ p1copies, p2copies)
xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
parent2=xp2)
diff --git a/mercurial/configitems.py b/mercurial/configitems.py
--- a/mercurial/configitems.py
+++ b/mercurial/configitems.py
@@ -488,6 +488,9 @@
coreconfigitem('experimental', 'copies.read-from',
default="filelog-only",
)
+coreconfigitem('experimental', 'copies.write-to',
+ default='filelog-only',
+)
coreconfigitem('experimental', 'crecordtest',
default=None,
)
diff --git a/mercurial/changelog.py b/mercurial/changelog.py
--- a/mercurial/changelog.py
+++ b/mercurial/changelog.py
@@ -80,6 +80,13 @@
]
return "\0".join(items)
+def encodecopies(copies):
+ items = [
+ '%s\0%s' % (_string_escape(k), _string_escape(copies[k]))
+ for k in sorted(copies)
+ ]
+ return "\n".join(items)
+
def stripdesc(desc):
"""strip trailing whitespace and leading and trailing empty lines"""
return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
@@ -533,7 +540,7 @@
return l[3:]
def add(self, manifest, files, desc, transaction, p1, p2,
- user, date=None, extra=None):
+ user, date=None, extra=None, p1copies=None, p2copies=None):
# Convert to UTF-8 encoded bytestrings as the very first
# thing: calling any method on a localstr object will turn it
# into a str object and the cached UTF-8 string is thus lost.
@@ -562,6 +569,13 @@
elif branch in (".", "null", "tip"):
raise error.StorageError(_('the name \'%s\' is reserved')
% branch)
+ if (p1copies or p2copies) and extra is None:
+ extra = {}
+ if p1copies:
+ extra['p1copies'] = encodecopies(p1copies)
+ if p2copies:
+ extra['p2copies'] = encodecopies(p2copies)
+
if extra:
extra = encodeextra(extra)
parseddate = "%s %s" % (parseddate, extra)
To: martinvonz, #hg-reviewers
Cc: yuja, pulkit, gracinet, marmoute, mercurial-devel
More information about the Mercurial-devel
mailing list