hgext/histedit.py
changeset 46113 59fa3890d40a
parent 46104 6f8a94bbfba1
child 46394 8477c91b5e8e
equal deleted inserted replaced
46112:d6afa9c149c3 46113:59fa3890d40a
   207 from mercurial.i18n import _
   207 from mercurial.i18n import _
   208 from mercurial.pycompat import (
   208 from mercurial.pycompat import (
   209     getattr,
   209     getattr,
   210     open,
   210     open,
   211 )
   211 )
       
   212 from mercurial.node import (
       
   213     bin,
       
   214     hex,
       
   215     short,
       
   216 )
   212 from mercurial import (
   217 from mercurial import (
   213     bundle2,
   218     bundle2,
   214     cmdutil,
   219     cmdutil,
   215     context,
   220     context,
   216     copies,
   221     copies,
   223     hg,
   228     hg,
   224     logcmdutil,
   229     logcmdutil,
   225     merge as mergemod,
   230     merge as mergemod,
   226     mergestate as mergestatemod,
   231     mergestate as mergestatemod,
   227     mergeutil,
   232     mergeutil,
   228     node,
       
   229     obsolete,
   233     obsolete,
   230     pycompat,
   234     pycompat,
   231     registrar,
   235     registrar,
   232     repair,
   236     repair,
   233     rewriteutil,
   237     rewriteutil,
   402             with self.repo.vfs(b"histedit-state", b"w") as f:
   406             with self.repo.vfs(b"histedit-state", b"w") as f:
   403                 self._write(f)
   407                 self._write(f)
   404 
   408 
   405     def _write(self, fp):
   409     def _write(self, fp):
   406         fp.write(b'v1\n')
   410         fp.write(b'v1\n')
   407         fp.write(b'%s\n' % node.hex(self.parentctxnode))
   411         fp.write(b'%s\n' % hex(self.parentctxnode))
   408         fp.write(b'%s\n' % node.hex(self.topmost))
   412         fp.write(b'%s\n' % hex(self.topmost))
   409         fp.write(b'%s\n' % (b'True' if self.keep else b'False'))
   413         fp.write(b'%s\n' % (b'True' if self.keep else b'False'))
   410         fp.write(b'%d\n' % len(self.actions))
   414         fp.write(b'%d\n' % len(self.actions))
   411         for action in self.actions:
   415         for action in self.actions:
   412             fp.write(b'%s\n' % action.tostate())
   416             fp.write(b'%s\n' % action.tostate())
   413         fp.write(b'%d\n' % len(self.replacements))
   417         fp.write(b'%d\n' % len(self.replacements))
   414         for replacement in self.replacements:
   418         for replacement in self.replacements:
   415             fp.write(
   419             fp.write(
   416                 b'%s%s\n'
   420                 b'%s%s\n'
   417                 % (
   421                 % (
   418                     node.hex(replacement[0]),
   422                     hex(replacement[0]),
   419                     b''.join(node.hex(r) for r in replacement[1]),
   423                     b''.join(hex(r) for r in replacement[1]),
   420                 )
   424                 )
   421             )
   425             )
   422         backupfile = self.backupfile
   426         backupfile = self.backupfile
   423         if not backupfile:
   427         if not backupfile:
   424             backupfile = b''
   428             backupfile = b''
   430 
   434 
   431         index = 0
   435         index = 0
   432         lines[index]  # version number
   436         lines[index]  # version number
   433         index += 1
   437         index += 1
   434 
   438 
   435         parentctxnode = node.bin(lines[index])
   439         parentctxnode = bin(lines[index])
   436         index += 1
   440         index += 1
   437 
   441 
   438         topmost = node.bin(lines[index])
   442         topmost = bin(lines[index])
   439         index += 1
   443         index += 1
   440 
   444 
   441         keep = lines[index] == b'True'
   445         keep = lines[index] == b'True'
   442         index += 1
   446         index += 1
   443 
   447 
   456         replacements = []
   460         replacements = []
   457         replacementlen = int(lines[index])
   461         replacementlen = int(lines[index])
   458         index += 1
   462         index += 1
   459         for i in pycompat.xrange(replacementlen):
   463         for i in pycompat.xrange(replacementlen):
   460             replacement = lines[index]
   464             replacement = lines[index]
   461             original = node.bin(replacement[:40])
   465             original = bin(replacement[:40])
   462             succ = [
   466             succ = [
   463                 node.bin(replacement[i : i + 40])
   467                 bin(replacement[i : i + 40])
   464                 for i in range(40, len(replacement), 40)
   468                 for i in range(40, len(replacement), 40)
   465             ]
   469             ]
   466             replacements.append((original, succ))
   470             replacements.append((original, succ))
   467             index += 1
   471             index += 1
   468 
   472 
   492         """Parses the given rule, returning an instance of the histeditaction."""
   496         """Parses the given rule, returning an instance of the histeditaction."""
   493         ruleid = rule.strip().split(b' ', 1)[0]
   497         ruleid = rule.strip().split(b' ', 1)[0]
   494         # ruleid can be anything from rev numbers, hashes, "bookmarks" etc
   498         # ruleid can be anything from rev numbers, hashes, "bookmarks" etc
   495         # Check for validation of rule ids and get the rulehash
   499         # Check for validation of rule ids and get the rulehash
   496         try:
   500         try:
   497             rev = node.bin(ruleid)
   501             rev = bin(ruleid)
   498         except TypeError:
   502         except TypeError:
   499             try:
   503             try:
   500                 _ctx = scmutil.revsingle(state.repo, ruleid)
   504                 _ctx = scmutil.revsingle(state.repo, ruleid)
   501                 rulehash = _ctx.hex()
   505                 rulehash = _ctx.hex()
   502                 rev = node.bin(rulehash)
   506                 rev = bin(rulehash)
   503             except error.RepoLookupError:
   507             except error.RepoLookupError:
   504                 raise error.ParseError(_(b"invalid changeset %s") % ruleid)
   508                 raise error.ParseError(_(b"invalid changeset %s") % ruleid)
   505         return cls(state, rev)
   509         return cls(state, rev)
   506 
   510 
   507     def verify(self, prev, expected, seen):
   511     def verify(self, prev, expected, seen):
   508         """ Verifies semantic correctness of the rule"""
   512         """ Verifies semantic correctness of the rule"""
   509         repo = self.repo
   513         repo = self.repo
   510         ha = node.hex(self.node)
   514         ha = hex(self.node)
   511         self.node = scmutil.resolvehexnodeidprefix(repo, ha)
   515         self.node = scmutil.resolvehexnodeidprefix(repo, ha)
   512         if self.node is None:
   516         if self.node is None:
   513             raise error.ParseError(_(b'unknown changeset %s listed') % ha[:12])
   517             raise error.ParseError(_(b'unknown changeset %s listed') % ha[:12])
   514         self._verifynodeconstraints(prev, expected, seen)
   518         self._verifynodeconstraints(prev, expected, seen)
   515 
   519 
   516     def _verifynodeconstraints(self, prev, expected, seen):
   520     def _verifynodeconstraints(self, prev, expected, seen):
   517         # by default command need a node in the edited list
   521         # by default command need a node in the edited list
   518         if self.node not in expected:
   522         if self.node not in expected:
   519             raise error.ParseError(
   523             raise error.ParseError(
   520                 _(b'%s "%s" changeset was not a candidate')
   524                 _(b'%s "%s" changeset was not a candidate')
   521                 % (self.verb, node.short(self.node)),
   525                 % (self.verb, short(self.node)),
   522                 hint=_(b'only use listed changesets'),
   526                 hint=_(b'only use listed changesets'),
   523             )
   527             )
   524         # and only one command per node
   528         # and only one command per node
   525         if self.node in seen:
   529         if self.node in seen:
   526             raise error.ParseError(
   530             raise error.ParseError(
   527                 _(b'duplicated command for changeset %s')
   531                 _(b'duplicated command for changeset %s') % short(self.node)
   528                 % node.short(self.node)
       
   529             )
   532             )
   530 
   533 
   531     def torule(self):
   534     def torule(self):
   532         """build a histedit rule line for an action
   535         """build a histedit rule line for an action
   533 
   536 
   555 
   558 
   556     def tostate(self):
   559     def tostate(self):
   557         """Print an action in format used by histedit state files
   560         """Print an action in format used by histedit state files
   558         (the first line is a verb, the remainder is the second)
   561         (the first line is a verb, the remainder is the second)
   559         """
   562         """
   560         return b"%s\n%s" % (self.verb, node.hex(self.node))
   563         return b"%s\n%s" % (self.verb, hex(self.node))
   561 
   564 
   562     def run(self):
   565     def run(self):
   563         """Runs the action. The default behavior is simply apply the action's
   566         """Runs the action. The default behavior is simply apply the action's
   564         rulectx onto the current parentctx."""
   567         rulectx onto the current parentctx."""
   565         self.applychange()
   568         self.applychange()
   576         repo.ui.popbuffer()
   579         repo.ui.popbuffer()
   577         stats = applychanges(repo.ui, repo, rulectx, {})
   580         stats = applychanges(repo.ui, repo, rulectx, {})
   578         repo.dirstate.setbranch(rulectx.branch())
   581         repo.dirstate.setbranch(rulectx.branch())
   579         if stats.unresolvedcount:
   582         if stats.unresolvedcount:
   580             raise error.InterventionRequired(
   583             raise error.InterventionRequired(
   581                 _(b'Fix up the change (%s %s)')
   584                 _(b'Fix up the change (%s %s)') % (self.verb, short(self.node)),
   582                 % (self.verb, node.short(self.node)),
       
   583                 hint=_(b'hg histedit --continue to resume'),
   585                 hint=_(b'hg histedit --continue to resume'),
   584             )
   586             )
   585 
   587 
   586     def continuedirty(self):
   588     def continuedirty(self):
   587         """Continues the action when changes have been applied to the working
   589         """Continues the action when changes have been applied to the working
   612         behavior is to accept the current commit as the new version of the
   614         behavior is to accept the current commit as the new version of the
   613         rulectx."""
   615         rulectx."""
   614         ctx = self.repo[b'.']
   616         ctx = self.repo[b'.']
   615         if ctx.node() == self.state.parentctxnode:
   617         if ctx.node() == self.state.parentctxnode:
   616             self.repo.ui.warn(
   618             self.repo.ui.warn(
   617                 _(b'%s: skipping changeset (no changes)\n')
   619                 _(b'%s: skipping changeset (no changes)\n') % short(self.node)
   618                 % node.short(self.node)
       
   619             )
   620             )
   620             return ctx, [(self.node, tuple())]
   621             return ctx, [(self.node, tuple())]
   621         if ctx.node() == self.node:
   622         if ctx.node() == self.node:
   622             # Nothing changed
   623             # Nothing changed
   623             return ctx, []
   624             return ctx, []
   682     if not ctxs:
   683     if not ctxs:
   683         return None
   684         return None
   684     for c in ctxs:
   685     for c in ctxs:
   685         if not c.mutable():
   686         if not c.mutable():
   686             raise error.ParseError(
   687             raise error.ParseError(
   687                 _(b"cannot fold into public change %s") % node.short(c.node())
   688                 _(b"cannot fold into public change %s") % short(c.node())
   688             )
   689             )
   689     base = firstctx.p1()
   690     base = firstctx.p1()
   690 
   691 
   691     # commit a new version of the old changeset, including the update
   692     # commit a new version of the old changeset, including the update
   692     # collect all files which might be affected
   693     # collect all files which might be affected
   784 @action([b'pick', b'p'], _(b'use commit'), priority=True)
   785 @action([b'pick', b'p'], _(b'use commit'), priority=True)
   785 class pick(histeditaction):
   786 class pick(histeditaction):
   786     def run(self):
   787     def run(self):
   787         rulectx = self.repo[self.node]
   788         rulectx = self.repo[self.node]
   788         if rulectx.p1().node() == self.state.parentctxnode:
   789         if rulectx.p1().node() == self.state.parentctxnode:
   789             self.repo.ui.debug(b'node %s unchanged\n' % node.short(self.node))
   790             self.repo.ui.debug(b'node %s unchanged\n' % short(self.node))
   790             return rulectx, []
   791             return rulectx, []
   791 
   792 
   792         return super(pick, self).run()
   793         return super(pick, self).run()
   793 
   794 
   794 
   795 
   795 @action([b'edit', b'e'], _(b'use commit, but allow edits before making new commit'), priority=True)
   796 @action(
       
   797     [b'edit', b'e'],
       
   798     _(b'use commit, but allow edits before making new commit'),
       
   799     priority=True,
       
   800 )
   796 class edit(histeditaction):
   801 class edit(histeditaction):
   797     def run(self):
   802     def run(self):
   798         repo = self.repo
   803         repo = self.repo
   799         rulectx = repo[self.node]
   804         rulectx = repo[self.node]
   800         hg.update(repo, self.state.parentctxnode, quietempty=True)
   805         hg.update(repo, self.state.parentctxnode, quietempty=True)
   801         applychanges(repo.ui, repo, rulectx, {})
   806         applychanges(repo.ui, repo, rulectx, {})
   802         hint = _(b'to edit %s, `hg histedit --continue` after making changes')
   807         hint = _(b'to edit %s, `hg histedit --continue` after making changes')
   803         raise error.InterventionRequired(
   808         raise error.InterventionRequired(
   804             _(b'Editing (%s), commit as needed now to split the change')
   809             _(b'Editing (%s), commit as needed now to split the change')
   805             % node.short(self.node),
   810             % short(self.node),
   806             hint=hint % node.short(self.node),
   811             hint=hint % short(self.node),
   807         )
   812         )
   808 
   813 
   809     def commiteditor(self):
   814     def commiteditor(self):
   810         return cmdutil.getcommiteditor(edit=True, editform=b'histedit.edit')
   815         return cmdutil.getcommiteditor(edit=True, editform=b'histedit.edit')
   811 
   816 
   822             return
   827             return
   823         else:
   828         else:
   824             c = repo[prev.node]
   829             c = repo[prev.node]
   825         if not c.mutable():
   830         if not c.mutable():
   826             raise error.ParseError(
   831             raise error.ParseError(
   827                 _(b"cannot fold into public change %s") % node.short(c.node())
   832                 _(b"cannot fold into public change %s") % short(c.node())
   828             )
   833             )
   829 
   834 
   830     def continuedirty(self):
   835     def continuedirty(self):
   831         repo = self.repo
   836         repo = self.repo
   832         rulectx = repo[self.node]
   837         rulectx = repo[self.node]
   833 
   838 
   834         commit = commitfuncfor(repo, rulectx)
   839         commit = commitfuncfor(repo, rulectx)
   835         commit(
   840         commit(
   836             text=b'fold-temp-revision %s' % node.short(self.node),
   841             text=b'fold-temp-revision %s' % short(self.node),
   837             user=rulectx.user(),
   842             user=rulectx.user(),
   838             date=rulectx.date(),
   843             date=rulectx.date(),
   839             extra=rulectx.extra(),
   844             extra=rulectx.extra(),
   840         )
   845         )
   841 
   846 
   843         repo = self.repo
   848         repo = self.repo
   844         ctx = repo[b'.']
   849         ctx = repo[b'.']
   845         rulectx = repo[self.node]
   850         rulectx = repo[self.node]
   846         parentctxnode = self.state.parentctxnode
   851         parentctxnode = self.state.parentctxnode
   847         if ctx.node() == parentctxnode:
   852         if ctx.node() == parentctxnode:
   848             repo.ui.warn(_(b'%s: empty changeset\n') % node.short(self.node))
   853             repo.ui.warn(_(b'%s: empty changeset\n') % short(self.node))
   849             return ctx, [(self.node, (parentctxnode,))]
   854             return ctx, [(self.node, (parentctxnode,))]
   850 
   855 
   851         parentctx = repo[parentctxnode]
   856         parentctx = repo[parentctxnode]
   852         newcommits = {
   857         newcommits = {
   853             c.node()
   858             c.node()
   857             repo.ui.warn(
   862             repo.ui.warn(
   858                 _(
   863                 _(
   859                     b'%s: cannot fold - working copy is not a '
   864                     b'%s: cannot fold - working copy is not a '
   860                     b'descendant of previous commit %s\n'
   865                     b'descendant of previous commit %s\n'
   861                 )
   866                 )
   862                 % (node.short(self.node), node.short(parentctxnode))
   867                 % (short(self.node), short(parentctxnode))
   863             )
   868             )
   864             return ctx, [(self.node, (ctx.node(),))]
   869             return ctx, [(self.node, (ctx.node(),))]
   865 
   870 
   866         middlecommits = newcommits.copy()
   871         middlecommits = newcommits.copy()
   867         middlecommits.discard(ctx.node())
   872         middlecommits.discard(ctx.node())
   971     def _verifynodeconstraints(self, prev, expected, seen):
   976     def _verifynodeconstraints(self, prev, expected, seen):
   972         # base can only be use with a node not in the edited set
   977         # base can only be use with a node not in the edited set
   973         if self.node in expected:
   978         if self.node in expected:
   974             msg = _(b'%s "%s" changeset was an edited list candidate')
   979             msg = _(b'%s "%s" changeset was an edited list candidate')
   975             raise error.ParseError(
   980             raise error.ParseError(
   976                 msg % (self.verb, node.short(self.node)),
   981                 msg % (self.verb, short(self.node)),
   977                 hint=_(b'base must only use unlisted changesets'),
   982                 hint=_(b'base must only use unlisted changesets'),
   978             )
   983             )
   979 
   984 
   980 
   985 
   981 @action(
   986 @action(
  1715 
  1720 
  1716         topmost = repo.dirstate.p1()
  1721         topmost = repo.dirstate.p1()
  1717         revs = between(repo, root, topmost, keep)
  1722         revs = between(repo, root, topmost, keep)
  1718         if not revs:
  1723         if not revs:
  1719             raise error.Abort(
  1724             raise error.Abort(
  1720                 _(b'%s is not an ancestor of working directory')
  1725                 _(b'%s is not an ancestor of working directory') % short(root)
  1721                 % node.short(root)
       
  1722             )
  1726             )
  1723 
  1727 
  1724         ctxs = []
  1728         ctxs = []
  1725         for i, r in enumerate(revs):
  1729         for i, r in enumerate(revs):
  1726             ctxs.append(histeditrule(ui, repo[r], i))
  1730             ctxs.append(histeditrule(ui, repo[r], i))
  2069 
  2073 
  2070     mapping, tmpnodes, created, ntm = processreplacement(state)
  2074     mapping, tmpnodes, created, ntm = processreplacement(state)
  2071     if mapping:
  2075     if mapping:
  2072         for prec, succs in pycompat.iteritems(mapping):
  2076         for prec, succs in pycompat.iteritems(mapping):
  2073             if not succs:
  2077             if not succs:
  2074                 ui.debug(b'histedit: %s is dropped\n' % node.short(prec))
  2078                 ui.debug(b'histedit: %s is dropped\n' % short(prec))
  2075             else:
  2079             else:
  2076                 ui.debug(
  2080                 ui.debug(
  2077                     b'histedit: %s is replaced by %s\n'
  2081                     b'histedit: %s is replaced by %s\n'
  2078                     % (node.short(prec), node.short(succs[0]))
  2082                     % (short(prec), short(succs[0]))
  2079                 )
  2083                 )
  2080                 if len(succs) > 1:
  2084                 if len(succs) > 1:
  2081                     m = b'histedit:                            %s'
  2085                     m = b'histedit:                            %s'
  2082                     for n in succs[1:]:
  2086                     for n in succs[1:]:
  2083                         ui.debug(m % node.short(n))
  2087                         ui.debug(m % short(n))
  2084 
  2088 
  2085     if not state.keep:
  2089     if not state.keep:
  2086         if mapping:
  2090         if mapping:
  2087             movetopmostbookmarks(repo, state.topmost, ntm)
  2091             movetopmostbookmarks(repo, state.topmost, ntm)
  2088             # TODO update mq state
  2092             # TODO update mq state
  2123 
  2127 
  2124 def _aborthistedit(ui, repo, state, nobackup=False):
  2128 def _aborthistedit(ui, repo, state, nobackup=False):
  2125     try:
  2129     try:
  2126         state.read()
  2130         state.read()
  2127         __, leafs, tmpnodes, __ = processreplacement(state)
  2131         __, leafs, tmpnodes, __ = processreplacement(state)
  2128         ui.debug(b'restore wc to old parent %s\n' % node.short(state.topmost))
  2132         ui.debug(b'restore wc to old parent %s\n' % short(state.topmost))
  2129 
  2133 
  2130         # Recover our old commits if necessary
  2134         # Recover our old commits if necessary
  2131         if not state.topmost in repo and state.backupfile:
  2135         if not state.topmost in repo and state.backupfile:
  2132             backupfile = repo.vfs.join(state.backupfile)
  2136             backupfile = repo.vfs.join(state.backupfile)
  2133             f = hg.openpath(ui, backupfile)
  2137             f = hg.openpath(ui, backupfile)
  2177 
  2181 
  2178 def _edithisteditplan(ui, repo, state, rules):
  2182 def _edithisteditplan(ui, repo, state, rules):
  2179     state.read()
  2183     state.read()
  2180     if not rules:
  2184     if not rules:
  2181         comment = geteditcomment(
  2185         comment = geteditcomment(
  2182             ui, node.short(state.parentctxnode), node.short(state.topmost)
  2186             ui, short(state.parentctxnode), short(state.topmost)
  2183         )
  2187         )
  2184         rules = ruleeditor(repo, ui, state.actions, comment)
  2188         rules = ruleeditor(repo, ui, state.actions, comment)
  2185     else:
  2189     else:
  2186         rules = _readfile(ui, rules)
  2190         rules = _readfile(ui, rules)
  2187     actions = parserules(rules, state)
  2191     actions = parserules(rules, state)
  2218         root = rr[0].node()
  2222         root = rr[0].node()
  2219 
  2223 
  2220     revs = between(repo, root, topmost, state.keep)
  2224     revs = between(repo, root, topmost, state.keep)
  2221     if not revs:
  2225     if not revs:
  2222         raise error.Abort(
  2226         raise error.Abort(
  2223             _(b'%s is not an ancestor of working directory') % node.short(root)
  2227             _(b'%s is not an ancestor of working directory') % short(root)
  2224         )
  2228         )
  2225 
  2229 
  2226     ctxs = [repo[r] for r in revs]
  2230     ctxs = [repo[r] for r in revs]
  2227 
  2231 
  2228     wctx = repo[None]
  2232     wctx = repo[None]
  2255                 )
  2259                 )
  2256                 % c
  2260                 % c
  2257             )
  2261             )
  2258 
  2262 
  2259     if not rules:
  2263     if not rules:
  2260         comment = geteditcomment(ui, node.short(root), node.short(topmost))
  2264         comment = geteditcomment(ui, short(root), short(topmost))
  2261         actions = [pick(state, r) for r in revs]
  2265         actions = [pick(state, r) for r in revs]
  2262         rules = ruleeditor(repo, ui, actions, comment)
  2266         rules = ruleeditor(repo, ui, actions, comment)
  2263     else:
  2267     else:
  2264         rules = _readfile(ui, rules)
  2268         rules = _readfile(ui, rules)
  2265     actions = parserules(rules, state)
  2269     actions = parserules(rules, state)
  2459         # put the in the beginning so they execute immediately and
  2463         # put the in the beginning so they execute immediately and
  2460         # don't show in the edit-plan in the future
  2464         # don't show in the edit-plan in the future
  2461         actions[:0] = drops
  2465         actions[:0] = drops
  2462     elif missing:
  2466     elif missing:
  2463         raise error.ParseError(
  2467         raise error.ParseError(
  2464             _(b'missing rules for changeset %s') % node.short(missing[0]),
  2468             _(b'missing rules for changeset %s') % short(missing[0]),
  2465             hint=_(
  2469             hint=_(
  2466                 b'use "drop %s" to discard, see also: '
  2470                 b'use "drop %s" to discard, see also: '
  2467                 b"'hg help -e histedit.config'"
  2471                 b"'hg help -e histedit.config'"
  2468             )
  2472             )
  2469             % node.short(missing[0]),
  2473             % short(missing[0]),
  2470         )
  2474         )
  2471 
  2475 
  2472 
  2476 
  2473 def adjustreplacementsfrommarkers(repo, oldreplacements):
  2477 def adjustreplacementsfrommarkers(repo, oldreplacements):
  2474     """Adjust replacements from obsolescence markers
  2478     """Adjust replacements from obsolescence markers
  2618         }
  2622         }
  2619         common_nodes = histedit_nodes & set(nodelist)
  2623         common_nodes = histedit_nodes & set(nodelist)
  2620         if common_nodes:
  2624         if common_nodes:
  2621             raise error.Abort(
  2625             raise error.Abort(
  2622                 _(b"histedit in progress, can't strip %s")
  2626                 _(b"histedit in progress, can't strip %s")
  2623                 % b', '.join(node.short(x) for x in common_nodes)
  2627                 % b', '.join(short(x) for x in common_nodes)
  2624             )
  2628             )
  2625     return orig(ui, repo, nodelist, *args, **kwargs)
  2629     return orig(ui, repo, nodelist, *args, **kwargs)
  2626 
  2630 
  2627 
  2631 
  2628 extensions.wrapfunction(repair, b'strip', stripwrapper)
  2632 extensions.wrapfunction(repair, b'strip', stripwrapper)