rewriteutil: extract evolve code used to replace obsolete hashes in commits
authorMatt Harbison <matt_harbison@yahoo.com>
Mon, 24 Aug 2020 12:43:53 -0400
changeset 45424 0a57ef4b3bdb
parent 45423 d4cf80341589
child 45425 f7e293e0475f
rewriteutil: extract evolve code used to replace obsolete hashes in commits The evolve command uses it, but there are core things like `phabsend` and `rebase` that would also benefit. Differential Revision: https://phab.mercurial-scm.org/D8948
mercurial/rewriteutil.py
--- a/mercurial/rewriteutil.py	Mon Sep 07 17:16:16 2020 -0400
+++ b/mercurial/rewriteutil.py	Mon Aug 24 12:43:53 2020 -0400
@@ -7,16 +7,23 @@
 
 from __future__ import absolute_import
 
+import re
+
 from .i18n import _
 
 from . import (
     error,
     node,
     obsolete,
+    obsutil,
     revset,
+    scmutil,
 )
 
 
+sha1re = re.compile(br'\b[0-9a-f]{6,40}\b')
+
+
 def precheck(repo, revs, action=b'rewrite'):
     """check if revs can be rewritten
     action is used to control the error message.
@@ -70,3 +77,39 @@
             )
             % (command, empty_successor)
         )
+
+
+def update_hash_refs(repo, commitmsg):
+    """Replace all obsolete commit hashes in the message with the current hash.
+
+    If the obsolete commit was split or is divergent, the hash is not replaced
+    as there's no way to know which successor to choose.
+    """
+    cache = {}
+    sha1s = re.findall(sha1re, commitmsg)
+    unfi = repo.unfiltered()
+    for sha1 in sha1s:
+        fullnode = scmutil.resolvehexnodeidprefix(unfi, sha1)
+        if fullnode is None:
+            continue
+        ctx = unfi[fullnode]
+        if not ctx.obsolete():
+            continue
+
+        successors = obsutil.successorssets(repo, ctx.node(), cache=cache)
+
+        # We can't make any assumptions about how to update the hash if the
+        # cset in question was split or diverged.
+        if len(successors) == 1 and len(successors[0]) == 1:
+            newsha1 = node.hex(successors[0][0])
+            commitmsg = commitmsg.replace(sha1, newsha1[: len(sha1)])
+        else:
+            repo.ui.note(
+                _(
+                    b'The stale commit message reference to %s could '
+                    b'not be updated\n'
+                )
+                % sha1
+            )
+
+    return commitmsg