1. Luke Plant
  2. histedit

Commits

Augie Fackler  committed 7c692b2

Initial version that does nothing but starts the process.

  • Participants
  • Branches default

Comments (0)

Files changed (1)

File __init__.py

View file
+"""Interactive history editing.
+
+Inspired by git rebase --interactive.
+"""
+
+from mercurial import cmdutil
+from mercurial import node
+from mercurial import util
+
+# almost entirely stolen from the git-rebase--interactive.sh source
+editcomment = """
+
+# Edit history between %s and %s
+#
+# Commands:
+#  p, pick = use commit
+#  e, edit = use commit, but stop for amending
+#  s, squash = use commit, but fold into previous commit
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+# However, if you remove everything, the rebase will be aborted.
+#
+"""
+
+def between(repo, old, new):
+    revs = [old, ]
+    current = old
+    while current != new:
+        ctx = repo[current]
+        if len(ctx.children()) != 1:
+            raise util.Abort('cannot edit history that would orphan nodes')
+        if len(ctx.parents()) != 1 and ctx.parents()[1] != node.nullid:
+            raise util.Abort("can't edit history with merges")
+        current = ctx.children()[0].node()
+        revs.append(current)
+    if len(repo[current].children()):
+        raise util.Abort('cannot edit history that would orphan nodes')
+    return revs
+
+
+def pick(ui, repo, ctx, ha):
+    oldctx = repo[ha]
+    if oldctx.parents()[0] == ctx:
+        ui.debug('node %s unchanged\n' % ha)
+        return oldctx
+    assert False
+
+def edit(ui, repo, ctx, ha):
+    assert False
+
+def squash(ui, repo, ctx, ha):
+    assert False
+
+actiontable = {'p': pick,
+               'pick': pick,
+               'e': edit,
+               'edit': edit,
+               's': squash,
+               'squash': squash,
+               }
+def histedit(ui, repo, parent, **opts):
+    """<parent>
+    """
+    tip, empty = repo.dirstate.parents()
+
+    cmdutil.bail_if_changed(repo)
+
+    revs = between(repo, parent, tip)
+
+    rules = '\n'.join([('pick %s %s' % (c.hex()[:12],
+                                     c.description().splitlines()[0]))[:80]
+                       for c in (repo[r] for r in revs)])
+
+    rules += editcomment % (node.hex(parent)[:12], node.hex(tip)[:12], )
+
+    rules = ui.edit(rules, ui.username())
+
+    parentctx = repo[parent].parents()[0]
+    first = True
+    for r in rules.splitlines():
+        r = r.strip()
+        if not r or r[0] == '#':
+            continue
+        action, ha, junk = r.split(' ', 2)
+        if action not in actiontable:
+            raise util.Abort('unknown action "%s"' % action)
+        if first and action == 's' or action == 'squash':
+            raise util.Abort('cannot (s)quash as first action')
+        else:
+            first = False
+        parentctx = actiontable[action](ui, repo, parentctx, ha)
+
+cmdtable = {
+    "histedit":
+        (histedit,
+         [],
+         __doc__,
+         ),
+}