diff hgext/phabricator.py @ 44720:601ce5392cb0

phabricator: restack any new orphans created by phabsend (issue6045) Previously, posting a new review for a non head commit would orphan the head. The general case is any descendant of the selected revisions got orphaned if this was the first time the selected revisions were submitted. It doesn't happen when resubmitting. I've already had coworkers hit this a few times and get confused. Since posting a review isn't generally thought of as an editing operation, it would probably be easier for new users if we just restacked. This avoids restacking existing orphans around the submission because that may involve merge conflict resolution. Users who already have orphans should know how to stabilize them anyway. Differential Revision: https://phab.mercurial-scm.org/D8438
author Matt Harbison <matt_harbison@yahoo.com>
date Tue, 14 Apr 2020 18:51:23 -0400
parents c482e2fe444c
children c1c922391314
line wrap: on
line diff
--- a/hgext/phabricator.py	Sun Apr 12 13:11:42 2020 -0400
+++ b/hgext/phabricator.py	Tue Apr 14 18:51:23 2020 -0400
@@ -1457,6 +1457,17 @@
         unfi = repo.unfiltered()
         drevs = callconduit(ui, b'differential.query', {b'ids': drevids})
         with repo.wlock(), repo.lock(), repo.transaction(b'phabsend'):
+            # Eagerly evaluate commits to restabilize before creating new
+            # commits.  The selected revisions are excluded because they are
+            # automatically restacked as part of the submission process.
+            restack = [
+                c
+                for c in repo.set(
+                    b"(%ld::) - (%ld) - unstable() - obsolete() - public()",
+                    revs,
+                    revs,
+                )
+            ]
             wnode = unfi[b'.'].node()
             mapping = {}  # {oldnode: [newnode]}
             newnodes = []
@@ -1551,6 +1562,41 @@
             elif fold:
                 _debug(ui, b"no newnodes to update\n")
 
+            # Restack any children of first-time submissions that were orphaned
+            # in the process.  The ctx won't report that it is an orphan until
+            # the cleanup takes place below.
+            for old in restack:
+                parents = [
+                    mapping.get(old.p1().node(), (old.p1(),))[0],
+                    mapping.get(old.p2().node(), (old.p2(),))[0],
+                ]
+                new = context.metadataonlyctx(
+                    repo,
+                    old,
+                    parents=parents,
+                    text=old.description(),
+                    user=old.user(),
+                    date=old.date(),
+                    extra=old.extra(),
+                )
+
+                newnode = new.commit()
+
+                # Don't obsolete unselected descendants of nodes that have not
+                # been changed in this transaction- that results in an error.
+                if newnode != old.node():
+                    mapping[old.node()] = [newnode]
+                    _debug(
+                        ui,
+                        b"restabilizing %s as %s\n"
+                        % (short(old.node()), short(newnode)),
+                    )
+                else:
+                    _debug(
+                        ui,
+                        b"not restabilizing unchanged %s\n" % short(old.node()),
+                    )
+
             scmutil.cleanupnodes(repo, mapping, b'phabsend', fixphase=True)
             if wnode in mapping:
                 unfi.setparents(mapping[wnode][0])