This is an archive of the discontinued Mercurial Phabricator instance.

phabricator: teach `getoldnodedrevmap()` to handle folded reviews
ClosedPublic

Authored by mharbison72 on Mar 20 2020, 5:24 PM.

Details

Summary

The tricky part here is reasoning through all of the possible predecessor
scenarios. In the typical case of submitting a folded range and then
resubmitting it (also folded), filtering the list of commits for the diff stored
on Phabricator through the local predecessor list for each single node will
result in the typical 1:1 mapping to the old node.

There are edge cases like using hg fold within the range prior to
resubmitting, that will result in mapping to multiple old nodes. In that case,
the first direct predecessor is needed for the base of the diff, and the last
direct predecessor is needed for the head of the diff in order to make sure that
the entire range is included in the diff content. And none of this matters for
commits in the middle of the range, as they are never used.

Fortunately the only crucial thing here is the drev number for each node. For
these complicated cases where there are multiple old nodes, simply ignore them
all. This will cause createdifferentialrevision() to generate a new diff
(within the same Differential), and avoids complicating the code.

Diff Detail

Repository
rHG Mercurial
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

mharbison72 created this revision.Mar 20 2020, 5:24 PM
Alphare requested changes to this revision.Mar 25 2020, 2:46 PM
Alphare added a subscriber: Alphare.

Could you add a comment about what happens if you hg split either the base or the tip of the range?

This revision now requires changes to proceed.Mar 25 2020, 2:46 PM

Could you add a comment about what happens if you hg split either the base or the tip of the range?

I think what happens is each newnode key maps to a single precursor, so it's like a regular amend case. It just happens that multiple newnode keys have the same oldnode in their value tuple. But all we care about is the first and last newnode in the range.

That said, I tried creating a simple test where I amended in a new file to the last commit of the last test, split it with the internal extension, and... Somehow I ended up with a weird state where the first half of the split is pruned, making the second half orphaned. I tried obslog on it, and it raises an AssertionError because of a cycle. I assume this is a known problem? Is there some other trivial split that works? (It's really hard getting the interactive sequence right in these *.t files, and I'm basically doing it by trial and error.)

CC @marmoute for obsmarker wizardry

$ hg obslog . --config extensions.evolve=/d/hg-evolve/hgext3rd/evolve
@  222d8ec1e644 (14) four: extend the fold range
|
** unknown exception encountered, please report by visiting
** https://mercurial-scm.org/wiki/BugTracker
** Python 2.7.15 (v2.7.15:ca079a3ea3, Apr 30 2018, 16:30:26) [MSC v.1500 64 bit (AMD64)]
** Mercurial Distributed SCM (version 5.3.1+389-9127f584b52b)
** Extensions loaded: phabricator, evolve
Traceback (most recent call last):
  File "d:\mercurial\hg", line 43, in <module>
    dispatch.run()
  File "d:\mercurial\mercurial\dispatch.py", line 111, in run
    status = dispatch(req)
  File "d:\mercurial\mercurial\dispatch.py", line 254, in dispatch
    ret = _runcatch(req) or 0
  File "d:\mercurial\mercurial\dispatch.py", line 428, in _runcatch
    return _callcatch(ui, _runcatchfunc)
  File "d:\mercurial\mercurial\dispatch.py", line 437, in _callcatch
    return scmutil.callcatch(ui, func)
  File "d:\mercurial\mercurial\scmutil.py", line 152, in callcatch
    return func()
  File "d:\mercurial\mercurial\dispatch.py", line 418, in _runcatchfunc
    return _dispatch(req)
  File "d:\mercurial\mercurial\dispatch.py", line 1182, in _dispatch
    lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
  File "d:\mercurial\mercurial\dispatch.py", line 866, in runcommand
    ret = _runcommand(ui, options, cmd, d)
  File "d:\mercurial\mercurial\dispatch.py", line 1193, in _runcommand
    return cmdfunc()
  File "d:\mercurial\mercurial\dispatch.py", line 1179, in <lambda>
    d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
  File "d:\mercurial\mercurial\util.py", line 1854, in check
    return func(*args, **kwargs)
  File "d:/hg-evolve/hgext3rd\evolve\obshistory.py", line 101, in cmdobshistory
    return _debugobshistorygraph(ui, repo, revs, opts)
  File "d:/hg-evolve/hgext3rd\evolve\obshistory.py", line 432, in _debugobshistorygraph
    compat.displaygraph(ui, repo, walker, displayer, edges)
  File "d:\mercurial\mercurial\logcmdutil.py", line 1042, in displaygraph
    for rev, type, ctx, parents in dag:
  File "d:/hg-evolve/hgext3rd\evolve\obshistory.py", line 330, in _obshistorywalker
    assert cycle
AssertionError
[1]

Could you add a comment about what happens if you hg split either the base or the tip of the range?

I think what happens is each newnode key maps to a single precursor, so it's like a regular amend case. It just happens that multiple newnode keys have the same oldnode in their value tuple. But all we care about is the first and last newnode in the range.
That said, I tried creating a simple test where I amended in a new file to the last commit of the last test, split it with the internal extension, and... Somehow I ended up with a weird state where the first half of the split is pruned...

Disregard this. What happened was that I split the commit in a way that recreated the content of the pre-amend commit. Because the timestamp is locked, it ended up reusing the existing (obsolete) commit. I guess there's no noise added to {extras} when splitting. With that out of the way, I confirmed my original thoughts above.

Alphare accepted this revision.Mar 31 2020, 4:33 AM
This revision was not accepted when it landed; it landed in state Needs Review.
This revision was automatically updated to reflect the committed changes.