mercurial/commands.py
changeset 15241 e4d135632f6d
parent 15240 bfb93963bb39
child 15242 dac2edce4e4a
equal deleted inserted replaced
15240:bfb93963bb39 15241:e4d135632f6d
  2447     repo[None].forget(forget)
  2447     repo[None].forget(forget)
  2448     return errs
  2448     return errs
  2449 
  2449 
  2450 @command(
  2450 @command(
  2451     'graft',
  2451     'graft',
  2452     [('e', 'edit', False, _('invoke editor on commit messages')),
  2452     [('c', 'continue', False, _('resume interrupted graft')),
  2453     ('D', 'currentdate', False,
  2453      ('e', 'edit', False, _('invoke editor on commit messages')),
  2454      _('record the current date as commit date')),
  2454      ('D', 'currentdate', False,
  2455     ('U', 'currentuser', False,
  2455       _('record the current date as commit date')),
  2456      _('record the current user as committer'), _('DATE'))]
  2456      ('U', 'currentuser', False,
       
  2457       _('record the current user as committer'), _('DATE'))]
  2457     + commitopts2 + mergetoolopts,
  2458     + commitopts2 + mergetoolopts,
  2458     _('[OPTION]... REVISION...'))
  2459     _('[OPTION]... REVISION...'))
  2459 def graft(ui, repo, rev, *revs, **opts):
  2460 def graft(ui, repo, *revs, **opts):
  2460     '''copy changes from other branches onto the current branch
  2461     '''copy changes from other branches onto the current branch
  2461 
  2462 
  2462     This command uses Mercurial's merge logic to copy individual
  2463     This command uses Mercurial's merge logic to copy individual
  2463     changes from other branches without merging branches in the
  2464     changes from other branches without merging branches in the
  2464     history graph. This is sometimes known as 'backporting' or
  2465     history graph. This is sometimes known as 'backporting' or
  2465     'cherry-picking'.
  2466     'cherry-picking'.
  2466 
  2467 
  2467     Changesets that are ancestors of the current revision, that have
  2468     Changesets that are ancestors of the current revision, that have
  2468     already been grafted, or that are merges will be skipped.
  2469     already been grafted, or that are merges will be skipped.
  2469 
  2470 
       
  2471     If a graft merge results in conflicts, the graft process is
       
  2472     aborted so that the current merge can be manually resolved. Once
       
  2473     all conflicts are addressed, the graft process can be continued
       
  2474     with the -c/--continue option.
       
  2475 
       
  2476     .. note::
       
  2477       The -c/--continue option does not reapply earlier options.
       
  2478 
  2470     Returns 0 on successful completion.
  2479     Returns 0 on successful completion.
  2471     '''
  2480     '''
  2472 
       
  2473     cmdutil.bailifchanged(repo)
       
  2474 
  2481 
  2475     if not opts.get('user') and opts.get('currentuser'):
  2482     if not opts.get('user') and opts.get('currentuser'):
  2476         opts['user'] = ui.username()
  2483         opts['user'] = ui.username()
  2477     if not opts.get('date') and opts.get('currentdate'):
  2484     if not opts.get('date') and opts.get('currentdate'):
  2478         opts['date'] = "%d %d" % util.makedate()
  2485         opts['date'] = "%d %d" % util.makedate()
  2479 
  2486 
  2480     editor = None
  2487     editor = None
  2481     if opts.get('edit'):
  2488     if opts.get('edit'):
  2482         editor = cmdutil.commitforceeditor
  2489         editor = cmdutil.commitforceeditor
  2483 
  2490 
  2484     revs = [rev] + list(revs)
  2491     cont = False
  2485     revs = scmutil.revrange(repo, revs)
  2492     if opts['continue']:
       
  2493         cont = True
       
  2494         if revs:
       
  2495             raise util.Abort(_("can't specify --continue and revisions"))
       
  2496         # read in unfinished revisions
       
  2497         try:
       
  2498             nodes = repo.opener.read('graftstate').splitlines()
       
  2499             revs = [repo[node].rev() for node in nodes]
       
  2500         except IOError, inst:
       
  2501             if inst.errno != errno.ENOENT:
       
  2502                 raise
       
  2503             raise util.Abort(_("no graft state found, can't continue"))
       
  2504     else:
       
  2505         cmdutil.bailifchanged(repo)
       
  2506         if not revs:
       
  2507             raise util.Abort(_('no revisions specified'))
       
  2508         revs = scmutil.revrange(repo, revs)
  2486 
  2509 
  2487     # check for merges
  2510     # check for merges
  2488     for ctx in repo.set('%ld and merge()', revs):
  2511     for ctx in repo.set('%ld and merge()', revs):
  2489         ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
  2512         ui.warn(_('skipping ungraftable merge revision %s\n') % ctx.rev())
  2490         revs.remove(ctx.rev())
  2513         revs.remove(ctx.rev())
  2507             ui.warn(_('skipping already grafted revision %s\n') % r)
  2530             ui.warn(_('skipping already grafted revision %s\n') % r)
  2508             revs.remove(r)
  2531             revs.remove(r)
  2509     if not revs:
  2532     if not revs:
  2510         return -1
  2533         return -1
  2511 
  2534 
  2512     for ctx in repo.set("%ld", revs):
  2535     for pos, ctx in enumerate(repo.set("%ld", revs)):
  2513         current = repo['.']
  2536         current = repo['.']
  2514         ui.debug('grafting revision %s', ctx.rev())
  2537         ui.debug('grafting revision %s', ctx.rev())
  2515         # perform the graft merge with p1(rev) as 'ancestor'
  2538 
  2516         try:
  2539         # we don't merge the first commit when continuing
  2517             # ui.forcemerge is an internal variable, do not document
  2540         if not cont:
  2518             repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
  2541             # perform the graft merge with p1(rev) as 'ancestor'
  2519             stats = mergemod.update(repo, ctx.node(), True, True, False,
  2542             try:
  2520                                     ctx.p1().node())
  2543                 # ui.forcemerge is an internal variable, do not document
  2521         finally:
  2544                 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
  2522             ui.setconfig('ui', 'forcemerge', '')
  2545                 stats = mergemod.update(repo, ctx.node(), True, True, False,
  2523         # drop the second merge parent
  2546                                         ctx.p1().node())
  2524         repo.dirstate.setparents(current.node(), nullid)
  2547             finally:
  2525         repo.dirstate.write()
  2548                 ui.setconfig('ui', 'forcemerge', '')
  2526         # fix up dirstate for copies and renames
  2549             # drop the second merge parent
  2527         cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
  2550             repo.dirstate.setparents(current.node(), nullid)
  2528         # report any conflicts
  2551             repo.dirstate.write()
  2529         if stats and stats[3] > 0:
  2552             # fix up dirstate for copies and renames
  2530             raise util.Abort(_("unresolved conflicts, can't continue"),
  2553             cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
  2531                              hint=_('use hg resolve and hg graft --continue'))
  2554             # report any conflicts
       
  2555             if stats and stats[3] > 0:
       
  2556                 # write out state for --continue
       
  2557                 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
       
  2558                 repo.opener.write('graftstate', ''.join(nodelines))
       
  2559                 raise util.Abort(
       
  2560                     _("unresolved conflicts, can't continue"),
       
  2561                     hint=_('use hg resolve and hg graft --continue'))
       
  2562         else:
       
  2563             cont = False
       
  2564 
  2532         # commit
  2565         # commit
  2533         extra = {'source': ctx.hex()}
  2566         extra = {'source': ctx.hex()}
  2534         user = ctx.user()
  2567         user = ctx.user()
  2535         if opts.get('user'):
  2568         if opts.get('user'):
  2536             user = opts['user']
  2569             user = opts['user']
  2537         date = ctx.date()
  2570         date = ctx.date()
  2538         if opts.get('date'):
  2571         if opts.get('date'):
  2539             date = opts['date']
  2572             date = opts['date']
  2540         repo.commit(text=ctx.description(), user=user,
  2573         repo.commit(text=ctx.description(), user=user,
  2541                     date=date, extra=extra, editor=editor)
  2574                     date=date, extra=extra, editor=editor)
       
  2575 
       
  2576     # remove state when we complete successfully
       
  2577     if os.path.exists(repo.join('graftstate')):
       
  2578         util.unlinkpath(repo.join('graftstate'))
  2542 
  2579 
  2543     return 0
  2580     return 0
  2544 
  2581 
  2545 @command('grep',
  2582 @command('grep',
  2546     [('0', 'print0', None, _('end fields with NUL')),
  2583     [('0', 'print0', None, _('end fields with NUL')),