# HG changeset patch
# User Jun Wu <qu...@fb.com>
# Date 1490552007 25200
#      Sun Mar 26 11:13:27 2017 -0700
# Node ID b6766d75404fb8c5d26af016caa76f44b47ce156
# Parent  336512ee2f947f07149e399a84927f9d820d2b62
# Available At https://bitbucket.org/quark-zju/hg-draft
#              hg pull https://bitbucket.org/quark-zju/hg-draft -r b6766d75404f
histedit: revive commits on demand

This is to address the "histedit --abort" issue mentioned in [1].

This solution is safer than what [1] proposed because it does not use unsafe
history writing ("strip"). The "strip" has caused several repo corruptions
in production.

It's similar to what "hg touch" in mutable-history does [3], without using
random number. So it could be more reliably tested.

Note that if we have obsolete marker versions, and obsoleted revisions are
revived automatically, as I proposed in [2], the "revive" hack will be no
longer necessary.

[1]: 
https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-March/095572.html
[2]: 
https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-March/094586.html
[3]: 
https://bitbucket.org/marmoute/mutable-history/src/c7da63d48/hgext3rd/evolve/__init__.py?at=default&fileviewer=file-view-default#__init__.py-2541

diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -507,4 +507,30 @@ class histeditaction(object):
         return ctx, [(self.node, (ctx.node(),))]
 
+def _revive(repo, n, updatedirstate=True):
+    """given a node, make sure it's not obsoleted by adding noises
+
+    If updatedirstate is True and new node is created, set dirstate parent to
+    the new node.
+
+    Return new node that is not obsoleted.
+    """
+    unfi = repo.unfiltered()
+    origctx = ctx = unfi[n]
+    while ctx.obsolete():
+        extra = dict(ctx.extra())
+        revive = int(extra.get('__revive__', '0')) + 1
+        extra['__revive__'] = str(revive)
+        newctx = context.metadataonlyctx(repo, ctx, date=ctx.date(),
+                                         user=ctx.user(), extra=extra)
+        newnode = newctx.commit()
+        repo.ui.debug('node %s was revived as %s (revive=%d)\n'
+                      % (node.short(ctx.node()), node.short(newnode), revive))
+        ctx = unfi[newnode]
+    if origctx != ctx and updatedirstate:
+        repo.dirstate.beginparentchange()
+        repo.dirstate.setparents(ctx.node())
+        repo.dirstate.endparentchange()
+    return ctx.node()
+
 def commitfuncfor(repo, src):
     """Build a commit function for the replacement of <src>
@@ -524,5 +550,6 @@ def commitfuncfor(repo, src):
             extra['histedit_source'] = src.hex()
             kwargs['extra'] = extra
-            return repo.commit(**kwargs)
+            newnode = repo.commit(**kwargs)
+            return _revive(repo, newnode)
     return commitfunc
 
diff --git a/tests/test-histedit-obsolete.t b/tests/test-histedit-obsolete.t
--- a/tests/test-histedit-obsolete.t
+++ b/tests/test-histedit-obsolete.t
@@ -552,5 +552,5 @@ Abort
 Re-run a similar histedit plan
 
-  $ hg histedit -r 'b449568bf7fc' --commands - << EOF
+  $ hg histedit --debug -r 'b449568bf7fc' --commands - << EOF | grep revive
   > pick b449568bf7fc 13 f
   > pick 7395e1ff83bd 15 h
@@ -560,4 +560,21 @@ Re-run a similar histedit plan
   > pick ee118ab9fa44 18 k
   > EOF
-  abort: 00changelog.i@4dc06258baa667440b8af3c849ddd9c10a4b0cb8: filtered node!
-  [255]
+  node 4dc06258baa6 was revived as 7bd549b16383 (revive=1)
+
+  $ hg log -G
+  @  27:563ef4a77b72 (secret) k
+  |
+  o  26:f371aa2c4158 (secret) j
+  |
+  o  25:5bfeafa73282 (secret) i
+  |
+  o  24:c53c6695c868 (draft) g
+  |
+  o  23:7bd549b16383 (draft) h
+  |
+  o  13:b449568bf7fc (draft) f
+  |
+  o  12:40db8afa467b (public) c
+  |
+  o  0:cb9a9f314b8b (public) a
+  
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to