context: fix sanity check in metadataonlyctx

Summary:
Previously, this check was subtly wrong, causing it to fail for empty
commits (which have the same manifest as their parents). Update the check to
ensure the actual thing we want to ensure -- that the caller isn't creating
incorrect commits.

The failure would happen in this case:

```
  B  empty commit (manifest Am)
  |
  A  draft commit (manifest Am)
 /
M  master (manifest Mm)
```

When metaediting `A`, `metaedit` would then "rebase" `B` onto `A'` to create
`B'`, with both `A'` and `B'` reusing `Am` as their manifest. The old check
would fail here because the parent of `Am` is `Mm`, but the manifest of `A'`
(the parent of `B'`) is `Am`, so when checking the manifest of the parent
against the parent of the manifest, we would find that `Am != Mm` and fail.

The actual check we wanted was that the manifest of the parent of `B'` is the
same as the manifest of the parent of `B` -- which the old check approximated
as long as no manifests were reused in the stack. As this is not sufficient
with empty commits, we instead want to check that the manifest of the old
parent matches the manifest of the new parent, which we now do.

By avoid reading `manifest.parents`, this would also avoid some lazy tree
fetches, therefore speed up metaedit in certain cases.

Reviewed By: quark-zju

Differential Revision: D9013995

fbshipit-source-id: 4d0b05fc9bb81d115cd87ba2bf98aa253ae6f88b
This commit is contained in:
Ryan McElroy 2018-07-27 02:40:25 -07:00 committed by Facebook Github Bot
parent 2b7e9e5e8b
commit 9e51fdef40
3 changed files with 29 additions and 12 deletions

View File

@ -2925,18 +2925,23 @@ class metadataonlyctx(committablectx):
parents.append(repo[nullid])
p1, p2 = self._parents = parents
# sanity check to ensure that the reused manifest parents are
# manifests of our commit parents
mp1, mp2 = self.manifestctx().parents
if p1 != nullid and p1.manifestnode() != mp1:
# sanity check to ensure that our parent's manifest has not changed
# from our original parent's manifest to ensure the caller is not
# creating invalid commits
ops = [repo[p] for p in originalctx.parents() if p is not None]
while len(ops) < 2:
ops.append(repo[nullid])
op1, op2 = ops
if p1.manifestnode() != op1.manifestnode():
raise RuntimeError(
"can't reuse the manifest: "
"its p1 (%s) doesn't match the new ctx p1 (%s)"
% (hex(p1.manifestnode()), hex(mp1))
"new p1 manifest (%s) is not the old p1 manifest (%s)"
% (hex(p1.manifestnode()), hex(op1.manifestnode()))
)
if p2 != nullid and p2.manifestnode() != mp2:
if p2.manifestnode() != op2.manifestnode():
raise RuntimeError(
"can't reuse the manifest: " "its p2 doesn't match the new ctx p2"
"new p2 manifest (%s) is not the old p2 manifest (%s)"
% (hex(p2.manifestnode()), hex(op2.manifestnode()))
)
self._files = originalctx.files()

View File

@ -37,7 +37,7 @@ Tests about metadataonlyctx
summary: Changed
$ hg --config extensions.metaedit=$TESTTMP/metaedit.py metaedit 'parents=0' 2>&1 | egrep '^RuntimeError'
RuntimeError: can't reuse the manifest: its p1 (007d8c9d88841325f5c6b06371b35b4e8a2b1a83) doesn't match the new ctx p1 (cb5cbbc1bfbf24cc34b9e8c16914e9caa2d2a7fd)
RuntimeError: new p1 manifest (007d8c9d88841325f5c6b06371b35b4e8a2b1a83) is not the old p1 manifest (cb5cbbc1bfbf24cc34b9e8c16914e9caa2d2a7fd)
$ hg --config extensions.metaedit=$TESTTMP/metaedit.py metaedit 'user=foo <foo@example.com>'
$ hg log -r tip

View File

@ -391,5 +391,17 @@ Test copying obsmarkers
Test empty commit
$ hg co -q 1be7301b35ae
$ hg commit --config ui.allowemptycommit=true -m empty
$ hg metaedit -r ".^" -m "parent of empty commit" 2>&1 | grep RuntimeError
RuntimeError: can't reuse the manifest: its p1 (c74667c33d85705d7872136b99225b744c924aa5) doesn't match the new ctx p1 (eb79886383871977bccdb3000c275a279f0d4c99)
$ hg metaedit -r ".^" -m "parent of empty commit"
$ glog -r 'all()'
@ 11:e582f22eefc0@default(draft) empty
|
o 10:539393debc47@default(draft) parent of empty commit
|
| o 8:52bc6136aa97@default(draft) D
| |
| x 6:19437442f9e4@default(draft) C
|/
o 5:888bb4818188@default(draft) B1
|
o 0:426bada5c675@default(draft) A