diff hgext/evolve.py @ 265:24943df310d4

amend: do not traceback on no-ops If rewrite() generated changeset happened to be an existing one, the call would traceback when trying to obsolete the changeset with itself. Instead, leave gracefully, marking any intermediate changeset extinct.
author Patrick Mezard <patrick@mezard.eu>
date Tue, 12 Jun 2012 13:28:39 +0200
parents 1c21865bf8ba
children 2da5af3dadeb
line wrap: on
line diff
--- a/hgext/evolve.py	Tue Jun 12 11:53:02 2012 +0200
+++ b/hgext/evolve.py	Tue Jun 12 13:28:39 2012 +0200
@@ -57,6 +57,11 @@
 #############################
 
 def rewrite(repo, old, updates, head, newbases, commitopts):
+    """Return (nodeid, created) where nodeid is the identifier of the
+    changeset generated by the rewrite process, and created is True if
+    nodeid was actually created. If created is False, nodeid
+    references a changeset existing before the rewrite call.
+    """
     if len(old.parents()) > 1: #XXX remove this unecessary limitation.
         raise error.Abort(_('cannot amend merge changesets'))
     base = old.p1()
@@ -126,29 +131,35 @@
 
         if commitopts.get('edit'):
             new._text = cmdutil.commitforceeditor(repo, new, [])
+        revcount = len(repo)
         newid = repo.commitctx(new)
         new = repo[newid]
-
-        # update the bookmark
-        if bm:
-            repo._bookmarks[bm] = newid
-            bookmarks.write(repo)
+        created = len(repo) != revcount
+        if created:
+            # update the bookmark
+            if bm:
+                repo._bookmarks[bm] = newid
+                bookmarks.write(repo)
 
-        # add evolution metadata
-        repo.addobsolete(new.node(), old.node())
-        for u in updates:
-            repo.addobsolete(u.node(), old.node())
-            repo.addobsolete(new.node(), u.node())
-        oldbookmarks = repo.nodebookmarks(old.node())
-        for book in oldbookmarks:
-            repo._bookmarks[book] = new.node()
-        if oldbookmarks:
-            bookmarks.write(repo)
-
+            # add evolution metadata
+            repo.addobsolete(new.node(), old.node())
+            for u in updates:
+                repo.addobsolete(u.node(), old.node())
+                repo.addobsolete(new.node(), u.node())
+            oldbookmarks = repo.nodebookmarks(old.node())
+            for book in oldbookmarks:
+                repo._bookmarks[book] = new.node()
+            if oldbookmarks:
+                bookmarks.write(repo)
+        else:
+            # newid is an existing revision. It could make sense to
+            # replace revisions with existing ones but probably not by
+            # default.
+            pass
     finally:
         wlock.release()
 
-    return newid
+    return newid, created
 
 def relocate(repo, orig, dest):
     """rewrite <rev> on dest"""
@@ -407,7 +418,11 @@
             def commitfunc(ui, repo, message, match, opts):
                 return repo.commit(message, opts.get('user'), opts.get('date'), match,
                                    editor=e)
-            cmdutil.commit(ui, repo, commitfunc, pats, ciopts)
+            revcount = len(repo)
+            tempid = cmdutil.commit(ui, repo, commitfunc, pats, ciopts)
+            if len(repo) == revcount:
+                # No revision created
+                tempid = None
 
             # find all changesets to be considered updates
             cl = repo.changelog
@@ -429,13 +444,20 @@
             # perform amend
             if opts.get('edit'):
                 opts['force_editor'] = True
-            newid = rewrite(repo, old, updates, head,
-                            [old.p1().node(), old.p2().node()], opts)
-
-            # reroute the working copy parent to the new changeset
-            phases.retractboundary(repo, oldphase, [newid])
-            repo.dirstate.setparents(newid, node.nullid)
-
+            newid, created = rewrite(repo, old, updates, head,
+                                     [old.p1().node(), old.p2().node()], opts)
+            if created:
+                # reroute the working copy parent to the new changeset
+                phases.retractboundary(repo, oldphase, [newid])
+                repo.dirstate.setparents(newid, node.nullid)
+            else:
+                # rewrite() recreated an existing revision, discard
+                # the intermediate revision if any. No need to update
+                # phases or parents.
+                if tempid is not None:
+                    repo.addobsolete(node.nullid, tempid)
+                # XXX: need another message in collapse case.
+                raise error.Abort(_('no updates found'))
         finally:
             wlock.release()
     finally: