hgext/strip.py
changeset 43076 2372284d9457
parent 42532 12243f15d53e
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    18     registrar,
    18     registrar,
    19     repair,
    19     repair,
    20     scmutil,
    20     scmutil,
    21     util,
    21     util,
    22 )
    22 )
       
    23 
    23 nullid = nodemod.nullid
    24 nullid = nodemod.nullid
    24 release = lockmod.release
    25 release = lockmod.release
    25 
    26 
    26 cmdtable = {}
    27 cmdtable = {}
    27 command = registrar.command(cmdtable)
    28 command = registrar.command(cmdtable)
    28 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    29 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    29 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    30 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    30 # be specifying the version(s) of Mercurial they are tested with, or
    31 # be specifying the version(s) of Mercurial they are tested with, or
    31 # leave the attribute unspecified.
    32 # leave the attribute unspecified.
    32 testedwith = 'ships-with-hg-core'
    33 testedwith = 'ships-with-hg-core'
       
    34 
    33 
    35 
    34 def checklocalchanges(repo, force=False):
    36 def checklocalchanges(repo, force=False):
    35     s = repo.status()
    37     s = repo.status()
    36     if not force:
    38     if not force:
    37         cmdutil.checkunfinished(repo)
    39         cmdutil.checkunfinished(repo)
    38         cmdutil.bailifchanged(repo)
    40         cmdutil.bailifchanged(repo)
    39     else:
    41     else:
    40         cmdutil.checkunfinished(repo, skipmerge=True)
    42         cmdutil.checkunfinished(repo, skipmerge=True)
    41     return s
    43     return s
    42 
    44 
       
    45 
    43 def _findupdatetarget(repo, nodes):
    46 def _findupdatetarget(repo, nodes):
    44     unode, p2 = repo.changelog.parents(nodes[0])
    47     unode, p2 = repo.changelog.parents(nodes[0])
    45     currentbranch = repo[None].branch()
    48     currentbranch = repo[None].branch()
    46 
    49 
    47     if (util.safehasattr(repo, 'mq') and p2 != nullid
    50     if (
    48         and p2 in [x.node for x in repo.mq.applied]):
    51         util.safehasattr(repo, 'mq')
       
    52         and p2 != nullid
       
    53         and p2 in [x.node for x in repo.mq.applied]
       
    54     ):
    49         unode = p2
    55         unode = p2
    50     elif currentbranch != repo[unode].branch():
    56     elif currentbranch != repo[unode].branch():
    51         pwdir = 'parents(wdir())'
    57         pwdir = 'parents(wdir())'
    52         revset = 'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))'
    58         revset = 'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))'
    53         branchtarget = repo.revs(revset, nodes, pwdir, pwdir, nodes, pwdir,
    59         branchtarget = repo.revs(
    54                                  currentbranch)
    60             revset, nodes, pwdir, pwdir, nodes, pwdir, currentbranch
       
    61         )
    55         if branchtarget:
    62         if branchtarget:
    56             cl = repo.changelog
    63             cl = repo.changelog
    57             unode = cl.node(branchtarget.first())
    64             unode = cl.node(branchtarget.first())
    58 
    65 
    59     return unode
    66     return unode
    60 
    67 
    61 def strip(ui, repo, revs, update=True, backup=True, force=None, bookmarks=None,
    68 
    62           soft=False):
    69 def strip(
       
    70     ui,
       
    71     repo,
       
    72     revs,
       
    73     update=True,
       
    74     backup=True,
       
    75     force=None,
       
    76     bookmarks=None,
       
    77     soft=False,
       
    78 ):
    63     with repo.wlock(), repo.lock():
    79     with repo.wlock(), repo.lock():
    64 
    80 
    65         if update:
    81         if update:
    66             checklocalchanges(repo, force=force)
    82             checklocalchanges(repo, force=force)
    67             urev = _findupdatetarget(repo, revs)
    83             urev = _findupdatetarget(repo, revs)
    80                     bookmarksmod.deactivate(repo)
    96                     bookmarksmod.deactivate(repo)
    81                 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks])
    97                 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks])
    82             for bookmark in sorted(bookmarks):
    98             for bookmark in sorted(bookmarks):
    83                 ui.write(_("bookmark '%s' deleted\n") % bookmark)
    99                 ui.write(_("bookmark '%s' deleted\n") % bookmark)
    84 
   100 
    85 @command("strip",
   101 
    86          [
   102 @command(
    87           ('r', 'rev', [], _('strip specified revision (optional, '
   103     "strip",
    88                                'can specify revisions without this '
   104     [
    89                                'option)'), _('REV')),
   105         (
    90           ('f', 'force', None, _('force removal of changesets, discard '
   106             'r',
    91                                  'uncommitted changes (no backup)')),
   107             'rev',
    92           ('', 'no-backup', None, _('do not save backup bundle')),
   108             [],
    93           ('', 'nobackup', None, _('do not save backup bundle '
   109             _(
    94                                    '(DEPRECATED)')),
   110                 'strip specified revision (optional, '
    95           ('n', '', None, _('ignored  (DEPRECATED)')),
   111                 'can specify revisions without this '
    96           ('k', 'keep', None, _("do not modify working directory during "
   112                 'option)'
    97                                 "strip")),
   113             ),
    98           ('B', 'bookmark', [], _("remove revs only reachable from given"
   114             _('REV'),
    99                                   " bookmark"), _('BOOKMARK')),
   115         ),
   100           ('', 'soft', None,
   116         (
   101           _("simply drop changesets from visible history (EXPERIMENTAL)")),
   117             'f',
   102          ],
   118             'force',
   103           _('hg strip [-k] [-f] [-B bookmark] [-r] REV...'),
   119             None,
   104           helpcategory=command.CATEGORY_MAINTENANCE)
   120             _(
       
   121                 'force removal of changesets, discard '
       
   122                 'uncommitted changes (no backup)'
       
   123             ),
       
   124         ),
       
   125         ('', 'no-backup', None, _('do not save backup bundle')),
       
   126         ('', 'nobackup', None, _('do not save backup bundle ' '(DEPRECATED)')),
       
   127         ('n', '', None, _('ignored  (DEPRECATED)')),
       
   128         (
       
   129             'k',
       
   130             'keep',
       
   131             None,
       
   132             _("do not modify working directory during " "strip"),
       
   133         ),
       
   134         (
       
   135             'B',
       
   136             'bookmark',
       
   137             [],
       
   138             _("remove revs only reachable from given" " bookmark"),
       
   139             _('BOOKMARK'),
       
   140         ),
       
   141         (
       
   142             '',
       
   143             'soft',
       
   144             None,
       
   145             _("simply drop changesets from visible history (EXPERIMENTAL)"),
       
   146         ),
       
   147     ],
       
   148     _('hg strip [-k] [-f] [-B bookmark] [-r] REV...'),
       
   149     helpcategory=command.CATEGORY_MAINTENANCE,
       
   150 )
   105 def stripcmd(ui, repo, *revs, **opts):
   151 def stripcmd(ui, repo, *revs, **opts):
   106     """strip changesets and all their descendants from the repository
   152     """strip changesets and all their descendants from the repository
   107 
   153 
   108     The strip command removes the specified changesets and all their
   154     The strip command removes the specified changesets and all their
   109     descendants. If the working directory has uncommitted changes, the
   155     descendants. If the working directory has uncommitted changes, the
   143     with repo.wlock():
   189     with repo.wlock():
   144         bookmarks = set(opts.get('bookmark'))
   190         bookmarks = set(opts.get('bookmark'))
   145         if bookmarks:
   191         if bookmarks:
   146             repomarks = repo._bookmarks
   192             repomarks = repo._bookmarks
   147             if not bookmarks.issubset(repomarks):
   193             if not bookmarks.issubset(repomarks):
   148                 raise error.Abort(_("bookmark '%s' not found") %
   194                 raise error.Abort(
   149                     ','.join(sorted(bookmarks - set(repomarks.keys()))))
   195                     _("bookmark '%s' not found")
       
   196                     % ','.join(sorted(bookmarks - set(repomarks.keys())))
       
   197                 )
   150 
   198 
   151             # If the requested bookmark is not the only one pointing to a
   199             # If the requested bookmark is not the only one pointing to a
   152             # a revision we have to only delete the bookmark and not strip
   200             # a revision we have to only delete the bookmark and not strip
   153             # anything. revsets cannot detect that case.
   201             # anything. revsets cannot detect that case.
   154             nodetobookmarks = {}
   202             nodetobookmarks = {}
   172         strippedrevs = revs.union(descendants)
   220         strippedrevs = revs.union(descendants)
   173         roots = revs.difference(descendants)
   221         roots = revs.difference(descendants)
   174 
   222 
   175         # if one of the wdir parent is stripped we'll need
   223         # if one of the wdir parent is stripped we'll need
   176         # to update away to an earlier revision
   224         # to update away to an earlier revision
   177         update = any(p != nullid and cl.rev(p) in strippedrevs
   225         update = any(
   178                      for p in repo.dirstate.parents())
   226             p != nullid and cl.rev(p) in strippedrevs
       
   227             for p in repo.dirstate.parents()
       
   228         )
   179 
   229 
   180         rootnodes = set(cl.node(r) for r in roots)
   230         rootnodes = set(cl.node(r) for r in roots)
   181 
   231 
   182         q = getattr(repo, 'mq', None)
   232         q = getattr(repo, 'mq', None)
   183         if q is not None and q.applied:
   233         if q is not None and q.applied:
   220             # clear resolve state
   270             # clear resolve state
   221             merge.mergestate.clean(repo, repo['.'].node())
   271             merge.mergestate.clean(repo, repo['.'].node())
   222 
   272 
   223             update = False
   273             update = False
   224 
   274 
   225 
   275         strip(
   226         strip(ui, repo, revs, backup=backup, update=update,
   276             ui,
   227               force=opts.get('force'), bookmarks=bookmarks,
   277             repo,
   228               soft=opts['soft'])
   278             revs,
       
   279             backup=backup,
       
   280             update=update,
       
   281             force=opts.get('force'),
       
   282             bookmarks=bookmarks,
       
   283             soft=opts['soft'],
       
   284         )
   229 
   285 
   230     return 0
   286     return 0