hgext/strip.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43089 c59eb1560c44
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
    28 command = registrar.command(cmdtable)
    28 command = registrar.command(cmdtable)
    29 # 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
    30 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    30 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    31 # 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
    32 # leave the attribute unspecified.
    32 # leave the attribute unspecified.
    33 testedwith = 'ships-with-hg-core'
    33 testedwith = b'ships-with-hg-core'
    34 
    34 
    35 
    35 
    36 def checklocalchanges(repo, force=False):
    36 def checklocalchanges(repo, force=False):
    37     s = repo.status()
    37     s = repo.status()
    38     if not force:
    38     if not force:
    46 def _findupdatetarget(repo, nodes):
    46 def _findupdatetarget(repo, nodes):
    47     unode, p2 = repo.changelog.parents(nodes[0])
    47     unode, p2 = repo.changelog.parents(nodes[0])
    48     currentbranch = repo[None].branch()
    48     currentbranch = repo[None].branch()
    49 
    49 
    50     if (
    50     if (
    51         util.safehasattr(repo, 'mq')
    51         util.safehasattr(repo, b'mq')
    52         and p2 != nullid
    52         and p2 != nullid
    53         and p2 in [x.node for x in repo.mq.applied]
    53         and p2 in [x.node for x in repo.mq.applied]
    54     ):
    54     ):
    55         unode = p2
    55         unode = p2
    56     elif currentbranch != repo[unode].branch():
    56     elif currentbranch != repo[unode].branch():
    57         pwdir = 'parents(wdir())'
    57         pwdir = b'parents(wdir())'
    58         revset = 'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))'
    58         revset = b'max(((parents(%ln::%r) + %r) - %ln::%r) and branch(%s))'
    59         branchtarget = repo.revs(
    59         branchtarget = repo.revs(
    60             revset, nodes, pwdir, pwdir, nodes, pwdir, currentbranch
    60             revset, nodes, pwdir, pwdir, nodes, pwdir, currentbranch
    61         )
    61         )
    62         if branchtarget:
    62         if branchtarget:
    63             cl = repo.changelog
    63             cl = repo.changelog
    89         else:
    89         else:
    90             repair.strip(ui, repo, revs, backup)
    90             repair.strip(ui, repo, revs, backup)
    91 
    91 
    92         repomarks = repo._bookmarks
    92         repomarks = repo._bookmarks
    93         if bookmarks:
    93         if bookmarks:
    94             with repo.transaction('strip') as tr:
    94             with repo.transaction(b'strip') as tr:
    95                 if repo._activebookmark in bookmarks:
    95                 if repo._activebookmark in bookmarks:
    96                     bookmarksmod.deactivate(repo)
    96                     bookmarksmod.deactivate(repo)
    97                 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks])
    97                 repomarks.applychanges(repo, tr, [(b, None) for b in bookmarks])
    98             for bookmark in sorted(bookmarks):
    98             for bookmark in sorted(bookmarks):
    99                 ui.write(_("bookmark '%s' deleted\n") % bookmark)
    99                 ui.write(_(b"bookmark '%s' deleted\n") % bookmark)
   100 
   100 
   101 
   101 
   102 @command(
   102 @command(
   103     "strip",
   103     b"strip",
   104     [
   104     [
   105         (
   105         (
   106             'r',
   106             b'r',
   107             'rev',
   107             b'rev',
   108             [],
   108             [],
   109             _(
   109             _(
   110                 'strip specified revision (optional, '
   110                 b'strip specified revision (optional, '
   111                 'can specify revisions without this '
   111                 b'can specify revisions without this '
   112                 'option)'
   112                 b'option)'
   113             ),
   113             ),
   114             _('REV'),
   114             _(b'REV'),
   115         ),
   115         ),
   116         (
   116         (
   117             'f',
   117             b'f',
   118             'force',
   118             b'force',
   119             None,
   119             None,
   120             _(
   120             _(
   121                 'force removal of changesets, discard '
   121                 b'force removal of changesets, discard '
   122                 'uncommitted changes (no backup)'
   122                 b'uncommitted changes (no backup)'
   123             ),
   123             ),
   124         ),
   124         ),
   125         ('', 'no-backup', None, _('do not save backup bundle')),
   125         (b'', b'no-backup', None, _(b'do not save backup bundle')),
   126         ('', 'nobackup', None, _('do not save backup bundle ' '(DEPRECATED)')),
   126         (
   127         ('n', '', None, _('ignored  (DEPRECATED)')),
   127             b'',
   128         (
   128             b'nobackup',
   129             'k',
   129             None,
   130             'keep',
   130             _(b'do not save backup bundle ' b'(DEPRECATED)'),
   131             None,
   131         ),
   132             _("do not modify working directory during " "strip"),
   132         (b'n', b'', None, _(b'ignored  (DEPRECATED)')),
   133         ),
   133         (
   134         (
   134             b'k',
   135             'B',
   135             b'keep',
   136             'bookmark',
   136             None,
       
   137             _(b"do not modify working directory during " b"strip"),
       
   138         ),
       
   139         (
       
   140             b'B',
       
   141             b'bookmark',
   137             [],
   142             [],
   138             _("remove revs only reachable from given" " bookmark"),
   143             _(b"remove revs only reachable from given" b" bookmark"),
   139             _('BOOKMARK'),
   144             _(b'BOOKMARK'),
   140         ),
   145         ),
   141         (
   146         (
   142             '',
   147             b'',
   143             'soft',
   148             b'soft',
   144             None,
   149             None,
   145             _("simply drop changesets from visible history (EXPERIMENTAL)"),
   150             _(b"simply drop changesets from visible history (EXPERIMENTAL)"),
   146         ),
   151         ),
   147     ],
   152     ],
   148     _('hg strip [-k] [-f] [-B bookmark] [-r] REV...'),
   153     _(b'hg strip [-k] [-f] [-B bookmark] [-r] REV...'),
   149     helpcategory=command.CATEGORY_MAINTENANCE,
   154     helpcategory=command.CATEGORY_MAINTENANCE,
   150 )
   155 )
   151 def stripcmd(ui, repo, *revs, **opts):
   156 def stripcmd(ui, repo, *revs, **opts):
   152     """strip changesets and all their descendants from the repository
   157     """strip changesets and all their descendants from the repository
   153 
   158 
   177 
   182 
   178     Return 0 on success.
   183     Return 0 on success.
   179     """
   184     """
   180     opts = pycompat.byteskwargs(opts)
   185     opts = pycompat.byteskwargs(opts)
   181     backup = True
   186     backup = True
   182     if opts.get('no_backup') or opts.get('nobackup'):
   187     if opts.get(b'no_backup') or opts.get(b'nobackup'):
   183         backup = False
   188         backup = False
   184 
   189 
   185     cl = repo.changelog
   190     cl = repo.changelog
   186     revs = list(revs) + opts.get('rev')
   191     revs = list(revs) + opts.get(b'rev')
   187     revs = set(scmutil.revrange(repo, revs))
   192     revs = set(scmutil.revrange(repo, revs))
   188 
   193 
   189     with repo.wlock():
   194     with repo.wlock():
   190         bookmarks = set(opts.get('bookmark'))
   195         bookmarks = set(opts.get(b'bookmark'))
   191         if bookmarks:
   196         if bookmarks:
   192             repomarks = repo._bookmarks
   197             repomarks = repo._bookmarks
   193             if not bookmarks.issubset(repomarks):
   198             if not bookmarks.issubset(repomarks):
   194                 raise error.Abort(
   199                 raise error.Abort(
   195                     _("bookmark '%s' not found")
   200                     _(b"bookmark '%s' not found")
   196                     % ','.join(sorted(bookmarks - set(repomarks.keys())))
   201                     % b','.join(sorted(bookmarks - set(repomarks.keys())))
   197                 )
   202                 )
   198 
   203 
   199             # If the requested bookmark is not the only one pointing to a
   204             # If the requested bookmark is not the only one pointing to a
   200             # a revision we have to only delete the bookmark and not strip
   205             # a revision we have to only delete the bookmark and not strip
   201             # anything. revsets cannot detect that case.
   206             # anything. revsets cannot detect that case.
   205             for marks in nodetobookmarks.values():
   210             for marks in nodetobookmarks.values():
   206                 if bookmarks.issuperset(marks):
   211                 if bookmarks.issuperset(marks):
   207                     rsrevs = scmutil.bookmarkrevs(repo, marks[0])
   212                     rsrevs = scmutil.bookmarkrevs(repo, marks[0])
   208                     revs.update(set(rsrevs))
   213                     revs.update(set(rsrevs))
   209             if not revs:
   214             if not revs:
   210                 with repo.lock(), repo.transaction('bookmark') as tr:
   215                 with repo.lock(), repo.transaction(b'bookmark') as tr:
   211                     bmchanges = [(b, None) for b in bookmarks]
   216                     bmchanges = [(b, None) for b in bookmarks]
   212                     repomarks.applychanges(repo, tr, bmchanges)
   217                     repomarks.applychanges(repo, tr, bmchanges)
   213                 for bookmark in sorted(bookmarks):
   218                 for bookmark in sorted(bookmarks):
   214                     ui.write(_("bookmark '%s' deleted\n") % bookmark)
   219                     ui.write(_(b"bookmark '%s' deleted\n") % bookmark)
   215 
   220 
   216         if not revs:
   221         if not revs:
   217             raise error.Abort(_('empty revision set'))
   222             raise error.Abort(_(b'empty revision set'))
   218 
   223 
   219         descendants = set(cl.descendants(revs))
   224         descendants = set(cl.descendants(revs))
   220         strippedrevs = revs.union(descendants)
   225         strippedrevs = revs.union(descendants)
   221         roots = revs.difference(descendants)
   226         roots = revs.difference(descendants)
   222 
   227 
   231 
   236 
   232         q = getattr(repo, 'mq', None)
   237         q = getattr(repo, 'mq', None)
   233         if q is not None and q.applied:
   238         if q is not None and q.applied:
   234             # refresh queue state if we're about to strip
   239             # refresh queue state if we're about to strip
   235             # applied patches
   240             # applied patches
   236             if cl.rev(repo.lookup('qtip')) in strippedrevs:
   241             if cl.rev(repo.lookup(b'qtip')) in strippedrevs:
   237                 q.applieddirty = True
   242                 q.applieddirty = True
   238                 start = 0
   243                 start = 0
   239                 end = len(q.applied)
   244                 end = len(q.applied)
   240                 for i, statusentry in enumerate(q.applied):
   245                 for i, statusentry in enumerate(q.applied):
   241                     if statusentry.node in rootnodes:
   246                     if statusentry.node in rootnodes:
   245                         break
   250                         break
   246                 del q.applied[start:end]
   251                 del q.applied[start:end]
   247                 q.savedirty()
   252                 q.savedirty()
   248 
   253 
   249         revs = sorted(rootnodes)
   254         revs = sorted(rootnodes)
   250         if update and opts.get('keep'):
   255         if update and opts.get(b'keep'):
   251             urev = _findupdatetarget(repo, revs)
   256             urev = _findupdatetarget(repo, revs)
   252             uctx = repo[urev]
   257             uctx = repo[urev]
   253 
   258 
   254             # only reset the dirstate for files that would actually change
   259             # only reset the dirstate for files that would actually change
   255             # between the working context and uctx
   260             # between the working context and uctx
   259                 # blindly reset the files, regardless of what actually changed
   264                 # blindly reset the files, regardless of what actually changed
   260                 changedfiles.extend(repo[rev].files())
   265                 changedfiles.extend(repo[rev].files())
   261 
   266 
   262             # reset files that only changed in the dirstate too
   267             # reset files that only changed in the dirstate too
   263             dirstate = repo.dirstate
   268             dirstate = repo.dirstate
   264             dirchanges = [f for f in dirstate if dirstate[f] != 'n']
   269             dirchanges = [f for f in dirstate if dirstate[f] != b'n']
   265             changedfiles.extend(dirchanges)
   270             changedfiles.extend(dirchanges)
   266 
   271 
   267             repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles)
   272             repo.dirstate.rebuild(urev, uctx.manifest(), changedfiles)
   268             repo.dirstate.write(repo.currenttransaction())
   273             repo.dirstate.write(repo.currenttransaction())
   269 
   274 
   270             # clear resolve state
   275             # clear resolve state
   271             merge.mergestate.clean(repo, repo['.'].node())
   276             merge.mergestate.clean(repo, repo[b'.'].node())
   272 
   277 
   273             update = False
   278             update = False
   274 
   279 
   275         strip(
   280         strip(
   276             ui,
   281             ui,
   277             repo,
   282             repo,
   278             revs,
   283             revs,
   279             backup=backup,
   284             backup=backup,
   280             update=update,
   285             update=update,
   281             force=opts.get('force'),
   286             force=opts.get(b'force'),
   282             bookmarks=bookmarks,
   287             bookmarks=bookmarks,
   283             soft=opts['soft'],
   288             soft=opts[b'soft'],
   284         )
   289         )
   285 
   290 
   286     return 0
   291     return 0