Commits

Patrick Mézard  committed 24943df

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.

  • Participants
  • Parent commits 1c21865
  • Branches default

Comments (0)

Files changed (2)

File hgext/evolve.py

 #############################
 
 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()
 
         if commitopts.get('edit'):
             new._text = cmdutil.commitforceeditor(repo, new, [])
+        revcount = len(repo)
         newid = repo.commitctx(new)
         new = repo[newid]
+        created = len(repo) != revcount
+        if created:
+            # update the bookmark
+            if bm:
+                repo._bookmarks[bm] = newid
+                bookmarks.write(repo)
 
-        # 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"""
             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
             # 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:

File tests/test-amend.t

   $ echo "obsolete=$(echo $(dirname $TESTDIR))/hgext/obsolete.py" >> $HGRCPATH
   $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
 
+  $ glog() {
+  >   hg glog --template '{rev}@{branch}({phase}) {desc|firstline}\n' "$@"
+  > }
+
   $ hg init repo
   $ cd repo
   $ echo a > a
   $ hg branches
   foo                            2:a34b93d251e4
   default                        0:07f494440405 (inactive)
-  $ hg glog --template '{rev}@{branch} {desc|firstline}\n'
-  @  2@foo adda
+  $ glog
+  @  2@foo(draft) adda
+  
+Test no-op
+
+  $ hg amend
+  abort: no updates found
+  [255]
+  $ glog
+  @  2@foo(draft) adda
   
 
+Test forcing the message to the same value, no intermediate revision.
+
+  $ hg amend -m 'adda'
+  abort: no updates found
+  [255]
+  $ glog
+  @  2@foo(draft) adda
+  
+
+Test collapsing into an existing revision, no intermediate revision.
+
+  $ echo a >> a
+  $ hg ci -m changea
+  $ echo a > a
+  $ hg ci -m reseta
+  $ hg amend --change 2
+  abort: no updates found
+  [255]
+  $ hg phase 2
+  2: draft
+  $ glog
+  @  4@foo(draft) reseta
+  |
+  o  3@foo(draft) changea
+  |
+  o  2@foo(draft) adda
+  
+
+Test collapsing into an existing rev, with an intermediate revision.
+
+  $ hg branch --force default
+  marked working directory as branch default
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg ci -m resetbranch
+  created new head
+  $ hg branch --force foo
+  marked working directory as branch foo
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg amend --change 2
+  abort: no updates found
+  [255]
+  $ glog
+  @  6@foo(secret) amends a34b93d251e49c93d5685ebacad785c73a7e8605
+  |
+  o  5@default(draft) resetbranch
+  |
+  o  4@foo(draft) reseta
+  |
+  o  3@foo(draft) changea
+  |
+  o  2@foo(draft) adda
+