# drop - allows the user to drop changeset from the middle of a stack # # Copyright 2017 Facebook, Inc. # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. """drop specified changeset from the stack This command drops specified changeset from the stack. For example, given changeset stack o C | o B | o A | o master execution of `hg drop -r B` command will result in the following stack o C | o A | o master If the changeset to drop has multiple children branching off of it, all of them (including their descendants) will be rebased onto the parent changeset. Dropping changeset which are a result of a merge (have two parent changesets) is not supported. Root changesets cannot be dropped. """ from mercurial import ( cmdutil, error, extensions, phases, registrar, scmutil, ) from mercurial.i18n import _ cmdtable = {} command = registrar.command(cmdtable) testedwith = 'ships-with-fb-hgext' def _checkextension(name, ui): try: return extensions.find(name) except KeyError: ui.warn(_('extension %s not found\n') % name) return None def _showrev(ui, repo, revid): """pretty print the changeset to drop""" showopts = { 'template': 'Dropping changeset ' '{shortest(node, 6)}{if(bookmarks, " ({bookmarks})")}' ': {desc|firstline}\n' } displayer = cmdutil.show_changeset(ui, repo, showopts) displayer.show(repo[revid]) def extsetup(ui): global rebasemod rebasemod = _checkextension('rebase', ui) @command('drop', [('r', 'rev', [], _("revision to drop"))], _('hg drop [OPTION] [REV]')) def drop(ui, repo, *revs, **opts): """drop changeset from stack """ if not rebasemod: raise error.Abort(_('required extensions not detected')) cmdutil.checkunfinished(repo) cmdutil.bailifchanged(repo) revs = scmutil.revrange(repo, list(revs) + opts.get('rev')) if not revs: raise error.Abort(_('no revision to drop was provided')) # currently drop supports dropping only one changeset at a time if len(revs) > 1: raise error.Abort(_('only one revision can be dropped at a time')) revid = revs.first() changectx = repo[revid] if changectx.phase() == phases.public: raise error.Abort(_('public changeset which landed cannot be dropped')) parents = repo.revs('parents(%s)', revid) if len(parents) > 1: raise error.Abort(_('merge changeset cannot be dropped')) elif len(parents) == 0: raise error.Abort(_('root changeset cannot be dropped')) _showrev(ui, repo, revid) descendants = repo.revs('(%d::) - %d', revid, revid) parent = parents.first() with repo.wlock(): with repo.lock(): with repo.transaction('drop'): if len(descendants) > 0: try: rebasemod.rebase(ui, repo, dest=str(parent), rev=descendants) except error.InterventionRequired: ui.warn(_("conflict occurred during drop: " + "please fix it by running " + "'hg rebase --continue', " + "and then re-run 'hg drop'\n")) raise scmutil.cleanupnodes(repo, [changectx.node()], 'drop')