hgext/rebase.py
changeset 9467 4c041f1ee1b4
parent 9301 ad4501d20214
child 9577 b91960aed018
equal deleted inserted replaced
9466:1214c64c592b 9467:4c041f1ee1b4
    33         return ancestor.ancestor(a, b, pfunc)
    33         return ancestor.ancestor(a, b, pfunc)
    34 
    34 
    35     if not first:
    35     if not first:
    36         ancestor.ancestor = newancestor
    36         ancestor.ancestor = newancestor
    37     else:
    37     else:
    38         repo.ui.debug(_("first revision, do not change ancestor\n"))
    38         repo.ui.debug("first revision, do not change ancestor\n")
    39     stats = merge.update(repo, rev, True, True, False)
    39     stats = merge.update(repo, rev, True, True, False)
    40     return stats
    40     return stats
    41 
    41 
    42 def rebase(ui, repo, **opts):
    42 def rebase(ui, repo, **opts):
    43     """move changeset (and descendants) to a different branch
    43     """move changeset (and descendants) to a different branch
   147 def concludenode(repo, rev, p1, p2, state, collapse, last=False, skipped=None,
   147 def concludenode(repo, rev, p1, p2, state, collapse, last=False, skipped=None,
   148                  extrafn=None):
   148                  extrafn=None):
   149     """Skip commit if collapsing has been required and rev is not the last
   149     """Skip commit if collapsing has been required and rev is not the last
   150     revision, commit otherwise
   150     revision, commit otherwise
   151     """
   151     """
   152     repo.ui.debug(_(" set parents\n"))
   152     repo.ui.debug(" set parents\n")
   153     if collapse and not last:
   153     if collapse and not last:
   154         repo.dirstate.setparents(repo[p1].node())
   154         repo.dirstate.setparents(repo[p1].node())
   155         return None
   155         return None
   156 
   156 
   157     repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
   157     repo.dirstate.setparents(repo[p1].node(), repo[p2].node())
   185         raise
   185         raise
   186 
   186 
   187 def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse,
   187 def rebasenode(repo, rev, target, state, skipped, targetancestors, collapse,
   188                extrafn):
   188                extrafn):
   189     'Rebase a single revision'
   189     'Rebase a single revision'
   190     repo.ui.debug(_("rebasing %d:%s\n") % (rev, repo[rev]))
   190     repo.ui.debug("rebasing %d:%s\n" % (rev, repo[rev]))
   191 
   191 
   192     p1, p2 = defineparents(repo, rev, target, state, targetancestors)
   192     p1, p2 = defineparents(repo, rev, target, state, targetancestors)
   193 
   193 
   194     repo.ui.debug(_(" future parents are %d and %d\n") % (repo[p1].rev(),
   194     repo.ui.debug(" future parents are %d and %d\n" % (repo[p1].rev(),
   195                                                             repo[p2].rev()))
   195                                                             repo[p2].rev()))
   196 
   196 
   197     # Merge phase
   197     # Merge phase
   198     if len(repo.parents()) != 2:
   198     if len(repo.parents()) != 2:
   199         # Update to target and merge it with local
   199         # Update to target and merge it with local
   200         if repo['.'].rev() != repo[p1].rev():
   200         if repo['.'].rev() != repo[p1].rev():
   201             repo.ui.debug(_(" update to %d:%s\n") % (repo[p1].rev(), repo[p1]))
   201             repo.ui.debug(" update to %d:%s\n" % (repo[p1].rev(), repo[p1]))
   202             merge.update(repo, p1, False, True, False)
   202             merge.update(repo, p1, False, True, False)
   203         else:
   203         else:
   204             repo.ui.debug(_(" already in target\n"))
   204             repo.ui.debug(" already in target\n")
   205         repo.dirstate.write()
   205         repo.dirstate.write()
   206         repo.ui.debug(_(" merge against %d:%s\n") % (repo[rev].rev(), repo[rev]))
   206         repo.ui.debug(" merge against %d:%s\n" % (repo[rev].rev(), repo[rev]))
   207         first = repo[rev].rev() == repo[min(state)].rev()
   207         first = repo[rev].rev() == repo[min(state)].rev()
   208         stats = rebasemerge(repo, rev, first)
   208         stats = rebasemerge(repo, rev, first)
   209 
   209 
   210         if stats[3] > 0:
   210         if stats[3] > 0:
   211             raise util.Abort(_('fix unresolved conflicts with hg resolve then '
   211             raise util.Abort(_('fix unresolved conflicts with hg resolve then '
   212                                                 'run hg rebase --continue'))
   212                                                 'run hg rebase --continue'))
   213     else: # we have an interrupted rebase
   213     else: # we have an interrupted rebase
   214         repo.ui.debug(_('resuming interrupted rebase\n'))
   214         repo.ui.debug('resuming interrupted rebase\n')
   215 
   215 
   216     # Keep track of renamed files in the revision that is going to be rebased
   216     # Keep track of renamed files in the revision that is going to be rebased
   217     # Here we simulate the copies and renames in the source changeset
   217     # Here we simulate the copies and renames in the source changeset
   218     cop, diver = copies.copies(repo, repo[rev], repo[target], repo[p2], True)
   218     cop, diver = copies.copies(repo, repo[rev], repo[target], repo[p2], True)
   219     m1 = repo[rev].manifest()
   219     m1 = repo[rev].manifest()
   232     if newrev is not None:
   232     if newrev is not None:
   233         state[rev] = repo[newrev].rev()
   233         state[rev] = repo[newrev].rev()
   234     else:
   234     else:
   235         if not collapse:
   235         if not collapse:
   236             repo.ui.note(_('no changes, revision %d skipped\n') % rev)
   236             repo.ui.note(_('no changes, revision %d skipped\n') % rev)
   237             repo.ui.debug(_('next revision set to %s\n') % p1)
   237             repo.ui.debug('next revision set to %s\n' % p1)
   238             skipped.add(rev)
   238             skipped.add(rev)
   239         state[rev] = p1
   239         state[rev] = p1
   240 
   240 
   241 def defineparents(repo, rev, target, state, targetancestors):
   241 def defineparents(repo, rev, target, state, targetancestors):
   242     'Return the new parent relationship of the revision that will be rebased'
   242     'Return the new parent relationship of the revision that will be rebased'
   278 def updatemq(repo, state, skipped, **opts):
   278 def updatemq(repo, state, skipped, **opts):
   279     'Update rebased mq patches - finalize and then import them'
   279     'Update rebased mq patches - finalize and then import them'
   280     mqrebase = {}
   280     mqrebase = {}
   281     for p in repo.mq.applied:
   281     for p in repo.mq.applied:
   282         if repo[p.rev].rev() in state:
   282         if repo[p.rev].rev() in state:
   283             repo.ui.debug(_('revision %d is an mq patch (%s), finalize it.\n') %
   283             repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
   284                                         (repo[p.rev].rev(), p.name))
   284                                         (repo[p.rev].rev(), p.name))
   285             mqrebase[repo[p.rev].rev()] = (p.name, isagitpatch(repo, p.name))
   285             mqrebase[repo[p.rev].rev()] = (p.name, isagitpatch(repo, p.name))
   286 
   286 
   287     if mqrebase:
   287     if mqrebase:
   288         repo.mq.finish(repo, mqrebase.keys())
   288         repo.mq.finish(repo, mqrebase.keys())
   289 
   289 
   290         # We must start import from the newest revision
   290         # We must start import from the newest revision
   291         for rev in sorted(mqrebase, reverse=True):
   291         for rev in sorted(mqrebase, reverse=True):
   292             if rev not in skipped:
   292             if rev not in skipped:
   293                 repo.ui.debug(_('import mq patch %d (%s)\n')
   293                 repo.ui.debug('import mq patch %d (%s)\n'
   294                               % (state[rev], mqrebase[rev][0]))
   294                               % (state[rev], mqrebase[rev][0]))
   295                 repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
   295                 repo.mq.qimport(repo, (), patchname=mqrebase[rev][0],
   296                             git=mqrebase[rev][1],rev=[str(state[rev])])
   296                             git=mqrebase[rev][1],rev=[str(state[rev])])
   297         repo.mq.save_dirty()
   297         repo.mq.save_dirty()
   298 
   298 
   309     for d, v in state.iteritems():
   309     for d, v in state.iteritems():
   310         oldrev = repo[d].hex()
   310         oldrev = repo[d].hex()
   311         newrev = repo[v].hex()
   311         newrev = repo[v].hex()
   312         f.write("%s:%s\n" % (oldrev, newrev))
   312         f.write("%s:%s\n" % (oldrev, newrev))
   313     f.close()
   313     f.close()
   314     repo.ui.debug(_('rebase status stored\n'))
   314     repo.ui.debug('rebase status stored\n')
   315 
   315 
   316 def clearstatus(repo):
   316 def clearstatus(repo):
   317     'Remove the status files'
   317     'Remove the status files'
   318     if os.path.exists(repo.join("rebasestate")):
   318     if os.path.exists(repo.join("rebasestate")):
   319         util.unlink(repo.join("rebasestate"))
   319         util.unlink(repo.join("rebasestate"))
   340             elif i == 5:
   340             elif i == 5:
   341                 keepbranches = bool(int(l))
   341                 keepbranches = bool(int(l))
   342             else:
   342             else:
   343                 oldrev, newrev = l.split(':')
   343                 oldrev, newrev = l.split(':')
   344                 state[repo[oldrev].rev()] = repo[newrev].rev()
   344                 state[repo[oldrev].rev()] = repo[newrev].rev()
   345         repo.ui.debug(_('rebase status resumed\n'))
   345         repo.ui.debug('rebase status resumed\n')
   346         return originalwd, target, state, collapse, keep, keepbranches, external
   346         return originalwd, target, state, collapse, keep, keepbranches, external
   347     except IOError, err:
   347     except IOError, err:
   348         if err.errno != errno.ENOENT:
   348         if err.errno != errno.ENOENT:
   349             raise
   349             raise
   350         raise util.Abort(_('no rebase in progress'))
   350         raise util.Abort(_('no rebase in progress'))
   390             cwd = repo[base].rev()
   390             cwd = repo[base].rev()
   391         else:
   391         else:
   392             cwd = repo['.'].rev()
   392             cwd = repo['.'].rev()
   393 
   393 
   394         if cwd == dest:
   394         if cwd == dest:
   395             repo.ui.debug(_('already working on current\n'))
   395             repo.ui.debug('already working on current\n')
   396             return None
   396             return None
   397 
   397 
   398         targetancestors = set(repo.changelog.ancestors(dest))
   398         targetancestors = set(repo.changelog.ancestors(dest))
   399         if cwd in targetancestors:
   399         if cwd in targetancestors:
   400             repo.ui.debug(_('already working on the current branch\n'))
   400             repo.ui.debug('already working on the current branch\n')
   401             return None
   401             return None
   402 
   402 
   403         cwdancestors = set(repo.changelog.ancestors(cwd))
   403         cwdancestors = set(repo.changelog.ancestors(cwd))
   404         cwdancestors.add(cwd)
   404         cwdancestors.add(cwd)
   405         rebasingbranch = cwdancestors - targetancestors
   405         rebasingbranch = cwdancestors - targetancestors
   406         source = min(rebasingbranch)
   406         source = min(rebasingbranch)
   407 
   407 
   408     repo.ui.debug(_('rebase onto %d starting from %d\n') % (dest, source))
   408     repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
   409     state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
   409     state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
   410     external = nullrev
   410     external = nullrev
   411     if collapse:
   411     if collapse:
   412         if not targetancestors:
   412         if not targetancestors:
   413             targetancestors = set(repo.changelog.ancestors(dest))
   413             targetancestors = set(repo.changelog.ancestors(dest))
   427 def pullrebase(orig, ui, repo, *args, **opts):
   427 def pullrebase(orig, ui, repo, *args, **opts):
   428     'Call rebase after pull if the latter has been invoked with --rebase'
   428     'Call rebase after pull if the latter has been invoked with --rebase'
   429     if opts.get('rebase'):
   429     if opts.get('rebase'):
   430         if opts.get('update'):
   430         if opts.get('update'):
   431             del opts['update']
   431             del opts['update']
   432             ui.debug(_('--update and --rebase are not compatible, ignoring '
   432             ui.debug('--update and --rebase are not compatible, ignoring '
   433                                         'the update flag\n'))
   433                      'the update flag\n')
   434 
   434 
   435         cmdutil.bail_if_changed(repo)
   435         cmdutil.bail_if_changed(repo)
   436         revsprepull = len(repo)
   436         revsprepull = len(repo)
   437         orig(ui, repo, *args, **opts)
   437         orig(ui, repo, *args, **opts)
   438         revspostpull = len(repo)
   438         revspostpull = len(repo)